3 * wxbPanel for restoring files
5 * Nicolas Boichat, April-July 2004
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2004-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
37 /* Note concerning "done" output (modifiable marked with +)
39 +JobName: RestoreFiles
40 Bootstrap: /var/lib/bacula/restore.bsr
41 +Where: /tmp/bacula-restores
46 +When: 2004-04-18 01:18:56
48 OK to run? (yes/mod/no):mod
50 1: Level (not appropriate)
51 2: Storage (automatic ?)
54 5: Client (yes : "The defined Client resources are:\n\t1: velours-fd\n\t2: tom-fd\nSelect Client (File daemon) resource (1-2):")
55 6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
56 7: Priority (yes : "Enter new Priority: (positive integer)")
58 9: Where (yes : "Please enter path prefix for restore (/ for none):")
59 10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n
60 Select replace option (1-4):")
62 Select parameter to modify (1-11):
65 /* Windows debug builds set _DEBUG which is used by wxWidgets to select their
66 * debug memory allocator. Unfortunately it conflicts with Bacula's SmartAlloc.
67 * So we turn _DEBUG off since we aren't interested in things it enables.
74 #include "wxbrestorepanel.h"
75 #include "wxbmainframe.h"
77 #include <wx/choice.h>
78 #include <wx/datetime.h>
80 #include "unmarked.xpm"
82 #include "partmarked.xpm"
83 #include <wx/listimpl.cpp>
85 /* A macro named Yield is defined under MinGW */
88 WX_DEFINE_LIST(wxbEventList);
91 * Class which is stored in the tree and in the list to keep informations
94 class wxbTreeItemData : public wxTreeItemData {
96 wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
102 void SetMarked(int marked);
106 wxString* path; /* Full path */
107 wxString* name; /* File name */
108 int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
109 long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
112 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
113 this->path = new wxString(path);
114 this->name = new wxString(name);
115 this->marked = marked;
116 this->listid = listid;
119 wxbTreeItemData::~wxbTreeItemData() {
124 int wxbTreeItemData::GetMarked() {
128 void wxbTreeItemData::SetMarked(int marked) {
129 this->marked = marked;
132 long wxbTreeItemData::GetListId() {
136 wxString wxbTreeItemData::GetPath() {
140 wxString wxbTreeItemData::GetName() {
144 // ----------------------------------------------------------------------------
145 // event tables and other macros for wxWindows
146 // ----------------------------------------------------------------------------
174 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
175 EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
176 EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
178 EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
179 EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
180 EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
181 EVT_TREE_MARKED_EVENT(TreeCtrl, wxbRestorePanel::OnTreeMarked)
182 EVT_BUTTON(TreeAdd, wxbRestorePanel::OnTreeAdd)
183 EVT_BUTTON(TreeRemove, wxbRestorePanel::OnTreeRemove)
184 EVT_BUTTON(TreeRefresh, wxbRestorePanel::OnTreeRefresh)
186 EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
187 EVT_LIST_MARKED_EVENT(ListCtrl, wxbRestorePanel::OnListMarked)
188 EVT_LIST_ITEM_SELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
189 EVT_LIST_ITEM_DESELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
190 EVT_BUTTON(ListAdd, wxbRestorePanel::OnListAdd)
191 EVT_BUTTON(ListRemove, wxbRestorePanel::OnListRemove)
192 EVT_BUTTON(ListRefresh, wxbRestorePanel::OnListRefresh)
194 EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
195 EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
196 EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
197 EVT_CHOICE(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
198 EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
199 EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
200 EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
201 EVT_CHOICE(ConfigStorage, wxbRestorePanel::OnConfigUpdated)
202 EVT_CHOICE(ConfigJobName, wxbRestorePanel::OnConfigUpdated)
203 EVT_CHOICE(ConfigPool, wxbRestorePanel::OnConfigUpdated)
205 EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
206 EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
207 EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
211 * wxbRestorePanel constructor
213 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent)
215 //pendingEvents = new wxbEventList(); //EVTQUEUE
216 //processing = false; //EVTQUEUE
219 imagelist = new wxImageList(16, 16, TRUE, 3);
220 imagelist->Add(wxIcon(unmarked_xpm));
221 imagelist->Add(wxIcon(marked_xpm));
222 imagelist->Add(wxIcon(partmarked_xpm));
224 wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
225 mainSizer->AddGrowableCol(0);
226 mainSizer->AddGrowableRow(1);
228 wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
230 firstSizer->AddGrowableCol(0);
231 firstSizer->AddGrowableRow(0);
233 start = new wxButton(this, RestoreStart, _("Enter restore mode"), wxDefaultPosition, wxSize(150, 30));
234 firstSizer->Add(start, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
236 cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
237 firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
241 /* clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
242 firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
244 jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
245 firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
247 mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
249 treelistPanel = new wxSplitterWindow(this);
251 wxPanel* treePanel = new wxPanel(treelistPanel);
252 wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
253 treeSizer->AddGrowableCol(0);
254 treeSizer->AddGrowableRow(0);
256 tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));
257 tree->SetImageList(imagelist);
259 treeSizer->Add(tree, 1, wxEXPAND, 0);
261 wxBoxSizer *treeCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
262 treeadd = new wxButton(treePanel, TreeAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
263 treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
264 treeremove = new wxButton(treePanel, TreeRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
265 treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
266 treerefresh = new wxButton(treePanel, TreeRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
267 treeCtrlSizer->Add(treerefresh, 0, wxLEFT | wxRIGHT, 3);
269 treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
271 treePanel->SetSizer(treeSizer);
273 wxPanel* listPanel = new wxPanel(treelistPanel);
274 wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
275 listSizer->AddGrowableCol(0);
276 listSizer->AddGrowableRow(0);
278 list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
279 //treelistSizer->Add(list, 1, wxEXPAND, 10);
281 list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
284 info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
285 info.SetText(_("M"));
286 info.SetAlign(wxLIST_FORMAT_CENTER);
287 list->InsertColumn(0, info);
289 info.SetText(_("Filename"));
290 info.SetAlign(wxLIST_FORMAT_LEFT);
291 list->InsertColumn(1, info);
293 info.SetText(_("Size"));
294 info.SetAlign(wxLIST_FORMAT_RIGHT);
295 list->InsertColumn(2, info);
297 info.SetText(_("Date"));
298 info.SetAlign(wxLIST_FORMAT_LEFT);
299 list->InsertColumn(3, info);
301 info.SetText(_("Perm."));
302 info.SetAlign(wxLIST_FORMAT_LEFT);
303 list->InsertColumn(4, info);
305 info.SetText(_("User"));
306 info.SetAlign(wxLIST_FORMAT_RIGHT);
307 list->InsertColumn(5, info);
309 info.SetText(_("Group"));
310 info.SetAlign(wxLIST_FORMAT_RIGHT);
311 list->InsertColumn(6, info);
313 listSizer->Add(list, 1, wxEXPAND, 0);
315 wxBoxSizer *listCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
316 listadd = new wxButton(listPanel, ListAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
317 listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
318 listremove = new wxButton(listPanel, ListRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
319 listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
320 listrefresh = new wxButton(listPanel, ListRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
321 listCtrlSizer->Add(listrefresh, 0, wxLEFT | wxRIGHT, 5);
323 listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
325 listPanel->SetSizer(listSizer);
327 treelistPanel->SplitVertically(treePanel, listPanel, 210);
329 treelistPanel->SetMinimumPaneSize(210);
331 treelistPanel->Show(false);
333 wxbConfig* config = new wxbConfig();
334 config->Add(new wxbConfigParam(_("Job Name"), ConfigJobName, choice, 0, elist));
335 config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, elist));
336 config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, elist));
337 config->Add(new wxbConfigParam(_("Pool"), ConfigPool, choice, 0, elist));
338 config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, elist));
339 config->Add(new wxbConfigParam(_("Before"), ConfigWhen, choice, 0, elist));
341 configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
343 configPanel->Show(true);
344 configPanel->Enable(false);
346 config = new wxbConfig();
347 config->Add(new wxbConfigParam(_("Job Name"), -1, text, wxT("")));
348 config->Add(new wxbConfigParam(_("Bootstrap"), -1, text, wxT("")));
349 config->Add(new wxbConfigParam(_("Where"), ConfigWhere, modifiableText, wxT("")));
350 wxString erlist[] = {_("always"), _("if newer"), _("if older"), _("never")};
351 config->Add(new wxbConfigParam(_("Replace"), ConfigReplace, choice, 4, erlist));
352 config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, erlist));
353 config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, erlist));
354 config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, erlist));
355 config->Add(new wxbConfigParam(_("When"), ConfigWhen, modifiableText, wxT("")));
356 config->Add(new wxbConfigParam(_("Priority"), ConfigPriority, modifiableText, wxT("")));
358 restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
360 restorePanel->Show(false);
362 centerSizer = new wxBoxSizer(wxHORIZONTAL);
363 //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
365 mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
367 gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
369 mainSizer->Add(gauge, 1, wxEXPAND, 5);
371 gauge->Enable(false);
374 mainSizer->SetSizeHints(this);
378 for (int i = 0; i < 7; i++) {
379 list->SetColumnWidth(i, 70);
382 SetCursor(*wxSTANDARD_CURSOR);
384 markWhenCommandDone = false;
390 * wxbRestorePanel destructor
392 wxbRestorePanel::~wxbRestorePanel()
397 /*----------------------------------------------------------------------------
398 wxbPanel overloadings
399 ----------------------------------------------------------------------------*/
401 wxString wxbRestorePanel::GetTitle()
406 void wxbRestorePanel::EnablePanel(bool enable)
409 if (status == disabled) {
410 SetStatus(activable);
417 /*----------------------------------------------------------------------------
418 Commands called by events handler
419 ----------------------------------------------------------------------------*/
421 /* The main button has been clicked */
422 void wxbRestorePanel::CmdStart()
425 if (status == activable) {
426 wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
427 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
430 configPanel->ClearRowChoices(_("Client"));
431 restorePanel->ClearRowChoices(_("Client"));
433 if (dt->GetCount() == 0) {
434 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
438 for (i = 0; i < dt->GetCount(); i++) {
441 configPanel->AddRowChoice(_("Client"), str);
442 restorePanel->AddRowChoice(_("Client"), str);
452 dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
454 configPanel->ClearRowChoices(_("Fileset"));
455 restorePanel->ClearRowChoices(_("Fileset"));
457 if (dt->GetCount() == 0) {
458 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
462 for (i = 0; i < dt->GetCount(); i++) {
465 configPanel->AddRowChoice(_("Fileset"), str);
466 restorePanel->AddRowChoice(_("Fileset"), str);
476 dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
478 configPanel->ClearRowChoices(_("Storage"));
479 restorePanel->ClearRowChoices(_("Storage"));
481 if (dt->GetCount() == 0) {
482 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
486 for (i = 0; i < dt->GetCount(); i++) {
489 configPanel->AddRowChoice(_("Storage"), str);
490 restorePanel->AddRowChoice(_("Storage"), str);
500 dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
502 configPanel->ClearRowChoices(_("Job Name"));
504 if (dt->GetCount() == 0) {
505 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
509 for (i = 0; i < dt->GetCount(); i++) {
512 configPanel->AddRowChoice(_("Job Name"), str);
515 configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
524 dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
526 configPanel->ClearRowChoices(_("Pool"));
528 if (dt->GetCount() == 0) {
529 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
533 for (i = 0; i < dt->GetCount(); i++) {
536 configPanel->AddRowChoice(_("Pool"), str);
550 wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
552 else if (status == entered) {
553 /* if (clientChoice->GetStringSelection().Length() < 1) {
554 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
557 if (jobChoice->GetStringSelection().Length() < 1) {
558 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
561 wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
565 wxbTableParser* tableparser = new wxbTableParser();
566 wxbDataTokenizer* dt = new wxbDataTokenizer(false);
569 * The following line was removed from ::GetInstance below because
570 * it does not work with multiple pools -- KES 5Oct05 see bug #433
571 * wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
573 wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
574 wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
575 wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
576 wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
577 wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
579 //wxbUtils::WaitForPrompt("6\n");
581 /*wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
582 int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
583 if (client == wxNOT_FOUND) {
584 wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
589 //wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
591 while (!tableparser->hasFinished() && !dt->hasFinished()) {
592 wxTheApp->Yield(true);
593 wxbUtils::MilliSleep(100);
598 if (dt->hasFinished() && !tableparser->hasFinished()) {
600 if (dt->GetCount() > 1) {
601 str = (*dt)[dt->GetCount()-2];
604 wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
614 for (i = 0; i < tableparser->GetCount(); i++) {
615 str = (*tableparser)[i][2];
616 str.Replace(wxT(","), wxT(""));
617 if (str.ToLong(&l)) {
623 gauge->SetRange(tot);
625 /*wxbMainFrame::GetInstance()->Print(
626 wxString("[") << tot << "]", CS_DEBUG);*/
628 wxDateTime base = wxDateTime::Now();
632 unsigned int lastindex = 0;
639 newdate = wxDateTime::Now();
640 if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
642 for (; lastindex < dt->GetCount(); lastindex++) {
643 if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) &&
644 ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
645 str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
646 for (i = 0; i < tableparser->GetCount(); i++) {
647 if (str == (*tableparser)[i][0]) {
648 str = (*tableparser)[i][2];
649 str.Replace(wxT(","), wxT(""));
650 if (str.ToLong(&l)) {
653 var = (willdo-done)/50;
654 gauge->SetValue(done);
655 wxTheApp->Yield(true);
661 else if ((*dt)[lastindex] == wxT("+")) {
662 gauge->SetValue(gauge->GetValue()+var);
663 wxTheApp->Yield(true);
668 if (dt->hasFinished()) {
672 wxTheApp->Yield(true);
673 wxbUtils::MilliSleep(1);
676 gauge->SetValue(tot);
677 wxTheApp->Yield(true);
688 wxbUtils::WaitForEnd(wxT("unmark *\n"));
689 wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
690 currentTreeItem = root;
692 tree->SelectItem(root);
694 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."));
697 else if (status == choosing) {
701 wxbDataTokenizer* dt;
705 dt = new wxbDataTokenizer(true);
706 wxbPromptParser* promptparser = wxbUtils::WaitForPrompt(wxT("done\n"), true);
708 while (!promptparser->getChoices() || (promptparser->getChoices()->Index(wxT("mod")) < 0)) {
709 wxbMainFrame::GetInstance()->Print(_("Unexpected question has been received.\n"), CS_DEBUG);
712 if (promptparser->getIntroString() != wxT("")) {
713 message << promptparser->getIntroString() << wxT("\n");
715 message << promptparser->getQuestionString();
717 if (promptparser->getChoices()) {
718 wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
719 int *numbers = new int[promptparser->getChoices()->GetCount()];
722 for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
723 if ((*promptparser->getChoices())[i] != wxT("")) {
724 choices[n] = (*promptparser->getChoices())[i];
730 int res = ::wxGetSingleChoiceIndex(message,
731 _("bwx-console: unexpected restore question."), n, choices, this);
734 promptparser = wxbUtils::WaitForPrompt(wxT(".\n"), true);
737 if (promptparser->isNumericalChoice()) {
739 promptparser = wxbUtils::WaitForPrompt(wxString() << numbers[res] << wxT("\n"), true);
743 promptparser = wxbUtils::WaitForPrompt(wxString() << choices[res] << wxT("\n"), true);
752 promptparser = wxbUtils::WaitForPrompt(::wxGetTextFromUser(message,
753 _("bwx-console: unexpected restore question."),
754 wxT(""), this) + wxT("\n"));
757 printf("promptparser->getChoices()=%ld", (long)promptparser->getChoices());
761 SetStatus(configuring);
763 for (i = 0; i < dt->GetCount(); i++) {
764 if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
765 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
769 if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
770 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
775 wxbMainFrame::GetInstance()->SetStatusText(
776 wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
778 UpdateSecondConfig(dt);
783 restorePanel->EnableApply(false);
785 if (totfilemessages == 0) {
786 wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
787 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
792 else if (status == configuring) {
793 cancel->Enable(false);
797 wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
799 wxbDataTokenizer* dt;
801 SetStatus(restoring);
802 dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
805 gauge->SetRange(totfilemessages);
809 for (i = 0; i < dt->GetCount(); i++) {
810 if ((j = (*dt)[i].Find(_("Job queued. JobId="))) > -1) {
811 jobid = (*dt)[i].Mid(j+19);
812 wxbMainFrame::GetInstance()->SetStatusText(_("Restore queued, jobid=") + jobid);
816 if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
817 wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
818 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
823 if (jobid == wxT("")) {
824 wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
825 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
829 wxDateTime currenttime;
831 dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
832 wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
833 if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
834 (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
835 currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
838 currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
842 wxDateTime scheduledtime;
843 wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
845 if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
846 (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
847 scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
850 if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
851 wxbMainFrame::GetInstance()->Print(_("Restore is scheduled in more than two minutes, bwx-console will not wait for its completion.\n"), CS_DEBUG);
852 wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled in more than two minutes, bwx-console will not wait for its completion."));
857 wxString cmd = wxString(wxT("list jobid=")) + jobid;
859 wxbTableParser* tableparser;
861 long filemessages = 0;
864 bool waitforever = false;
870 wxbUtils::WaitForEnd(wxT("autodisplay off\n"));
871 wxbUtils::WaitForEnd(wxT("gui on\n"));
873 tableparser = wxbUtils::CreateAndWaitForParser(cmd);
875 status = (*tableparser)[0][7].GetChar(0);
878 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
882 wxbMainFrame::GetInstance()->SetStatusText(
883 wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
887 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
888 wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
892 case JS_ErrorTerminated:
893 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
894 wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
899 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
903 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
908 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
909 wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
914 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
918 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
921 case JS_WaitStoreRes:
922 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
926 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
929 case JS_WaitClientRes:
930 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
934 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
937 case JS_WaitStartTime:
938 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
941 case JS_WaitPriority:
942 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
948 dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
950 for (unsigned int i = 0; i < dt->GetCount(); i++) {
951 wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
955 // Date Time name: perm ? user grp size date time
956 //04-Apr-2004 17:19 Tom-fd: -rwx------ 1 nicolas None 514967 2004-03-20 20:03:42 filename
958 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
959 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
960 if (tkz.GetNextToken().Last() == ':') { // name:
961 tkz.GetNextToken(); // perm
962 tkz.GetNextToken(); // ?
963 tkz.GetNextToken(); // user
964 tkz.GetNextToken(); // grp
965 tkz.GetNextToken(); // size
966 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
967 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
969 //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
970 gauge->SetValue(filemessages);
981 while (sw2.Time() < 10000) {
982 wxTheApp->Yield(true);
983 wxbUtils::MilliSleep(100);
990 if ((!waitforever) && (sw.Time() > 60000)) {
991 wxbMainFrame::GetInstance()->Print(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore.\n"), CS_DEBUG);
992 wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore."));
996 wxbUtils::WaitForEnd(wxT("autodisplay on\n"));
997 wxbUtils::WaitForEnd(wxT(".messages\n"));
999 gauge->SetValue(totfilemessages);
1001 if (status == JS_Terminated) {
1002 wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
1003 wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
1005 SetStatus(finished);
1009 /* The cancel button has been clicked */
1010 void wxbRestorePanel::CmdCancel() {
1013 if (status == restoring) {
1014 if (jobid != wxT("")) {
1015 wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
1017 cancel->Enable(true);
1022 while ((IsWorking()) && (cancelled != 2)) {
1023 wxTheApp->Yield(true);
1024 wxbUtils::MilliSleep(100);
1025 if (sw.Time() > 30000) { /* 30 seconds timeout */
1026 if (status == choosing) {
1027 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1029 else if (status == configuring) {
1030 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1032 else if (status == restoring) {
1035 SetStatus(finished);
1036 wxbUtils::MilliSleep(1000);
1043 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1046 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1051 wxbUtils::MilliSleep(1000);
1052 SetStatus(finished);
1055 /* Apply configuration changes */
1057 /* 1: Level (not appropriate)
1062 * 6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1063 * 7: Priority (yes : "Enter new Priority: (positive integer)")
1065 * 9: Where (yes : "Please enter path prefix for restore (/ for none):")
1066 * 10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n
1067 * Select replace option (1-4):")
1071 void wxbRestorePanel::CmdConfigApply() {
1072 if (cfgUpdated == 0) return;
1074 wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1076 EnableConfig(false);
1078 wxbDataTokenizer* dt = NULL;
1080 bool failed = false;
1082 while (cfgUpdated > 0) {
1087 wxString def; //String to send if can't use our data
1088 if ((cfgUpdated >> ConfigWhere) & 1) {
1089 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1090 wxbUtils::WaitForPrompt(wxT("9\n"));
1091 dt = new wxbDataTokenizer(true);
1092 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1094 cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1096 else if ((cfgUpdated >> ConfigReplace) & 1) {
1097 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1098 wxbUtils::WaitForPrompt(wxT("10\n"));
1099 dt = new wxbDataTokenizer(true);
1100 wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1102 cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1104 else if ((cfgUpdated >> ConfigWhen) & 1) {
1105 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1106 wxbUtils::WaitForPrompt(wxT("6\n"));
1107 dt = new wxbDataTokenizer(true);
1108 wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1110 cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1112 else if ((cfgUpdated >> ConfigPriority) & 1) {
1113 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1114 wxbUtils::WaitForPrompt(wxT("7\n"));
1115 dt = new wxbDataTokenizer(true);
1116 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1118 cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1120 else if ((cfgUpdated >> ConfigClient) & 1) {
1121 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1122 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1123 int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1124 if (client == wxNOT_FOUND) {
1125 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1130 dt = new wxbDataTokenizer(true);
1131 wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1133 cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1135 else if ((cfgUpdated >> ConfigFileset) & 1) {
1136 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1137 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1138 int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1139 if (fileset == wxNOT_FOUND) {
1140 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1145 dt = new wxbDataTokenizer(true);
1146 wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1148 cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1150 else if ((cfgUpdated >> ConfigStorage) & 1) {
1151 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1152 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1153 int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1154 if (fileset == wxNOT_FOUND) {
1155 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1160 dt = new wxbDataTokenizer(true);
1161 wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1163 cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1171 for (i = 0; i < dt->GetCount(); i++) {
1172 if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1177 if (i == dt->GetCount()) {
1179 dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1183 UpdateSecondConfig(dt); /* TODO: Check result */
1188 wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1194 /* Cancel restore */
1195 void wxbRestorePanel::CmdConfigCancel() {
1196 wxbUtils::WaitForEnd(wxT("no\n"));
1197 wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1198 wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1199 SetStatus(finished);
1202 /* List jobs for a specified client and fileset */
1203 void wxbRestorePanel::CmdListJobs() {
1204 if (status == entered) {
1205 configPanel->ClearRowChoices(_("Before"));
1206 /*wxbUtils::WaitForPrompt("query\n");
1207 wxbUtils::WaitForPrompt("6\n");*/
1208 wxbTableParser* tableparser = new wxbTableParser(false);
1209 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1210 wxString(wxT(".backups client=\"")) + configPanel->GetRowString(_("Client")) +
1211 wxT("\" fileset=\"") + configPanel->GetRowString(_("Fileset")) + wxT("\"\n"), true);
1213 while (!tableparser->hasFinished()) {
1214 wxTheApp->Yield(true);
1215 wxbUtils::MilliSleep(100);
1218 if (!tableparser->GetCount() == 0) {
1219 for (unsigned int i = 0; i < dt->Count(); i++) {
1220 if ((*dt)[i].Find(_("No results to list.")) == 0) {
1221 configPanel->AddRowChoice(_("Before"),
1222 _("No backup found for this client."));
1223 configPanel->SetRowSelection(_("Before"), 0);
1224 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1229 else if (((*dt)[i].Find(_("ERROR")) > -1) ||
1230 ((*dt)[i].Find(_("Query failed")) > -1)) {
1231 configPanel->AddRowChoice(_("Before"),
1232 _("Cannot get previous backups list, see console."));
1233 configPanel->SetRowSelection(_("Before"), 0);
1234 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1244 wxDateTime lastdatetime = (time_t) 0;
1245 for (int i = tableparser->GetCount()-1; i > -1; i--) {
1246 wxString str = (*tableparser)[i][3];
1247 wxDateTime datetime;
1249 if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) && ! lastdatetime.IsEqualTo(datetime) ) {
1250 lastdatetime = datetime;
1251 datetime += wxTimeSpan::Seconds(1);
1252 configPanel->AddRowChoice(_("Before"),
1253 datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1259 configPanel->SetRowSelection(_("Before"), 0);
1260 configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1264 /* List files and directories for a specified tree item */
1265 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1266 if (status == choosing) {
1267 list->DeleteAllItems();
1272 UpdateTreeItem(item, true, false);
1274 if (list->GetItemCount() >= 1) {
1275 int firstwidth = list->GetSize().GetWidth();
1276 for (int i = 2; i < 7; i++) {
1277 list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1278 firstwidth -= list->GetColumnWidth(i);
1281 list->SetColumnWidth(0, 18);
1283 list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1284 if (list->GetColumnWidth(1) < firstwidth) {
1285 list->SetColumnWidth(1, firstwidth-25);
1291 /* Mark a treeitem (directory) or a listitem (file or directory) */
1292 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1293 if (status == choosing) {
1294 wxbTreeItemData** itemdata;
1295 int itemdatasize = 0;
1296 if (listsize == 0) {
1297 itemdata = new wxbTreeItemData*[1];
1301 itemdata = new wxbTreeItemData*[listsize];
1302 itemdatasize = listsize;
1305 if (listitems != NULL) {
1306 for (int i = 0; i < itemdatasize; i++) {
1307 itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1310 else if (treeitem.IsOk()) {
1311 itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1318 if (itemdata[0] == NULL) { //Should never happen
1323 wxString dir = itemdata[0]->GetPath();
1326 if (dir != wxT("/")) {
1327 if (IsPathSeparator(dir.GetChar(dir.Length()-1))) {
1331 int i = dir.Find('/', TRUE);
1336 else { /* first dir below root */
1337 file = dir.Mid(i+1);
1338 dir = dir.Mid(0, i+1);
1347 bool marked = false;
1348 bool unmarked = false;
1350 for (int i = 0; i < itemdatasize; i++) {
1351 switch(itemdata[i]->GetMarked()) {
1365 if (marked && unmarked)
1381 wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1382 wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1384 /* TODO: Check commands results */
1386 /*if ((dir == "/") && (file == "*")) {
1387 itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1390 if (listitems == NULL) { /* tree item state changed */
1391 SetTreeItemState(treeitem, state);
1392 /*treeitem = tree->GetSelection();
1393 UpdateTree(treeitem, true);
1394 treeitem = tree->GetItemParent(treeitem);*/
1397 for (int i = 0; i < itemdatasize; i++) {
1398 SetListItemState(listitems[i], state);
1400 listadd->Enable(state == 0);
1401 listremove->Enable(state == 1);
1402 /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1403 treeitem = tree->GetItemParent(treeitem);*/
1406 /*while (treeitem.IsOk()) {
1407 WaitForList(treeitem, false);
1408 treeitem = tree->GetItemParent(treeitem);
1415 /*----------------------------------------------------------------------------
1417 ----------------------------------------------------------------------------*/
1419 /* Run a dir command, and waits until result is fully received. */
1420 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse)
1422 // this->updatelist = updatelist;
1423 wxbDataTokenizer* dt;
1425 dt = wxbUtils::WaitForEnd(wxString(wxT("cd \"")) <<
1426 static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1427 ->GetPath() << wxT("\"\n"), false);
1429 /* TODO: check command result */
1436 list->DeleteAllItems();
1437 dt = wxbUtils::WaitForEnd(wxT(".dir\n"), true);
1441 for (unsigned int i = 0; i < dt->GetCount(); i++) {
1444 if (str.Find(wxT("cwd is:")) == 0) { // Sometimes cd command result "infiltrate" into listings.
1452 if (!ParseList(str, &entry))
1455 wxTreeItemId treeid;
1457 if (IsPathSeparator(entry.fullname.GetChar(entry.fullname.Length()-1))) {
1460 #if wxCHECK_VERSION(2, 6, 0)
1461 wxTreeItemIdValue cookie;
1466 treeid = tree->GetFirstChild(item, cookie);
1468 bool updated = false;
1470 while (treeid.IsOk()) {
1471 itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1472 if (entry.filename == itemStr) {
1473 if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != entry.marked) {
1474 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Normal);
1475 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Selected);
1476 static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(entry.marked);
1478 if ((recurse) && (tree->IsExpanded(treeid))) {
1479 UpdateTreeItem(treeid, false, true);
1484 treeid = tree->GetNextChild(item, cookie);
1488 treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(entry.filename), entry.marked, entry.marked, new wxbTreeItemData(entry.fullname, entry.filename, entry.marked));
1493 long ind = list->InsertItem(list->GetItemCount(), entry.marked);
1494 wxbTreeItemData* data = new wxbTreeItemData(entry.fullname, entry.filename, entry.marked, ind);
1495 data->SetId(treeid);
1496 list->SetItemData(ind, (long)data);
1497 list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(entry.filename));
1498 list->SetItem(ind, 2, entry.size);
1499 list->SetItem(ind, 3, entry.date);
1500 list->SetItem(ind, 4, entry.perm);
1501 list->SetItem(ind, 5, entry.user);
1502 list->SetItem(ind, 6, entry.group);
1512 /* Parse .dir command results, returns true if the result has been stored in entry, false otherwise. */
1513 int wxbRestorePanel::ParseList(wxString line, wxbDirEntry* entry)
1515 /* See ls_output in dird/ua_tree.c */
1516 //-rw-r-----,1,root,root,41575,2005-10-18 18:21:36, ,/usr/var/bacula/working/bacula.sql
1518 wxStringTokenizer tkz(line, wxT(","));
1520 if (!tkz.HasMoreTokens())
1522 entry->perm = tkz.GetNextToken();
1524 if (!tkz.HasMoreTokens())
1526 entry->nlink = tkz.GetNextToken();
1528 if (!tkz.HasMoreTokens())
1530 entry->user = tkz.GetNextToken();
1532 if (!tkz.HasMoreTokens())
1534 entry->group = tkz.GetNextToken();
1536 if (!tkz.HasMoreTokens())
1538 entry->size = tkz.GetNextToken();
1540 if (!tkz.HasMoreTokens())
1542 entry->date = tkz.GetNextToken();
1544 if (!tkz.HasMoreTokens())
1546 wxString marked = tkz.GetNextToken();
1547 if (marked == wxT("*")) {
1550 else if (marked == wxT("+")) {
1557 if (!tkz.HasMoreTokens())
1559 entry->fullname = tkz.GetString();
1561 /* Get only the filename (cut path by finding the last '/') */
1562 if (IsPathSeparator(entry->fullname.GetChar(entry->fullname.Length()-1))) {
1563 wxString tmp = entry->fullname;
1565 entry->filename = entry->fullname.Mid(tmp.Find('/', true)+1);
1568 entry->filename = entry->fullname.Mid(entry->fullname.Find('/', true)+1);
1574 /* Sets a list item state, and update its parents and children if it is a directory */
1575 void wxbRestorePanel::SetListItemState(long listitem, int newstate)
1577 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1579 wxTreeItemId treeitem;
1581 itemdata->SetMarked(newstate);
1582 list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1583 list->SetItemImage(listitem, newstate, 1);
1585 if ((treeitem = itemdata->GetId()).IsOk()) {
1586 SetTreeItemState(treeitem, newstate);
1589 UpdateTreeItemState(tree->GetSelection());
1593 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1594 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1595 #if wxCHECK_VERSION(2, 6, 0)
1596 wxTreeItemIdValue cookie;
1600 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1602 wxbTreeItemData* itemdata;
1604 while (currentChild.IsOk()) {
1605 itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1606 int state = itemdata->GetMarked();
1608 if (state != newstate) {
1609 itemdata->SetMarked(newstate);
1610 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1611 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1614 currentChild = tree->GetNextChild(item, cookie);
1617 itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1618 itemdata->SetMarked(newstate);
1619 tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1620 tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1623 if (tree->GetSelection() == item) {
1624 for (long i = 0; i < list->GetItemCount(); i++) {
1625 list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1626 list->SetItemImage(i, newstate, 1);
1630 UpdateTreeItemState(tree->GetItemParent(item));
1633 /* Update a tree item state, and its parents' state */
1634 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {
1641 #if wxCHECK_VERSION(2, 6, 0)
1642 wxTreeItemIdValue cookie;
1646 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1648 bool onechildmarked = false;
1649 bool onechildunmarked = false;
1651 while (currentChild.IsOk()) {
1652 state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1655 onechildunmarked = true;
1658 onechildmarked = true;
1661 onechildmarked = true;
1662 onechildunmarked = true;
1666 if (onechildmarked && onechildunmarked) {
1670 currentChild = tree->GetNextChild(item, cookie);
1673 if (tree->GetSelection() == item) {
1674 for (long i = 0; i < list->GetItemCount(); i++) {
1675 state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1679 onechildunmarked = true;
1682 onechildmarked = true;
1685 onechildmarked = true;
1686 onechildunmarked = true;
1690 if (onechildmarked && onechildunmarked) {
1698 if (onechildmarked && onechildunmarked) {
1701 else if (onechildmarked) {
1704 else if (onechildunmarked) {
1707 else { // no child, don't change anything
1708 UpdateTreeItemState(tree->GetItemParent(item));
1712 wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1714 itemdata->SetMarked(state);
1715 tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1716 tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1718 UpdateTreeItemState(tree->GetItemParent(item));
1721 /* Refresh the whole tree. */
1722 void wxbRestorePanel::RefreshTree() {
1723 /* Save current selection */
1724 wxArrayString current;
1726 wxTreeItemId item = currentTreeItem;
1728 while ((item.IsOk()) && (item != tree->GetRootItem())) {
1729 current.Add(tree->GetItemText(item));
1730 item = tree->GetItemParent(item);
1733 /* Update the tree */
1734 UpdateTreeItem(tree->GetRootItem(), false, true);
1736 /* Reselect the former selected item */
1737 item = tree->GetRootItem();
1739 if (current.Count() == 0) {
1740 tree->SelectItem(item);
1746 for (int i = current.Count()-1; i >= 0; i--) {
1747 #if wxCHECK_VERSION(2, 6, 0)
1748 wxTreeItemIdValue cookie;
1752 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1756 while (currentChild.IsOk()) {
1757 if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1758 item = currentChild;
1763 currentChild = tree->GetNextChild(item, cookie);
1769 UpdateTreeItem(item, true, false); /* Update the list */
1771 tree->SelectItem(item);
1774 void wxbRestorePanel::RefreshList() {
1775 if (currentTreeItem.IsOk()) {
1776 UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1780 /* Update first config, adapting settings to the job name selected */
1781 void wxbRestorePanel::UpdateFirstConfig() {
1782 configPanel->Enable(false);
1783 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(wxT(".defaults job=")) + configPanel->GetRowString(_("Job Name")) + wxT("\n"), true, false);
1789 * where=/tmp/bacula-restores
1799 bool dolistjobs = false;
1801 for (i = 0; i < dt->GetCount(); i++) {
1803 if ((j = str.Find('=')) > -1) {
1804 name = str.Mid(0, j);
1805 if (name == wxT("pool")) {
1806 configPanel->SetRowString(_("Pool"), str.Mid(j+1));
1808 else if (name == wxT("client")) {
1810 if ((str != configPanel->GetRowString(_("Client"))) ||
1811 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1812 configPanel->SetRowString(_("Client"), str);
1816 else if (name == wxT("storage")) {
1817 configPanel->SetRowString(_("Storage"), str.Mid(j+1));
1819 else if (name == wxT("fileset")) {
1821 if ((str != configPanel->GetRowString(_("Fileset"))) ||
1822 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1823 configPanel->SetRowString(_("Fileset"), str);
1833 //wxTheApp->Yield(false);
1836 configPanel->Enable(true);
1840 * Update second config.
1843 * JobName: RestoreFiles
1844 * Bootstrap: /var/lib/bacula/restore.bsr
1845 * Where: /tmp/bacula-restores
1850 * When: 2004-04-18 01:18:56
1852 * OK to run? (yes/mod/no):
1855 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1857 for (i = 0; i < dt->GetCount(); i++) {
1858 if ((*dt)[i].Find(_("Run Restore job")) == 0)
1862 if ((i + 10) > dt->GetCount()) {
1868 if ((k = (*dt)[++i].Find(_("JobName:"))) != 0) return false;
1869 restorePanel->SetRowString(_("Job Name"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1870 if ((k = (*dt)[++i].Find(_("Bootstrap:"))) != 0) return false;
1871 restorePanel->SetRowString(_("Bootstrap"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1872 if ((k = (*dt)[++i].Find(_("Where:"))) != 0) return false;
1873 restorePanel->SetRowString(_("Where"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1875 if ((k = (*dt)[++i].Find(_("Replace:"))) != 0) return false;
1876 wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1877 if (str == _("always")) restorePanel->SetRowSelection(_("Replace"), 0);
1878 else if (str == _("ifnewer")) restorePanel->SetRowSelection(_("Replace"), 1);
1879 else if (str == _("ifolder")) restorePanel->SetRowSelection(_("Replace"), 2);
1880 else if (str == _("never")) restorePanel->SetRowSelection(_("Replace"), 3);
1881 else restorePanel->SetRowSelection(_("Replace"), 0);
1883 if ((k = (*dt)[++i].Find(_("FileSet:"))) != 0) return false;
1884 restorePanel->SetRowString(_("Fileset"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1885 if ((k = (*dt)[++i].Find(_("Client:"))) != 0) return false;
1886 restorePanel->SetRowString(_("Client"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1887 if ((k = (*dt)[++i].Find(_("Storage:"))) != 0) return false;
1888 restorePanel->SetRowString(_("Storage"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1889 if ((k = (*dt)[++i].Find(_("When:"))) != 0) return false;
1890 restorePanel->SetRowString(_("When"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1891 i++; /* Skip catalog field */
1892 if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1893 restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1896 restorePanel->Layout();
1901 /*----------------------------------------------------------------------------
1903 ----------------------------------------------------------------------------*/
1905 /* Set current status by enabling/disabling components */
1906 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1907 switch (newstatus) {
1909 centerSizer->Remove(configPanel);
1910 centerSizer->Remove(restorePanel);
1911 centerSizer->Remove(treelistPanel);
1912 treelistPanel->Show(false);
1913 restorePanel->Show(false);
1914 centerSizer->Add(configPanel, 1, wxEXPAND);
1915 configPanel->Show(true);
1916 configPanel->Layout();
1917 centerSizer->Layout();
1919 start->SetLabel(_("Enter restore mode"));
1920 start->Enable(false);
1921 configPanel->Enable(false);
1922 tree->Enable(false);
1923 list->Enable(false);
1924 gauge->Enable(false);
1925 cancel->Enable(false);
1930 centerSizer->Remove(configPanel);
1931 centerSizer->Remove(restorePanel);
1932 centerSizer->Remove(treelistPanel);
1933 treelistPanel->Show(false);
1934 restorePanel->Show(false);
1935 centerSizer->Add(configPanel, 1, wxEXPAND);
1936 configPanel->Show(true);
1937 configPanel->Layout();
1938 centerSizer->Layout();
1940 tree->DeleteAllItems();
1941 list->DeleteAllItems();
1942 configPanel->ClearRowChoices(_("Client"));
1943 configPanel->ClearRowChoices(_("Before"));
1944 wxbMainFrame::GetInstance()->EnablePanels();
1945 newstatus = activable;
1948 start->SetLabel(_("Enter restore mode"));
1949 start->Enable(true);
1950 configPanel->Enable(false);
1951 tree->Enable(false);
1952 list->Enable(false);
1953 gauge->Enable(false);
1954 cancel->Enable(false);
1958 wxbMainFrame::GetInstance()->DisablePanels(this);
1960 start->Enable(false);
1961 //start->SetLabel(_("Choose files to restore"));
1962 configPanel->Enable(true);
1963 tree->Enable(false);
1964 list->Enable(false);
1965 cancel->Enable(true);
1972 start->Enable(true);
1973 start->SetLabel(_("Restore"));
1974 centerSizer->Remove(configPanel);
1975 configPanel->Show(false);
1976 centerSizer->Add(treelistPanel, 1, wxEXPAND);
1977 treelistPanel->Show(true);
1978 treelistPanel->Layout();
1979 centerSizer->Layout();
1986 start->Enable(false);
1987 configPanel->Enable(false);
1988 tree->Enable(false);
1989 list->Enable(false);
1990 centerSizer->Remove(treelistPanel);
1991 treelistPanel->Show(false);
1992 centerSizer->Add(restorePanel, 1, wxEXPAND);
1993 restorePanel->Show(true);
1994 restorePanel->Layout();
1995 centerSizer->Layout();
1997 restorePanel->EnableApply(false);
2000 start->SetLabel(_("Restoring..."));
2001 gauge->Enable(true);
2003 start->Enable(false);
2004 configPanel->Enable(false);
2005 tree->Enable(false);
2006 list->Enable(false);
2013 /*----------------------------------------------------------------------------
2015 ----------------------------------------------------------------------------*/
2017 void wxbRestorePanel::SetWorking(bool working) {
2018 this->working = working;
2020 SetCursor(*wxHOURGLASS_CURSOR);
2021 // SetEvtHandlerEnabled(false); //EVTQUEUE
2023 // else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
2025 // processing = true; //EVTQUEUE
2026 SetCursor(*wxSTANDARD_CURSOR);
2027 // SetEvtHandlerEnabled(true); //EVTQUEUE
2028 /* wxNode *node = pendingEvents->First(); //EVTQUEUE
2030 wxEvent *event = (wxEvent *)node->Data();
2033 wxEvtHandler::ProcessEvent(*event);
2036 node = pendingEvents->First();
2038 processing = false;*/
2042 bool wxbRestorePanel::IsWorking() {
2043 return this->working;
2046 void wxbRestorePanel::EnableConfig(bool enable) {
2047 restorePanel->Enable(enable);
2050 /*----------------------------------------------------------------------------
2052 ----------------------------------------------------------------------------*/
2057 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2058 if (IsWorking() || processing) {
2059 wxEvent *eventCopy = event.Clone();
2061 pendingEvents->Append(eventCopy);
2065 return wxEvtHandler::ProcessEvent(event);
2070 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2071 cancel->Enable(false);
2072 SetCursor(*wxHOURGLASS_CURSOR);
2074 SetCursor(*wxSTANDARD_CURSOR);
2077 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2086 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2092 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2098 //CmdList(event.GetItem());
2099 if (tree->GetSelection() != event.GetItem()) {
2100 tree->SelectItem(event.GetItem());
2105 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2109 if (currentTreeItem == event.GetItem()) {
2112 treeadd->Enable(false);
2113 treeremove->Enable(false);
2114 treerefresh->Enable(false);
2115 markWhenCommandDone = false;
2117 currentTreeItem = event.GetItem();
2118 CmdList(event.GetItem());
2119 if (markWhenCommandDone) {
2120 CmdMark(event.GetItem(), NULL, 0);
2124 if (event.GetItem().IsOk()) {
2125 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2126 treeadd->Enable(status != 1);
2127 treeremove->Enable(status != 0);
2129 treerefresh->Enable(true);
2132 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2134 if (tree->GetSelection() == event.GetItem()) {
2135 markWhenCommandDone = !markWhenCommandDone;
2140 markWhenCommandDone = false;
2141 CmdMark(event.GetItem(), NULL, 0);
2142 if (markWhenCommandDone) {
2143 CmdMark(event.GetItem(), NULL, 0);
2148 if (event.GetItem().IsOk()) {
2149 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2150 treeadd->Enable(status != 1);
2151 treeremove->Enable(status != 0);
2155 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2160 if (currentTreeItem.IsOk()) {
2162 CmdMark(currentTreeItem, NULL, 0, 1);
2165 treeremove->Enable(1);
2170 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2175 if (currentTreeItem.IsOk()) {
2177 CmdMark(currentTreeItem, NULL, 0, 0);
2180 treeremove->Enable(0);
2185 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2195 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2200 if (list->GetSelectedItemCount() == 0) {
2206 long* items = new long[list->GetSelectedItemCount()];
2210 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2211 while (item != -1) {
2214 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2217 CmdMark(wxTreeItemId(), items, num);
2221 wxListEvent listevt;
2223 OnListChanged(listevt);
2230 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2235 long item = event.GetIndex();
2236 // long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2238 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2239 wxString name = itemdata->GetName();
2244 #if wxCHECK_VERSION(2, 6, 0)
2245 wxTreeItemIdValue cookie;
2250 if (IsPathSeparator(name.GetChar(name.Length()-1))) {
2251 wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2253 while (currentChild.IsOk()) {
2254 wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2255 if (name2 == name) {
2256 //tree->UnselectAll();
2258 tree->Expand(currentTreeItem);
2259 tree->SelectItem(currentChild);
2263 currentChild = tree->GetNextChild(currentTreeItem, cookie);
2270 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2275 listadd->Enable(false);
2276 listremove->Enable(false);
2278 bool marked = false;
2279 bool unmarked = false;
2281 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2282 while (item != -1) {
2283 switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2296 // Should never happen
2298 if (marked && unmarked) break;
2299 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2302 listadd->Enable(unmarked);
2303 listremove->Enable(marked);
2306 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2313 long* items = new long[list->GetSelectedItemCount()];
2317 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2318 while (item != -1) {
2321 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2324 CmdMark(wxTreeItemId(), items, num, 1);
2331 listadd->Enable(false);
2332 listremove->Enable(true);
2335 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2342 long* items = new long[list->GetSelectedItemCount()];
2346 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2347 while (item != -1) {
2350 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2353 CmdMark(wxTreeItemId(), items, num, 0);
2360 listadd->Enable(true);
2361 listremove->Enable(false);
2364 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2374 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2375 if (status == entered) {
2376 if (event.GetId() == ConfigJobName) {
2381 UpdateFirstConfig();
2384 else if ((event.GetId() == ConfigClient) || (event.GetId() == ConfigFileset)) {
2389 configPanel->Enable(false);
2391 configPanel->Enable(true);
2394 cfgUpdated = cfgUpdated | (1 << event.GetId());
2396 else if (status == configuring) {
2397 restorePanel->EnableApply(true);
2398 cfgUpdated = cfgUpdated | (1 << event.GetId());
2402 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2403 if (status != configuring) return;
2412 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2413 if (status != configuring) return;
2419 if (cfgUpdated == 0) {
2420 restorePanel->EnableApply(false);
2425 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2426 if (status != configuring) return;