]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
A bug was introduced in with commit 5727. Restoretree and restore were
[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    /* add unix '/' directory first */
197    if (m_dirPaths.empty()) {
198       if (isWin32Path(newdir)) {
199          /* this is a windows drive */
200          if (mainWin->m_miscDebug) {
201             Pmsg0(000, "Need to do windows \"letter\":/\n");
202          }
203          fullpath.replace(0,1,"");
204          windrive = true;
205       } else {
206          QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
207          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
208          
209          QString text("/");
210          item->setText(0, text.toUtf8().data());
211          if (mainWin->m_miscDebug) {
212             Pmsg1(000, "Pre Inserting %s\n",text.toUtf8().data());
213          }
214          m_dirPaths.insert(text, item);
215          m_dirTreeItems.insert(item, text);
216       }
217    }
218
219  
220    /* is it already existent ?? */
221    if (!m_dirPaths.contains(fullpath)) {
222       QTreeWidgetItem *item = NULL;
223       if (windrive) {
224          /* this is the base widget */
225          item = new QTreeWidgetItem(directoryWidget);
226          item->setText(0, fullpath.toUtf8().data());
227          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
228       } else {
229          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
230          if (parent) {
231             /* new directories to add */
232             item = new QTreeWidgetItem(parent);
233             item->setText(0, newdir.toUtf8().data());
234             item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
235             directoryWidget->expandItem(parent);
236          } else {
237             ok = false;
238             if (mainWin->m_miscDebug) {
239                QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
240                     .arg(m_cwd)
241                     .arg(newdir);
242                Pmsg0(000, msg.toUtf8().data());
243             }
244          }
245       }
246       /* insert into both forward and reverse hash */
247       if (ok) {
248          if (mainWin->m_miscDebug) {
249             Pmsg1(000, "Inserting %s\n",fullpath.toUtf8().data());
250          }
251          m_dirPaths.insert(fullpath, item);
252          m_dirTreeItems.insert(item, fullpath);
253       }
254    }
255 }
256
257 /*
258  * Executed when the tree item in the directory pane is changed.  This will
259  * allow us to populate the file pane and make this the cwd.
260  */
261 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
262                                          QTreeWidgetItem * /*previousitem*/)
263 {
264    QString fullpath = m_dirTreeItems.value(currentitem);
265    statusLine->setText("");
266    if (fullpath != ""){
267       cwd(fullpath.toUtf8().data());
268       fillDirectory();
269    }
270 }
271
272 void restorePage::okButtonPushed()
273 {
274 // printf("In restorePage::okButtonPushed\n");
275    this->hide();
276    m_console->write("done");
277    m_console->notify(true);
278    setConsoleCurrent();
279    closeStackPage();
280    mainWin->resetFocus();
281 }
282
283
284 void restorePage::cancelButtonPushed()
285 {
286    this->hide();
287    m_console->write("quit");
288    m_console->displayToPrompt();
289    mainWin->set_status(tr("Canceled"));
290    closeStackPage();
291    m_console->notify(true);
292    mainWin->resetFocus();
293 }
294
295 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
296 {
297    char cmd[1000];
298    statusLine->setText("");
299    if (column == 0) {                 /* mark/unmark */
300       if (item->data(0, Qt::UserRole).toBool()) {
301          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
302          item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
303          item->setData(0, Qt::UserRole, false);
304       } else {
305          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
306          item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
307          item->setData(0, Qt::UserRole, true);
308       }
309       m_console->write_dir(cmd);
310       if (m_console->read() > 0) {
311          strip_trailing_junk(m_console->msg());
312          statusLine->setText(m_console->msg());
313       }
314       m_console->displayToPrompt();
315       return;
316    }    
317    /* 
318     * Double clicking other than column 0 means to decend into
319     *  the directory -- or nothing if it is not a directory.
320     */
321    if (item->text(1).endsWith("/")) {
322       QString fullpath = m_cwd + item->text(1);
323       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
324       if (item) {
325          directoryWidget->setCurrentItem(item);
326       } else {
327          QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
328               .arg(column,10)
329               .arg(fullpath);
330          Pmsg0(000, msg.toUtf8().data());
331       }
332    }
333 }
334
335 /*
336  * If up button pushed, making the parent tree widget current will call fill
337  * directory.
338  */
339 void restorePage::upButtonPushed()
340 {
341    cwd("..");
342    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
343    if (item) {
344       directoryWidget->setCurrentItem(item);
345    }
346    statusLine->setText("");
347 }
348
349 /*
350  * Mark selected items
351  */
352 void restorePage::markButtonPushed()
353 {
354    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
355    QTreeWidgetItem *item;
356    char cmd[1000];
357    int count = 0;
358    statusLine->setText("");
359    foreach (item, treeItemList) {
360       count++;
361       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
362       item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
363       m_console->write_dir(cmd);
364       if (m_console->read() > 0) {
365          strip_trailing_junk(m_console->msg());
366          statusLine->setText(m_console->msg());
367       }
368       Dmsg1(100, "cmd=%s\n", cmd);
369       m_console->discardToPrompt();
370    }
371    if (count == 0) {
372       mainWin->set_status("Nothing selected, nothing done");
373       statusLine->setText("Nothing selected, nothing done");
374    }
375       
376 }
377
378 /*
379  * Unmark selected items
380  */
381 void restorePage::unmarkButtonPushed()
382 {
383    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
384    QTreeWidgetItem *item;
385    char cmd[1000];
386    int count = 0;
387    statusLine->setText("");
388    foreach (item, treeItemList) {
389       count++;
390       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
391       item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
392       m_console->write_dir(cmd);
393       if (m_console->read() > 0) {
394          strip_trailing_junk(m_console->msg());
395          statusLine->setText(m_console->msg());
396       }
397       Dmsg1(100, "cmd=%s\n", cmd);
398       m_console->discardToPrompt();
399    }
400    if (count == 0) {
401       mainWin->set_status(tr("Nothing selected, nothing done"));
402       statusLine->setText(tr("Nothing selected, nothing done"));
403    }
404
405 }
406
407 /*
408  * Change current working directory 
409  */
410 bool restorePage::cwd(const char *dir)
411 {
412    int stat;
413    char cd_cmd[MAXSTRING];
414
415    statusLine->setText("");
416    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
417    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
418    m_console->write_dir(cd_cmd);
419    lineEdit->clear();
420    if ((stat = m_console->read()) > 0) {
421       m_cwd = m_console->msg();
422       lineEdit->insert(m_cwd);
423       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
424    } else {
425       Dmsg1(000, "stat=%d\n", stat);
426       QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
427    }
428    m_console->discardToPrompt();
429    return true;  /* ***FIXME*** return real status */
430 }
431
432 /*
433  * Return cwd when in tree restore mode 
434  */
435 char *restorePage::get_cwd()
436 {
437    int stat;
438    m_console->write_dir(".pwd");
439    Dmsg0(100, "send: .pwd\n");
440    if ((stat = m_console->read()) > 0) {
441       m_cwd = m_console->msg();
442       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
443    } else {
444       Dmsg1(000, "Something went wrong read stat=%d\n", stat);
445       QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
446    }
447    m_console->discardToPrompt(); 
448    return m_cwd.toUtf8().data();
449 }
450
451 /*
452  * Save user settings associated with this page
453  */
454 void restorePage::writeSettings()
455 {
456    QSettings settings(m_console->m_dir->name(), "bat");
457    settings.beginGroup("RestorePage");
458    settings.setValue("splitterSizes", splitter->saveState());
459    settings.endGroup();
460 }
461
462 /*
463  * Read and restore user settings associated with this page
464  */
465 void restorePage::readSettings()
466 {
467    QSettings settings(m_console->m_dir->name(), "bat");
468    settings.beginGroup("RestorePage");
469    splitter->restoreState(settings.value("splitterSizes").toByteArray());
470    settings.endGroup();
471 }