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