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