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