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