]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Tweak bat debug code
[bacula/bacula] / bacula / src / qt-console / restore / restore.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28  
29 /*
30  *  Restore Class 
31  *
32  *   Kern Sibbald, February MMVII
33  *
34  */ 
35
36 #include "bat.h"
37 #include "restore.h"
38
39 static const int dbglvl = 100;
40
41 restorePage::restorePage(int conn)
42 {
43    Dmsg1(dbglvl, "Construcing restorePage Instance connection %i\n", conn);
44    m_conn = conn;
45    QStringList titles;
46
47    setupUi(this);
48    m_name = tr("Restore Select");
49    pgInitialize();
50    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
51    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
52
53    m_console->notify(m_conn, false);          /* this should already be off */
54    m_closeable = true;
55
56    connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), 
57            this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
58    connect(directoryWidget, SIGNAL(
59            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
60            this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
61    connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
62    connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
63    connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
64    connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
65    connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
66
67    fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
68    fileWidget->addAction(actionMark);
69    fileWidget->addAction(actionUnMark);
70    connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
71    connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
72
73    setFont(m_console->get_font());
74    m_console->displayToPrompt(m_conn);
75
76    titles << tr("Mark") << tr("File") << tr("Mode") << tr("User") 
77           << tr("Group") << tr("Size") << tr("Date");
78    fileWidget->setHeaderLabels(titles);
79
80    get_cwd();
81
82    readSettings();
83    /* wait was entered from pre-restore 
84     * will exit, but will reenter in fillDirectory */
85    mainWin->waitExit();
86    fillDirectory();
87    dockPage();
88    setCurrent();
89    this->show();
90    if (mainWin->m_miscDebug) Pmsg0(000, "Leave restorePage\n");
91 }
92
93 restorePage::~restorePage()
94 {
95    writeSettings();
96 }
97
98 /*
99  * Fill the fileWidget box with the contents of the current directory
100  */
101 void restorePage::fillDirectory()
102 {
103    mainWin->waitEnter();
104    char modes[20], user[20], group[20], size[20], date[30];
105    char marked[10];
106    int pnl, fnl;
107    POOLMEM *file = get_pool_memory(PM_FNAME);
108    POOLMEM *path = get_pool_memory(PM_FNAME);
109
110    fileWidget->clear();
111    m_console->write_dir(m_conn, "dir", false);
112    QList<QTreeWidgetItem *> treeItemList;
113    QStringList item;
114    m_rx.setPattern("has no children\\.$");
115    bool first = true;
116    while (m_console->read(m_conn) > 0) {
117       char *p = m_console->msg(m_conn);
118       char *l;
119       strip_trailing_junk(p);
120       if (*p == '$' || !*p) { continue; }
121       if (first) {
122          if (m_rx.indexIn(QString(p)) != -1) { continue; }
123          first = false;
124       }
125       l = p;
126       skip_nonspaces(&p);             /* permissions */
127       *p++ = 0;
128       bstrncpy(modes, l, sizeof(modes));
129       skip_spaces(&p);
130       skip_nonspaces(&p);             /* link count */
131       *p++ = 0;
132       skip_spaces(&p);
133       l = p;
134       skip_nonspaces(&p);             /* user */
135       *p++ = 0;
136       skip_spaces(&p);
137       bstrncpy(user, l, sizeof(user));
138       l = p;
139       skip_nonspaces(&p);             /* group */
140       *p++ = 0;
141       bstrncpy(group, l, sizeof(group));
142       skip_spaces(&p);
143       l = p;
144       skip_nonspaces(&p);             /* size */
145       *p++ = 0;
146       bstrncpy(size, l, sizeof(size));
147       skip_spaces(&p);
148       l = p;
149       skip_nonspaces(&p);             /* date/time */
150       skip_spaces(&p);
151       skip_nonspaces(&p);
152       *p++ = 0;
153       bstrncpy(date, l, sizeof(date));
154       skip_spaces(&p);
155       if (*p == '*') {
156          bstrncpy(marked, "*", sizeof(marked));
157          p++;
158       } else {
159          bstrncpy(marked, " ", sizeof(marked));
160       }
161       split_path_and_filename(p, &path, &pnl, &file, &fnl);
162       item.clear();
163       item << "" << file << modes << user << group << size << date;
164       if (item[1].endsWith("/")) {
165          addDirectory(item[1]);
166       }
167       QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
168       ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
169       if (strcmp(marked, "*") == 0) {
170          ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
171          ti->setData(0, Qt::UserRole, true);
172       } else {
173          ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
174          ti->setData(0, Qt::UserRole, false);
175       }
176       treeItemList.append(ti);
177    }
178    fileWidget->clear();
179    fileWidget->insertTopLevelItems(0, treeItemList);
180    for (int i=0; i<7; i++) {
181       fileWidget->resizeColumnToContents(i);
182    }
183
184    free_pool_memory(file);
185    free_pool_memory(path);
186    mainWin->waitExit();
187 }
188
189 /*
190  * Function called from fill directory when a directory is found to see if this
191  * directory exists in the directory pane and then add it to the directory pane
192  */
193 void restorePage::addDirectory(QString &newdirr)
194 {
195    QString newdir = newdirr;
196    QString fullpath = m_cwd + newdirr;
197    bool ok = true;
198    bool windrive = false;
199
200    if (mainWin->m_miscDebug) {
201       QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
202                     .arg(m_cwd)
203                     .arg(newdir)
204                     .arg(fullpath);
205       Pmsg0(dbglvl, msg.toUtf8().data());
206    }
207
208    if (isWin32Path(newdir)) {
209       /* this is a windows drive */
210       if (mainWin->m_miscDebug) {
211          Pmsg0(dbglvl, "Found windows drive\n");
212       }
213       windrive = true;
214    }
215    
216    if (windrive) {
217       if (fullpath.left(1) == "/") {
218          fullpath.replace(0, 1, "");           /* strip leading / */
219       }
220       /* If drive and not already in add it */
221       if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
222          QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
223          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
224          item->setText(0, fullpath.toUtf8().data());
225          if (mainWin->m_miscDebug) {
226             Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
227          }
228          m_dirPaths.insert(fullpath, item);
229          m_dirTreeItems.insert(item, fullpath);
230          directoryWidget->setCurrentItem(NULL);
231       }
232    } else {
233       // Unix add / first if not already there 
234       if (m_dirPaths.empty()) {
235          QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
236          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
237             
238          QString text("/");
239          item->setText(0, text.toUtf8().data());
240          if (mainWin->m_miscDebug) {
241             Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
242          }
243          m_dirPaths.insert(text, item);
244          m_dirTreeItems.insert(item, text);
245       }
246    }
247  
248    /* Does it already exist ?? */
249    if (!m_dirPaths.contains(fullpath)) {
250       QTreeWidgetItem *item = NULL;
251       if (windrive) {
252          /* this is the base widget */
253          item = new QTreeWidgetItem(directoryWidget);
254          item->setText(0, fullpath.toUtf8().data());
255          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
256       } else {
257          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
258          if (parent) {
259             /* new directories to add */
260             item = new QTreeWidgetItem(parent);
261             item->setText(0, newdir.toUtf8().data());
262             item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
263             directoryWidget->expandItem(parent);
264          } else {
265             ok = false;
266             if (mainWin->m_miscDebug) {
267                QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
268                     .arg(m_cwd)
269                     .arg(newdir);
270                Pmsg0(dbglvl, msg.toUtf8().data());
271             }
272          }
273       }
274       /* insert into both forward and reverse hash */
275       if (ok) {
276          if (mainWin->m_miscDebug) {
277             Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
278          }
279          m_dirPaths.insert(fullpath, item);
280          m_dirTreeItems.insert(item, fullpath);
281       }
282    }
283 }
284
285 /*
286  * Executed when the tree item in the directory pane is changed.  This will
287  * allow us to populate the file pane and make this the cwd.
288  */
289 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
290                                          QTreeWidgetItem * /*previousitem*/)
291 {
292    QString fullpath = m_dirTreeItems.value(currentitem);
293    statusLine->setText("");
294    if (fullpath != "") {
295       cwd(fullpath.toUtf8().data());
296       fillDirectory();
297    }
298 }
299
300 void restorePage::okButtonPushed()
301 {
302    this->hide();
303    m_console->write(m_conn, "done");
304    m_console->notify(m_conn, true);
305    setConsoleCurrent();
306    closeStackPage();
307    mainWin->resetFocus();
308 }
309
310
311 void restorePage::cancelButtonPushed()
312 {
313    this->hide();
314    m_console->write(m_conn, "quit");
315    m_console->displayToPrompt(m_conn);
316    mainWin->set_status(tr("Canceled"));
317    closeStackPage();
318    m_console->notify(m_conn, true);
319    mainWin->resetFocus();
320 }
321
322 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
323 {
324    char cmd[1000];
325    statusLine->setText("");
326    if (column == 0) {                 /* mark/unmark */
327       mainWin->waitEnter();
328       if (item->data(0, Qt::UserRole).toBool()) {
329          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
330          item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
331          item->setData(0, Qt::UserRole, false);
332       } else {
333          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
334          item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
335          item->setData(0, Qt::UserRole, true);
336       }
337       m_console->write_dir(m_conn, cmd, false);
338       if (m_console->read(m_conn) > 0) {
339          strip_trailing_junk(m_console->msg(m_conn));
340          statusLine->setText(m_console->msg(m_conn));
341       }
342       m_console->displayToPrompt(m_conn);
343       mainWin->waitExit();
344       return;
345    }    
346    /* 
347     * Double clicking other than column 0 means to decend into
348     *  the directory -- or nothing if it is not a directory.
349     */
350    if (item->text(1).endsWith("/")) {
351       QString fullpath = m_cwd + item->text(1);
352       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
353       if (item) {
354          directoryWidget->setCurrentItem(item);
355       } else {
356          QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
357               .arg(column,10)
358               .arg(fullpath);
359          Pmsg0(dbglvl, msg.toUtf8().data());
360       }
361    }
362 }
363
364 /*
365  * If up button pushed, making the parent tree widget current will call fill
366  * directory.
367  */
368 void restorePage::upButtonPushed()
369 {
370    cwd("..");
371    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
372    if (item) {
373       directoryWidget->setCurrentItem(item);
374    }
375    statusLine->setText("");
376 }
377
378 /*
379  * Mark selected items
380  */
381 void restorePage::markButtonPushed()
382 {
383    mainWin->waitEnter();
384    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
385    QTreeWidgetItem *item;
386    char cmd[1000];
387    int count = 0;
388    statusLine->setText("");
389    foreach (item, treeItemList) {
390       count++;
391       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
392       item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
393       m_console->write_dir(m_conn, cmd, false);
394       if (m_console->read(m_conn) > 0) {
395          strip_trailing_junk(m_console->msg(m_conn));
396          statusLine->setText(m_console->msg(m_conn));
397       }
398       Dmsg1(dbglvl, "cmd=%s\n", cmd);
399       m_console->discardToPrompt(m_conn);
400    }
401    if (count == 0) {
402       mainWin->set_status("Nothing selected, nothing done");
403       statusLine->setText("Nothing selected, nothing done");
404    }
405    mainWin->waitExit();
406 }
407
408 /*
409  * Unmark selected items
410  */
411 void restorePage::unmarkButtonPushed()
412 {
413    mainWin->waitEnter();
414    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
415    QTreeWidgetItem *item;
416    char cmd[1000];
417    int count = 0;
418    statusLine->setText("");
419    foreach (item, treeItemList) {
420       count++;
421       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
422       item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
423       m_console->write_dir(m_conn, cmd, false);
424       if (m_console->read(m_conn) > 0) {
425          strip_trailing_junk(m_console->msg(m_conn));
426          statusLine->setText(m_console->msg(m_conn));
427       }
428       Dmsg1(dbglvl, "cmd=%s\n", cmd);
429       m_console->discardToPrompt(m_conn);
430    }
431    if (count == 0) {
432       mainWin->set_status(tr("Nothing selected, nothing done"));
433       statusLine->setText(tr("Nothing selected, nothing done"));
434    }
435    mainWin->waitExit();
436 }
437
438 /*
439  * Change current working directory 
440  */
441 bool restorePage::cwd(const char *dir)
442 {
443    int stat;
444    char cd_cmd[MAXSTRING];
445
446    mainWin->waitEnter();
447    statusLine->setText("");
448    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
449    Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
450    m_console->write_dir(m_conn, cd_cmd, false);
451    lineEdit->clear();
452    if ((stat = m_console->read(m_conn)) > 0) {
453       m_cwd = m_console->msg(m_conn);
454       lineEdit->insert(m_cwd);
455       Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
456    } else {
457       Dmsg1(dbglvl, "stat=%d\n", stat);
458       QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
459    }
460    m_console->discardToPrompt(m_conn);
461    mainWin->waitExit();
462    return true;  /* ***FIXME*** return real status */
463 }
464
465 /*
466  * Return cwd when in tree restore mode 
467  */
468 char *restorePage::get_cwd()
469 {
470    int stat;
471    mainWin->waitEnter();
472    m_console->write_dir(m_conn, ".pwd", false);
473    Dmsg0(dbglvl, "send: .pwd\n");
474    if ((stat = m_console->read(m_conn)) > 0) {
475       m_cwd = m_console->msg(m_conn);
476       Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
477    } else {
478       Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
479       QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
480    }
481    m_console->discardToPrompt(m_conn); 
482    mainWin->waitExit();
483    return m_cwd.toUtf8().data();
484 }
485
486 /*
487  * Save user settings associated with this page
488  */
489 void restorePage::writeSettings()
490 {
491    QSettings settings(m_console->m_dir->name(), "bat");
492    settings.beginGroup("RestorePage");
493    settings.setValue(m_splitText, splitter->saveState());
494    settings.endGroup();
495 }
496
497 /*
498  * Read and restore user settings associated with this page
499  */
500 void restorePage::readSettings()
501 {
502    m_splitText = "splitterSizes_2";
503    QSettings settings(m_console->m_dir->name(), "bat");
504    settings.beginGroup("RestorePage");
505    if (settings.contains(m_splitText)) { 
506       splitter->restoreState(settings.value(m_splitText).toByteArray());
507    }
508    settings.endGroup();
509 }