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 and included
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/imaglist.h>
84 #include <wx/listimpl.cpp>
86 /* A macro named Yield is defined under MinGW */
89 WX_DEFINE_LIST(wxbEventList);
92 * Class which is stored in the tree and in the list to keep informations
95 class wxbTreeItemData : public wxTreeItemData {
97 wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
103 void SetMarked(int marked);
107 wxString* path; /* Full path */
108 wxString* name; /* File name */
109 int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
110 long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
113 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
114 this->path = new wxString(path);
115 this->name = new wxString(name);
116 this->marked = marked;
117 this->listid = listid;
120 wxbTreeItemData::~wxbTreeItemData() {
125 int wxbTreeItemData::GetMarked() {
129 void wxbTreeItemData::SetMarked(int marked) {
130 this->marked = marked;
133 long wxbTreeItemData::GetListId() {
137 wxString wxbTreeItemData::GetPath() {
141 wxString wxbTreeItemData::GetName() {
145 // ----------------------------------------------------------------------------
146 // event tables and other macros for wxWindows
147 // ----------------------------------------------------------------------------
175 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
176 EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
177 EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
179 EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
180 EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
181 EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
182 EVT_TREE_MARKED_EVENT(TreeCtrl, wxbRestorePanel::OnTreeMarked)
183 EVT_BUTTON(TreeAdd, wxbRestorePanel::OnTreeAdd)
184 EVT_BUTTON(TreeRemove, wxbRestorePanel::OnTreeRemove)
185 EVT_BUTTON(TreeRefresh, wxbRestorePanel::OnTreeRefresh)
187 EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
188 EVT_LIST_MARKED_EVENT(ListCtrl, wxbRestorePanel::OnListMarked)
189 EVT_LIST_ITEM_SELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
190 EVT_LIST_ITEM_DESELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
191 EVT_BUTTON(ListAdd, wxbRestorePanel::OnListAdd)
192 EVT_BUTTON(ListRemove, wxbRestorePanel::OnListRemove)
193 EVT_BUTTON(ListRefresh, wxbRestorePanel::OnListRefresh)
195 EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
196 EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
197 EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
198 EVT_CHOICE(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
199 EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
200 EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
201 EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
202 EVT_CHOICE(ConfigStorage, wxbRestorePanel::OnConfigUpdated)
203 EVT_CHOICE(ConfigJobName, wxbRestorePanel::OnConfigUpdated)
204 EVT_CHOICE(ConfigPool, wxbRestorePanel::OnConfigUpdated)
206 EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
207 EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
208 EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
212 * wxbRestorePanel constructor
214 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent)
216 //pendingEvents = new wxbEventList(); //EVTQUEUE
217 //processing = false; //EVTQUEUE
220 imagelist = new wxImageList(16, 16, TRUE, 3);
221 imagelist->Add(wxIcon(unmarked_xpm));
222 imagelist->Add(wxIcon(marked_xpm));
223 imagelist->Add(wxIcon(partmarked_xpm));
225 wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
226 mainSizer->AddGrowableCol(0);
227 mainSizer->AddGrowableRow(1);
229 wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
231 firstSizer->AddGrowableCol(0);
232 firstSizer->AddGrowableRow(0);
234 start = new wxButton(this, RestoreStart, _("Enter restore mode"), wxDefaultPosition, wxSize(150, 30));
235 firstSizer->Add(start, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
237 cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
238 firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
242 /* clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
243 firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
245 jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
246 firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
248 mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
250 treelistPanel = new wxSplitterWindow(this);
252 wxPanel* treePanel = new wxPanel(treelistPanel);
253 wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
254 treeSizer->AddGrowableCol(0);
255 treeSizer->AddGrowableRow(0);
257 tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));
258 tree->SetImageList(imagelist);
260 treeSizer->Add(tree, 1, wxEXPAND, 0);
262 wxBoxSizer *treeCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
263 treeadd = new wxButton(treePanel, TreeAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
264 treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
265 treeremove = new wxButton(treePanel, TreeRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
266 treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
267 treerefresh = new wxButton(treePanel, TreeRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
268 treeCtrlSizer->Add(treerefresh, 0, wxLEFT | wxRIGHT, 3);
270 treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
272 treePanel->SetSizer(treeSizer);
274 wxPanel* listPanel = new wxPanel(treelistPanel);
275 wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
276 listSizer->AddGrowableCol(0);
277 listSizer->AddGrowableRow(0);
279 list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
280 //treelistSizer->Add(list, 1, wxEXPAND, 10);
282 list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
285 info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
286 info.SetText(_("M"));
287 info.SetAlign(wxLIST_FORMAT_CENTER);
288 list->InsertColumn(0, info);
290 info.SetText(_("Filename"));
291 info.SetAlign(wxLIST_FORMAT_LEFT);
292 list->InsertColumn(1, info);
294 info.SetText(_("Size"));
295 info.SetAlign(wxLIST_FORMAT_RIGHT);
296 list->InsertColumn(2, info);
298 info.SetText(_("Date"));
299 info.SetAlign(wxLIST_FORMAT_LEFT);
300 list->InsertColumn(3, info);
302 info.SetText(_("Perm."));
303 info.SetAlign(wxLIST_FORMAT_LEFT);
304 list->InsertColumn(4, info);
306 info.SetText(_("User"));
307 info.SetAlign(wxLIST_FORMAT_RIGHT);
308 list->InsertColumn(5, info);
310 info.SetText(_("Group"));
311 info.SetAlign(wxLIST_FORMAT_RIGHT);
312 list->InsertColumn(6, info);
314 listSizer->Add(list, 1, wxEXPAND, 0);
316 wxBoxSizer *listCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
317 listadd = new wxButton(listPanel, ListAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
318 listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
319 listremove = new wxButton(listPanel, ListRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
320 listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
321 listrefresh = new wxButton(listPanel, ListRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
322 listCtrlSizer->Add(listrefresh, 0, wxLEFT | wxRIGHT, 5);
324 listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
326 listPanel->SetSizer(listSizer);
328 treelistPanel->SplitVertically(treePanel, listPanel, 210);
330 treelistPanel->SetMinimumPaneSize(210);
332 treelistPanel->Show(false);
334 wxbConfig* config = new wxbConfig();
335 config->Add(new wxbConfigParam(_("Job Name"), ConfigJobName, choice, 0, elist));
336 config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, elist));
337 config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, elist));
338 config->Add(new wxbConfigParam(_("Pool"), ConfigPool, choice, 0, elist));
339 config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, elist));
340 config->Add(new wxbConfigParam(_("Before"), ConfigWhen, choice, 0, elist));
342 configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
344 configPanel->Show(true);
345 configPanel->Enable(false);
347 config = new wxbConfig();
348 config->Add(new wxbConfigParam(_("Job Name"), -1, text, wxT("")));
349 config->Add(new wxbConfigParam(_("Bootstrap"), -1, text, wxT("")));
350 config->Add(new wxbConfigParam(_("Where"), ConfigWhere, modifiableText, wxT("")));
351 wxString erlist[] = {_("always"), _("if newer"), _("if older"), _("never")};
352 config->Add(new wxbConfigParam(_("Replace"), ConfigReplace, choice, 4, erlist));
353 config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, erlist));
354 config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, erlist));
355 config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, erlist));
356 config->Add(new wxbConfigParam(_("When"), ConfigWhen, modifiableText, wxT("")));
357 config->Add(new wxbConfigParam(_("Priority"), ConfigPriority, modifiableText, wxT("")));
359 restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
361 restorePanel->Show(false);
363 centerSizer = new wxBoxSizer(wxHORIZONTAL);
364 //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
366 mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
368 gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
370 mainSizer->Add(gauge, 1, wxEXPAND, 5);
372 gauge->Enable(false);
375 mainSizer->SetSizeHints(this);
379 for (int i = 0; i < 7; i++) {
380 list->SetColumnWidth(i, 70);
383 SetCursor(*wxSTANDARD_CURSOR);
385 markWhenCommandDone = false;
391 * wxbRestorePanel destructor
393 wxbRestorePanel::~wxbRestorePanel()
398 /*----------------------------------------------------------------------------
399 wxbPanel overloadings
400 ----------------------------------------------------------------------------*/
402 wxString wxbRestorePanel::GetTitle()
407 void wxbRestorePanel::EnablePanel(bool enable)
410 if (status == disabled) {
411 SetStatus(activable);
418 /*----------------------------------------------------------------------------
419 Commands called by events handler
420 ----------------------------------------------------------------------------*/
422 /* The main button has been clicked */
423 void wxbRestorePanel::CmdStart()
426 if (status == activable) {
427 wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
428 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
431 configPanel->ClearRowChoices(_("Client"));
432 restorePanel->ClearRowChoices(_("Client"));
434 if (dt->GetCount() == 0) {
435 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
439 for (i = 0; i < dt->GetCount(); i++) {
442 configPanel->AddRowChoice(_("Client"), str);
443 restorePanel->AddRowChoice(_("Client"), str);
453 dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
455 configPanel->ClearRowChoices(_("Fileset"));
456 restorePanel->ClearRowChoices(_("Fileset"));
458 if (dt->GetCount() == 0) {
459 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
463 for (i = 0; i < dt->GetCount(); i++) {
466 configPanel->AddRowChoice(_("Fileset"), str);
467 restorePanel->AddRowChoice(_("Fileset"), str);
477 dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
479 configPanel->ClearRowChoices(_("Storage"));
480 restorePanel->ClearRowChoices(_("Storage"));
482 if (dt->GetCount() == 0) {
483 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
487 for (i = 0; i < dt->GetCount(); i++) {
490 configPanel->AddRowChoice(_("Storage"), str);
491 restorePanel->AddRowChoice(_("Storage"), str);
501 dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
503 configPanel->ClearRowChoices(_("Job Name"));
505 if (dt->GetCount() == 0) {
506 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
510 for (i = 0; i < dt->GetCount(); i++) {
513 configPanel->AddRowChoice(_("Job Name"), str);
516 configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
525 dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
527 configPanel->ClearRowChoices(_("Pool"));
529 if (dt->GetCount() == 0) {
530 wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
534 for (i = 0; i < dt->GetCount(); i++) {
537 configPanel->AddRowChoice(_("Pool"), str);
551 wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
553 else if (status == entered) {
554 /* if (clientChoice->GetStringSelection().Length() < 1) {
555 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
558 if (jobChoice->GetStringSelection().Length() < 1) {
559 wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
562 wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
566 wxbTableParser* tableparser = new wxbTableParser();
567 wxbDataTokenizer* dt = new wxbDataTokenizer(false);
570 * The following line was removed from ::GetInstance below because
571 * it does not work with multiple pools -- KES 5Oct05 see bug #433
572 * wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
574 wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
575 wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
576 wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
577 wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
578 wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
580 //wxbUtils::WaitForPrompt("6\n");
582 /*wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
583 int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
584 if (client == wxNOT_FOUND) {
585 wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
590 //wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
592 while (!tableparser->hasFinished() && !dt->hasFinished()) {
593 wxTheApp->Yield(true);
594 wxbUtils::MilliSleep(100);
599 if (dt->hasFinished() && !tableparser->hasFinished()) {
601 if (dt->GetCount() > 1) {
602 str = (*dt)[dt->GetCount()-2];
605 wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
615 for (i = 0; i < tableparser->GetCount(); i++) {
616 str = (*tableparser)[i][2];
617 str.Replace(wxT(","), wxT(""));
618 if (str.ToLong(&l)) {
624 gauge->SetRange(tot);
626 /*wxbMainFrame::GetInstance()->Print(
627 wxString("[") << tot << "]", CS_DEBUG);*/
629 wxDateTime base = wxDateTime::Now();
633 unsigned int lastindex = 0;
640 newdate = wxDateTime::Now();
641 if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
643 for (; lastindex < dt->GetCount(); lastindex++) {
644 if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) &&
645 ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
646 str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
647 for (i = 0; i < tableparser->GetCount(); i++) {
648 if (str == (*tableparser)[i][0]) {
649 str = (*tableparser)[i][2];
650 str.Replace(wxT(","), wxT(""));
651 if (str.ToLong(&l)) {
654 var = (willdo-done)/50;
655 gauge->SetValue(done);
656 wxTheApp->Yield(true);
662 else if ((*dt)[lastindex] == wxT("+")) {
663 gauge->SetValue(gauge->GetValue()+var);
664 wxTheApp->Yield(true);
669 if (dt->hasFinished()) {
673 wxTheApp->Yield(true);
674 wxbUtils::MilliSleep(1);
677 gauge->SetValue(tot);
678 wxTheApp->Yield(true);
689 wxbUtils::WaitForEnd(wxT("unmark *\n"));
690 wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
691 currentTreeItem = root;
693 tree->SelectItem(root);
695 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."));
698 else if (status == choosing) {
702 wxbDataTokenizer* dt;
706 dt = new wxbDataTokenizer(true);
707 wxbPromptParser* promptparser = wxbUtils::WaitForPrompt(wxT("done\n"), true);
709 while (!promptparser->getChoices() || (promptparser->getChoices()->Index(wxT("mod")) < 0)) {
710 wxbMainFrame::GetInstance()->Print(_("Unexpected question has been received.\n"), CS_DEBUG);
713 if (promptparser->getIntroString() != wxT("")) {
714 message << promptparser->getIntroString() << wxT("\n");
716 message << promptparser->getQuestionString();
718 if (promptparser->getChoices()) {
719 wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
720 int *numbers = new int[promptparser->getChoices()->GetCount()];
723 for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
724 if ((*promptparser->getChoices())[i] != wxT("")) {
725 choices[n] = (*promptparser->getChoices())[i];
731 int res = ::wxGetSingleChoiceIndex(message,
732 _("bwx-console: unexpected restore question."), n, choices, this);
735 promptparser = wxbUtils::WaitForPrompt(wxT(".\n"), true);
738 if (promptparser->isNumericalChoice()) {
740 promptparser = wxbUtils::WaitForPrompt(wxString() << numbers[res] << wxT("\n"), true);
744 promptparser = wxbUtils::WaitForPrompt(wxString() << choices[res] << wxT("\n"), true);
753 promptparser = wxbUtils::WaitForPrompt(::wxGetTextFromUser(message,
754 _("bwx-console: unexpected restore question."),
755 wxT(""), this) + wxT("\n"));
758 printf("promptparser->getChoices()=%ld", (long)promptparser->getChoices());
762 SetStatus(configuring);
764 for (i = 0; i < dt->GetCount(); i++) {
765 if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
766 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
770 if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
771 (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
776 wxbMainFrame::GetInstance()->SetStatusText(
777 wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
779 UpdateSecondConfig(dt);
784 restorePanel->EnableApply(false);
786 if (totfilemessages == 0) {
787 wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
788 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
793 else if (status == configuring) {
794 cancel->Enable(false);
798 wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
800 wxbDataTokenizer* dt;
802 SetStatus(restoring);
803 dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
806 gauge->SetRange(totfilemessages);
810 for (i = 0; i < dt->GetCount(); i++) {
811 if ((j = (*dt)[i].Find(_("Job queued. JobId="))) > -1) {
812 jobid = (*dt)[i].Mid(j+19);
813 wxbMainFrame::GetInstance()->SetStatusText(_("Restore queued, jobid=") + jobid);
817 if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
818 wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
819 wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
824 if (jobid == wxT("")) {
825 wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
826 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
830 wxDateTime currenttime;
832 dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
833 wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
834 if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
835 (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
836 currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
839 currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
843 wxDateTime scheduledtime;
844 wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
846 if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
847 (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
848 scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
851 if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
852 wxbMainFrame::GetInstance()->Print(_("Restore is scheduled in more than two minutes, bwx-console will not wait for its completion.\n"), CS_DEBUG);
853 wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled in more than two minutes, bwx-console will not wait for its completion."));
858 wxString cmd = wxString(wxT("list jobid=")) + jobid;
860 wxbTableParser* tableparser;
862 long filemessages = 0;
865 bool waitforever = false;
871 wxbUtils::WaitForEnd(wxT("autodisplay off\n"));
872 wxbUtils::WaitForEnd(wxT("gui on\n"));
874 tableparser = wxbUtils::CreateAndWaitForParser(cmd);
876 status = (*tableparser)[0][7].GetChar(0);
879 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
883 wxbMainFrame::GetInstance()->SetStatusText(
884 wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
888 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
889 wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
893 case JS_ErrorTerminated:
894 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
895 wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
900 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
904 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
909 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
910 wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
915 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
919 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
922 case JS_WaitStoreRes:
923 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
927 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
930 case JS_WaitClientRes:
931 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
935 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
938 case JS_WaitStartTime:
939 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
942 case JS_WaitPriority:
943 wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
949 dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
951 for (unsigned int i = 0; i < dt->GetCount(); i++) {
952 wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
956 // Date Time name: perm ? user grp size date time
957 //04-Apr-2004 17:19 Tom-fd: -rwx------ 1 nicolas None 514967 2004-03-20 20:03:42 filename
959 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
960 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
961 if (tkz.GetNextToken().Last() == ':') { // name:
962 tkz.GetNextToken(); // perm
963 tkz.GetNextToken(); // ?
964 tkz.GetNextToken(); // user
965 tkz.GetNextToken(); // grp
966 tkz.GetNextToken(); // size
967 if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
968 if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
970 //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
971 gauge->SetValue(filemessages);
982 while (sw2.Time() < 10000) {
983 wxTheApp->Yield(true);
984 wxbUtils::MilliSleep(100);
991 if ((!waitforever) && (sw.Time() > 60000)) {
992 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);
993 wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, bwx-console will not wait for its completion anymore."));
997 wxbUtils::WaitForEnd(wxT("autodisplay on\n"));
998 wxbUtils::WaitForEnd(wxT(".messages\n"));
1000 gauge->SetValue(totfilemessages);
1002 if (status == JS_Terminated) {
1003 wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
1004 wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
1006 SetStatus(finished);
1010 /* The cancel button has been clicked */
1011 void wxbRestorePanel::CmdCancel() {
1014 if (status == restoring) {
1015 if (jobid != wxT("")) {
1016 wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
1018 cancel->Enable(true);
1023 while ((IsWorking()) && (cancelled != 2)) {
1024 wxTheApp->Yield(true);
1025 wxbUtils::MilliSleep(100);
1026 if (sw.Time() > 30000) { /* 30 seconds timeout */
1027 if (status == choosing) {
1028 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1030 else if (status == configuring) {
1031 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1033 else if (status == restoring) {
1036 SetStatus(finished);
1037 wxbUtils::MilliSleep(1000);
1044 wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1047 wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1052 wxbUtils::MilliSleep(1000);
1053 SetStatus(finished);
1056 /* Apply configuration changes */
1058 /* 1: Level (not appropriate)
1063 * 6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1064 * 7: Priority (yes : "Enter new Priority: (positive integer)")
1066 * 9: Where (yes : "Please enter path prefix for restore (/ for none):")
1067 * 10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n
1068 * Select replace option (1-4):")
1072 void wxbRestorePanel::CmdConfigApply() {
1073 if (cfgUpdated == 0) return;
1075 wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1077 EnableConfig(false);
1079 wxbDataTokenizer* dt = NULL;
1081 bool failed = false;
1083 while (cfgUpdated > 0) {
1088 wxString def; //String to send if can't use our data
1089 if ((cfgUpdated >> ConfigWhere) & 1) {
1090 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1091 wxbUtils::WaitForPrompt(wxT("9\n"));
1092 dt = new wxbDataTokenizer(true);
1093 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1095 cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1097 else if ((cfgUpdated >> ConfigReplace) & 1) {
1098 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1099 wxbUtils::WaitForPrompt(wxT("10\n"));
1100 dt = new wxbDataTokenizer(true);
1101 wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1103 cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1105 else if ((cfgUpdated >> ConfigWhen) & 1) {
1106 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1107 wxbUtils::WaitForPrompt(wxT("6\n"));
1108 dt = new wxbDataTokenizer(true);
1109 wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1111 cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1113 else if ((cfgUpdated >> ConfigPriority) & 1) {
1114 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1115 wxbUtils::WaitForPrompt(wxT("7\n"));
1116 dt = new wxbDataTokenizer(true);
1117 wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1119 cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1121 else if ((cfgUpdated >> ConfigClient) & 1) {
1122 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1123 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1124 int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1125 if (client == wxNOT_FOUND) {
1126 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1131 dt = new wxbDataTokenizer(true);
1132 wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1134 cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1136 else if ((cfgUpdated >> ConfigFileset) & 1) {
1137 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1138 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1139 int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1140 if (fileset == wxNOT_FOUND) {
1141 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1146 dt = new wxbDataTokenizer(true);
1147 wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1149 cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1151 else if ((cfgUpdated >> ConfigStorage) & 1) {
1152 wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1153 wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1154 int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1155 if (fileset == wxNOT_FOUND) {
1156 wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1161 dt = new wxbDataTokenizer(true);
1162 wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1164 cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1172 for (i = 0; i < dt->GetCount(); i++) {
1173 if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1178 if (i == dt->GetCount()) {
1180 dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1184 UpdateSecondConfig(dt); /* TODO: Check result */
1189 wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1195 /* Cancel restore */
1196 void wxbRestorePanel::CmdConfigCancel() {
1197 wxbUtils::WaitForEnd(wxT("no\n"));
1198 wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1199 wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1200 SetStatus(finished);
1203 /* List jobs for a specified client and fileset */
1204 void wxbRestorePanel::CmdListJobs() {
1205 if (status == entered) {
1206 configPanel->ClearRowChoices(_("Before"));
1207 /*wxbUtils::WaitForPrompt("query\n");
1208 wxbUtils::WaitForPrompt("6\n");*/
1209 wxbTableParser* tableparser = new wxbTableParser(false);
1210 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1211 wxString(wxT(".backups client=\"")) + configPanel->GetRowString(_("Client")) +
1212 wxT("\" fileset=\"") + configPanel->GetRowString(_("Fileset")) + wxT("\"\n"), true);
1214 while (!tableparser->hasFinished()) {
1215 wxTheApp->Yield(true);
1216 wxbUtils::MilliSleep(100);
1219 if (!tableparser->GetCount() == 0) {
1220 for (unsigned int i = 0; i < dt->Count(); i++) {
1221 if ((*dt)[i].Find(_("No results to list.")) == 0) {
1222 configPanel->AddRowChoice(_("Before"),
1223 _("No backup found for this client."));
1224 configPanel->SetRowSelection(_("Before"), 0);
1225 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1230 else if (((*dt)[i].Find(_("ERROR")) > -1) ||
1231 ((*dt)[i].Find(_("Query failed")) > -1)) {
1232 configPanel->AddRowChoice(_("Before"),
1233 _("Cannot get previous backups list, see console."));
1234 configPanel->SetRowSelection(_("Before"), 0);
1235 configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1245 wxDateTime lastdatetime = (time_t) 0;
1246 for (int i = tableparser->GetCount()-1; i > -1; i--) {
1247 wxString str = (*tableparser)[i][3];
1248 wxDateTime datetime;
1250 if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) && ! lastdatetime.IsEqualTo(datetime) ) {
1251 lastdatetime = datetime;
1252 datetime += wxTimeSpan::Seconds(1);
1253 configPanel->AddRowChoice(_("Before"),
1254 datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1260 configPanel->SetRowSelection(_("Before"), 0);
1261 configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1265 /* List files and directories for a specified tree item */
1266 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1267 if (status == choosing) {
1268 list->DeleteAllItems();
1273 UpdateTreeItem(item, true, false);
1275 if (list->GetItemCount() >= 1) {
1276 int firstwidth = list->GetSize().GetWidth();
1277 for (int i = 2; i < 7; i++) {
1278 list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1279 firstwidth -= list->GetColumnWidth(i);
1282 list->SetColumnWidth(0, 18);
1284 list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1285 if (list->GetColumnWidth(1) < firstwidth) {
1286 list->SetColumnWidth(1, firstwidth-25);
1292 /* Mark a treeitem (directory) or a listitem (file or directory) */
1293 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1294 if (status == choosing) {
1295 wxbTreeItemData** itemdata;
1296 int itemdatasize = 0;
1297 if (listsize == 0) {
1298 itemdata = new wxbTreeItemData*[1];
1302 itemdata = new wxbTreeItemData*[listsize];
1303 itemdatasize = listsize;
1306 if (listitems != NULL) {
1307 for (int i = 0; i < itemdatasize; i++) {
1308 itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1311 else if (treeitem.IsOk()) {
1312 itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1319 if (itemdata[0] == NULL) { //Should never happen
1324 wxString dir = itemdata[0]->GetPath();
1327 if (dir != wxT("/")) {
1328 if (IsPathSeparator(dir.GetChar(dir.Length()-1))) {
1332 int i = dir.Find('/', TRUE);
1337 else { /* first dir below root */
1338 file = dir.Mid(i+1);
1339 dir = dir.Mid(0, i+1);
1348 bool marked = false;
1349 bool unmarked = false;
1351 for (int i = 0; i < itemdatasize; i++) {
1352 switch(itemdata[i]->GetMarked()) {
1366 if (marked && unmarked)
1382 wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1383 wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1385 /* TODO: Check commands results */
1387 /*if ((dir == "/") && (file == "*")) {
1388 itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1391 if (listitems == NULL) { /* tree item state changed */
1392 SetTreeItemState(treeitem, state);
1393 /*treeitem = tree->GetSelection();
1394 UpdateTree(treeitem, true);
1395 treeitem = tree->GetItemParent(treeitem);*/
1398 for (int i = 0; i < itemdatasize; i++) {
1399 SetListItemState(listitems[i], state);
1401 listadd->Enable(state == 0);
1402 listremove->Enable(state == 1);
1403 /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1404 treeitem = tree->GetItemParent(treeitem);*/
1407 /*while (treeitem.IsOk()) {
1408 WaitForList(treeitem, false);
1409 treeitem = tree->GetItemParent(treeitem);
1416 /*----------------------------------------------------------------------------
1418 ----------------------------------------------------------------------------*/
1420 /* Run a dir command, and waits until result is fully received. */
1421 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse)
1423 // this->updatelist = updatelist;
1424 wxbDataTokenizer* dt;
1426 dt = wxbUtils::WaitForEnd(wxString(wxT("cd \"")) <<
1427 static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1428 ->GetPath() << wxT("\"\n"), false);
1430 /* TODO: check command result */
1437 list->DeleteAllItems();
1438 dt = wxbUtils::WaitForEnd(wxT(".dir\n"), true);
1442 for (unsigned int i = 0; i < dt->GetCount(); i++) {
1445 if (str.Find(wxT("cwd is:")) == 0) { // Sometimes cd command result "infiltrate" into listings.
1453 if (!ParseList(str, &entry))
1456 wxTreeItemId treeid;
1458 if (IsPathSeparator(entry.fullname.GetChar(entry.fullname.Length()-1))) {
1461 #if wxCHECK_VERSION(2, 6, 0)
1462 wxTreeItemIdValue cookie;
1467 treeid = tree->GetFirstChild(item, cookie);
1469 bool updated = false;
1471 while (treeid.IsOk()) {
1472 itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1473 if (entry.filename == itemStr) {
1474 if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != entry.marked) {
1475 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Normal);
1476 tree->SetItemImage(treeid, entry.marked, wxTreeItemIcon_Selected);
1477 static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(entry.marked);
1479 if ((recurse) && (tree->IsExpanded(treeid))) {
1480 UpdateTreeItem(treeid, false, true);
1485 treeid = tree->GetNextChild(item, cookie);
1489 treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(entry.filename), entry.marked, entry.marked, new wxbTreeItemData(entry.fullname, entry.filename, entry.marked));
1494 long ind = list->InsertItem(list->GetItemCount(), entry.marked);
1495 wxbTreeItemData* data = new wxbTreeItemData(entry.fullname, entry.filename, entry.marked, ind);
1496 data->SetId(treeid);
1497 list->SetItemData(ind, (long)data);
1498 list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(entry.filename));
1499 list->SetItem(ind, 2, entry.size);
1500 list->SetItem(ind, 3, entry.date);
1501 list->SetItem(ind, 4, entry.perm);
1502 list->SetItem(ind, 5, entry.user);
1503 list->SetItem(ind, 6, entry.group);
1513 /* Parse .dir command results, returns true if the result has been stored in entry, false otherwise. */
1514 int wxbRestorePanel::ParseList(wxString line, wxbDirEntry* entry)
1516 /* See ls_output in dird/ua_tree.c */
1517 //-rw-r-----,1,root,root,41575,2005-10-18 18:21:36, ,/usr/var/bacula/working/bacula.sql
1519 wxStringTokenizer tkz(line, wxT(","));
1521 if (!tkz.HasMoreTokens())
1523 entry->perm = tkz.GetNextToken();
1525 if (!tkz.HasMoreTokens())
1527 entry->nlink = tkz.GetNextToken();
1529 if (!tkz.HasMoreTokens())
1531 entry->user = tkz.GetNextToken();
1533 if (!tkz.HasMoreTokens())
1535 entry->group = tkz.GetNextToken();
1537 if (!tkz.HasMoreTokens())
1539 entry->size = tkz.GetNextToken();
1541 if (!tkz.HasMoreTokens())
1543 entry->date = tkz.GetNextToken();
1545 if (!tkz.HasMoreTokens())
1547 wxString marked = tkz.GetNextToken();
1548 if (marked == wxT("*")) {
1551 else if (marked == wxT("+")) {
1558 if (!tkz.HasMoreTokens())
1560 entry->fullname = tkz.GetString();
1562 /* Get only the filename (cut path by finding the last '/') */
1563 if (IsPathSeparator(entry->fullname.GetChar(entry->fullname.Length()-1))) {
1564 wxString tmp = entry->fullname;
1566 entry->filename = entry->fullname.Mid(tmp.Find('/', true)+1);
1569 entry->filename = entry->fullname.Mid(entry->fullname.Find('/', true)+1);
1575 /* Sets a list item state, and update its parents and children if it is a directory */
1576 void wxbRestorePanel::SetListItemState(long listitem, int newstate)
1578 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1580 wxTreeItemId treeitem;
1582 itemdata->SetMarked(newstate);
1583 list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1584 list->SetItemImage(listitem, newstate, 1);
1586 if ((treeitem = itemdata->GetId()).IsOk()) {
1587 SetTreeItemState(treeitem, newstate);
1590 UpdateTreeItemState(tree->GetSelection());
1594 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1595 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1596 #if wxCHECK_VERSION(2, 6, 0)
1597 wxTreeItemIdValue cookie;
1601 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1603 wxbTreeItemData* itemdata;
1605 while (currentChild.IsOk()) {
1606 itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1607 int state = itemdata->GetMarked();
1609 if (state != newstate) {
1610 itemdata->SetMarked(newstate);
1611 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1612 tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1615 currentChild = tree->GetNextChild(item, cookie);
1618 itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1619 itemdata->SetMarked(newstate);
1620 tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1621 tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1624 if (tree->GetSelection() == item) {
1625 for (long i = 0; i < list->GetItemCount(); i++) {
1626 list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1627 list->SetItemImage(i, newstate, 1);
1631 UpdateTreeItemState(tree->GetItemParent(item));
1634 /* Update a tree item state, and its parents' state */
1635 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {
1642 #if wxCHECK_VERSION(2, 6, 0)
1643 wxTreeItemIdValue cookie;
1647 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1649 bool onechildmarked = false;
1650 bool onechildunmarked = false;
1652 while (currentChild.IsOk()) {
1653 state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1656 onechildunmarked = true;
1659 onechildmarked = true;
1662 onechildmarked = true;
1663 onechildunmarked = true;
1667 if (onechildmarked && onechildunmarked) {
1671 currentChild = tree->GetNextChild(item, cookie);
1674 if (tree->GetSelection() == item) {
1675 for (long i = 0; i < list->GetItemCount(); i++) {
1676 state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1680 onechildunmarked = true;
1683 onechildmarked = true;
1686 onechildmarked = true;
1687 onechildunmarked = true;
1691 if (onechildmarked && onechildunmarked) {
1699 if (onechildmarked && onechildunmarked) {
1702 else if (onechildmarked) {
1705 else if (onechildunmarked) {
1708 else { // no child, don't change anything
1709 UpdateTreeItemState(tree->GetItemParent(item));
1713 wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1715 itemdata->SetMarked(state);
1716 tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1717 tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1719 UpdateTreeItemState(tree->GetItemParent(item));
1722 /* Refresh the whole tree. */
1723 void wxbRestorePanel::RefreshTree() {
1724 /* Save current selection */
1725 wxArrayString current;
1727 wxTreeItemId item = currentTreeItem;
1729 while ((item.IsOk()) && (item != tree->GetRootItem())) {
1730 current.Add(tree->GetItemText(item));
1731 item = tree->GetItemParent(item);
1734 /* Update the tree */
1735 UpdateTreeItem(tree->GetRootItem(), false, true);
1737 /* Reselect the former selected item */
1738 item = tree->GetRootItem();
1740 if (current.Count() == 0) {
1741 tree->SelectItem(item);
1747 for (int i = current.Count()-1; i >= 0; i--) {
1748 #if wxCHECK_VERSION(2, 6, 0)
1749 wxTreeItemIdValue cookie;
1753 wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1757 while (currentChild.IsOk()) {
1758 if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1759 item = currentChild;
1764 currentChild = tree->GetNextChild(item, cookie);
1770 UpdateTreeItem(item, true, false); /* Update the list */
1772 tree->SelectItem(item);
1775 void wxbRestorePanel::RefreshList() {
1776 if (currentTreeItem.IsOk()) {
1777 UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1781 /* Update first config, adapting settings to the job name selected */
1782 void wxbRestorePanel::UpdateFirstConfig() {
1783 configPanel->Enable(false);
1784 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(wxT(".defaults job=")) + configPanel->GetRowString(_("Job Name")) + wxT("\n"), true, false);
1790 * where=/tmp/bacula-restores
1800 bool dolistjobs = false;
1802 for (i = 0; i < dt->GetCount(); i++) {
1804 if ((j = str.Find('=')) > -1) {
1805 name = str.Mid(0, j);
1806 if (name == wxT("pool")) {
1807 configPanel->SetRowString(_("Pool"), str.Mid(j+1));
1809 else if (name == wxT("client")) {
1811 if ((str != configPanel->GetRowString(_("Client"))) ||
1812 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1813 configPanel->SetRowString(_("Client"), str);
1817 else if (name == wxT("storage")) {
1818 configPanel->SetRowString(_("Storage"), str.Mid(j+1));
1820 else if (name == wxT("fileset")) {
1822 if ((str != configPanel->GetRowString(_("Fileset"))) ||
1823 (configPanel->GetRowString(_("Before"))) == wxT("")) {
1824 configPanel->SetRowString(_("Fileset"), str);
1834 //wxTheApp->Yield(false);
1837 configPanel->Enable(true);
1841 * Update second config.
1844 * JobName: RestoreFiles
1845 * Bootstrap: /var/lib/bacula/restore.bsr
1846 * Where: /tmp/bacula-restores
1851 * When: 2004-04-18 01:18:56
1853 * OK to run? (yes/mod/no):
1856 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1858 for (i = 0; i < dt->GetCount(); i++) {
1859 if ((*dt)[i].Find(_("Run Restore job")) == 0)
1863 if ((i + 10) > dt->GetCount()) {
1869 if ((k = (*dt)[++i].Find(_("JobName:"))) != 0) return false;
1870 restorePanel->SetRowString(_("Job Name"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1871 if ((k = (*dt)[++i].Find(_("Bootstrap:"))) != 0) return false;
1872 restorePanel->SetRowString(_("Bootstrap"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1873 if ((k = (*dt)[++i].Find(_("Where:"))) != 0) return false;
1874 restorePanel->SetRowString(_("Where"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1876 if ((k = (*dt)[++i].Find(_("Replace:"))) != 0) return false;
1877 wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1878 if (str == _("always")) restorePanel->SetRowSelection(_("Replace"), 0);
1879 else if (str == _("ifnewer")) restorePanel->SetRowSelection(_("Replace"), 1);
1880 else if (str == _("ifolder")) restorePanel->SetRowSelection(_("Replace"), 2);
1881 else if (str == _("never")) restorePanel->SetRowSelection(_("Replace"), 3);
1882 else restorePanel->SetRowSelection(_("Replace"), 0);
1884 if ((k = (*dt)[++i].Find(_("FileSet:"))) != 0) return false;
1885 restorePanel->SetRowString(_("Fileset"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1886 if ((k = (*dt)[++i].Find(_("Client:"))) != 0) return false;
1887 restorePanel->SetRowString(_("Client"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1888 if ((k = (*dt)[++i].Find(_("Storage:"))) != 0) return false;
1889 restorePanel->SetRowString(_("Storage"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1890 if ((k = (*dt)[++i].Find(_("When:"))) != 0) return false;
1891 restorePanel->SetRowString(_("When"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1892 i++; /* Skip catalog field */
1893 if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1894 restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1897 restorePanel->Layout();
1902 /*----------------------------------------------------------------------------
1904 ----------------------------------------------------------------------------*/
1906 /* Set current status by enabling/disabling components */
1907 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1908 switch (newstatus) {
1910 centerSizer->Remove(configPanel);
1911 centerSizer->Remove(restorePanel);
1912 centerSizer->Remove(treelistPanel);
1913 treelistPanel->Show(false);
1914 restorePanel->Show(false);
1915 centerSizer->Add(configPanel, 1, wxEXPAND);
1916 configPanel->Show(true);
1917 configPanel->Layout();
1918 centerSizer->Layout();
1920 start->SetLabel(_("Enter restore mode"));
1921 start->Enable(false);
1922 configPanel->Enable(false);
1923 tree->Enable(false);
1924 list->Enable(false);
1925 gauge->Enable(false);
1926 cancel->Enable(false);
1931 centerSizer->Remove(configPanel);
1932 centerSizer->Remove(restorePanel);
1933 centerSizer->Remove(treelistPanel);
1934 treelistPanel->Show(false);
1935 restorePanel->Show(false);
1936 centerSizer->Add(configPanel, 1, wxEXPAND);
1937 configPanel->Show(true);
1938 configPanel->Layout();
1939 centerSizer->Layout();
1941 tree->DeleteAllItems();
1942 list->DeleteAllItems();
1943 configPanel->ClearRowChoices(_("Client"));
1944 configPanel->ClearRowChoices(_("Before"));
1945 wxbMainFrame::GetInstance()->EnablePanels();
1946 newstatus = activable;
1949 start->SetLabel(_("Enter restore mode"));
1950 start->Enable(true);
1951 configPanel->Enable(false);
1952 tree->Enable(false);
1953 list->Enable(false);
1954 gauge->Enable(false);
1955 cancel->Enable(false);
1959 wxbMainFrame::GetInstance()->DisablePanels(this);
1961 start->Enable(false);
1962 //start->SetLabel(_("Choose files to restore"));
1963 configPanel->Enable(true);
1964 tree->Enable(false);
1965 list->Enable(false);
1966 cancel->Enable(true);
1973 start->Enable(true);
1974 start->SetLabel(_("Restore"));
1975 centerSizer->Remove(configPanel);
1976 configPanel->Show(false);
1977 centerSizer->Add(treelistPanel, 1, wxEXPAND);
1978 treelistPanel->Show(true);
1979 treelistPanel->Layout();
1980 centerSizer->Layout();
1987 start->Enable(false);
1988 configPanel->Enable(false);
1989 tree->Enable(false);
1990 list->Enable(false);
1991 centerSizer->Remove(treelistPanel);
1992 treelistPanel->Show(false);
1993 centerSizer->Add(restorePanel, 1, wxEXPAND);
1994 restorePanel->Show(true);
1995 restorePanel->Layout();
1996 centerSizer->Layout();
1998 restorePanel->EnableApply(false);
2001 start->SetLabel(_("Restoring..."));
2002 gauge->Enable(true);
2004 start->Enable(false);
2005 configPanel->Enable(false);
2006 tree->Enable(false);
2007 list->Enable(false);
2014 /*----------------------------------------------------------------------------
2016 ----------------------------------------------------------------------------*/
2018 void wxbRestorePanel::SetWorking(bool working) {
2019 this->working = working;
2021 SetCursor(*wxHOURGLASS_CURSOR);
2022 // SetEvtHandlerEnabled(false); //EVTQUEUE
2024 // else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
2026 // processing = true; //EVTQUEUE
2027 SetCursor(*wxSTANDARD_CURSOR);
2028 // SetEvtHandlerEnabled(true); //EVTQUEUE
2029 /* wxNode *node = pendingEvents->First(); //EVTQUEUE
2031 wxEvent *event = (wxEvent *)node->Data();
2034 wxEvtHandler::ProcessEvent(*event);
2037 node = pendingEvents->First();
2039 processing = false;*/
2043 bool wxbRestorePanel::IsWorking() {
2044 return this->working;
2047 void wxbRestorePanel::EnableConfig(bool enable) {
2048 restorePanel->Enable(enable);
2051 /*----------------------------------------------------------------------------
2053 ----------------------------------------------------------------------------*/
2058 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2059 if (IsWorking() || processing) {
2060 wxEvent *eventCopy = event.Clone();
2062 pendingEvents->Append(eventCopy);
2066 return wxEvtHandler::ProcessEvent(event);
2071 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2072 cancel->Enable(false);
2073 SetCursor(*wxHOURGLASS_CURSOR);
2075 SetCursor(*wxSTANDARD_CURSOR);
2078 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2087 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2093 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2099 //CmdList(event.GetItem());
2100 if (tree->GetSelection() != event.GetItem()) {
2101 tree->SelectItem(event.GetItem());
2106 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2110 if (currentTreeItem == event.GetItem()) {
2113 treeadd->Enable(false);
2114 treeremove->Enable(false);
2115 treerefresh->Enable(false);
2116 markWhenCommandDone = false;
2118 currentTreeItem = event.GetItem();
2119 CmdList(event.GetItem());
2120 if (markWhenCommandDone) {
2121 CmdMark(event.GetItem(), NULL, 0);
2125 if (event.GetItem().IsOk()) {
2126 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2127 treeadd->Enable(status != 1);
2128 treeremove->Enable(status != 0);
2130 treerefresh->Enable(true);
2133 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2135 if (tree->GetSelection() == event.GetItem()) {
2136 markWhenCommandDone = !markWhenCommandDone;
2141 markWhenCommandDone = false;
2142 CmdMark(event.GetItem(), NULL, 0);
2143 if (markWhenCommandDone) {
2144 CmdMark(event.GetItem(), NULL, 0);
2149 if (event.GetItem().IsOk()) {
2150 int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2151 treeadd->Enable(status != 1);
2152 treeremove->Enable(status != 0);
2156 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2161 if (currentTreeItem.IsOk()) {
2163 CmdMark(currentTreeItem, NULL, 0, 1);
2166 treeremove->Enable(1);
2171 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2176 if (currentTreeItem.IsOk()) {
2178 CmdMark(currentTreeItem, NULL, 0, 0);
2181 treeremove->Enable(0);
2186 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2196 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2201 if (list->GetSelectedItemCount() == 0) {
2207 long* items = new long[list->GetSelectedItemCount()];
2211 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2212 while (item != -1) {
2215 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2218 CmdMark(wxTreeItemId(), items, num);
2222 wxListEvent listevt;
2224 OnListChanged(listevt);
2231 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2236 long item = event.GetIndex();
2237 // long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2239 wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2240 wxString name = itemdata->GetName();
2245 #if wxCHECK_VERSION(2, 6, 0)
2246 wxTreeItemIdValue cookie;
2251 if (IsPathSeparator(name.GetChar(name.Length()-1))) {
2252 wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2254 while (currentChild.IsOk()) {
2255 wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2256 if (name2 == name) {
2257 //tree->UnselectAll();
2259 tree->Expand(currentTreeItem);
2260 tree->SelectItem(currentChild);
2264 currentChild = tree->GetNextChild(currentTreeItem, cookie);
2271 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2276 listadd->Enable(false);
2277 listremove->Enable(false);
2279 bool marked = false;
2280 bool unmarked = false;
2282 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2283 while (item != -1) {
2284 switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2297 // Should never happen
2299 if (marked && unmarked) break;
2300 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2303 listadd->Enable(unmarked);
2304 listremove->Enable(marked);
2307 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2314 long* items = new long[list->GetSelectedItemCount()];
2318 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2319 while (item != -1) {
2322 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2325 CmdMark(wxTreeItemId(), items, num, 1);
2332 listadd->Enable(false);
2333 listremove->Enable(true);
2336 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2343 long* items = new long[list->GetSelectedItemCount()];
2347 long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2348 while (item != -1) {
2351 item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2354 CmdMark(wxTreeItemId(), items, num, 0);
2361 listadd->Enable(true);
2362 listremove->Enable(false);
2365 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2375 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2376 if (status == entered) {
2377 if (event.GetId() == ConfigJobName) {
2382 UpdateFirstConfig();
2385 else if ((event.GetId() == ConfigClient) || (event.GetId() == ConfigFileset)) {
2390 configPanel->Enable(false);
2392 configPanel->Enable(true);
2395 cfgUpdated = cfgUpdated | (1 << event.GetId());
2397 else if (status == configuring) {
2398 restorePanel->EnableApply(true);
2399 cfgUpdated = cfgUpdated | (1 << event.GetId());
2403 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2404 if (status != configuring) return;
2413 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2414 if (status != configuring) return;
2420 if (cfgUpdated == 0) {
2421 restorePanel->EnableApply(false);
2426 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2427 if (status != configuring) return;