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