]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Convert to pure GPL v2 license.
[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    QRegExp regex("^/[a-z]:/$");
185    bool ok = true;
186    bool windrive = false;
187
188    if (mainWin->m_miscDebug) {
189       QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
190                     .arg(m_cwd)
191                     .arg(newdir);
192       Pmsg0(000, msg.toUtf8().data());
193    }
194
195    /* add unix '/' directory first */
196    if (m_dirPaths.empty() && (regex.indexIn(fullpath,0) == -1)) {
197       QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
198       item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
199       
200       QString text("/");
201       item->setText(0, text.toUtf8().data());
202       if (mainWin->m_miscDebug) {
203          Pmsg1(000, "Pre Inserting %s\n",text.toUtf8().data());
204       }
205       m_dirPaths.insert(text, item);
206       m_dirTreeItems.insert(item, text);
207    }
208
209    if (regex.indexIn(fullpath,0) == 0) {
210       /* this is a windows drive */
211       if (mainWin->m_miscDebug) {
212          Pmsg0(000, "Need to do windows \"letter\":/\n");
213       }
214       fullpath.replace(0,1,"");
215       windrive = true;
216    }
217  
218    /* is it already existent ?? */
219    if (!m_dirPaths.contains(fullpath)) {
220       QTreeWidgetItem *item = NULL;
221       if (windrive) {
222          /* this is the base widget */
223          item = new QTreeWidgetItem(directoryWidget);
224          item->setText(0, fullpath.toUtf8().data());
225          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
226       } else {
227          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
228          if (parent) {
229             /* new directories to add */
230             item = new QTreeWidgetItem(parent);
231             item->setText(0, newdir.toUtf8().data());
232             item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
233             directoryWidget->expandItem(parent);
234          } else {
235             ok = false;
236             if (mainWin->m_miscDebug) {
237                QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
238                     .arg(m_cwd)
239                     .arg(newdir);
240                Pmsg0(000, msg.toUtf8().data());
241             }
242          }
243       }
244       /* insert into both forward and reverse hash */
245       if (ok) {
246          if (mainWin->m_miscDebug) {
247             Pmsg1(000, "Inserting %s\n",fullpath.toUtf8().data());
248          }
249          m_dirPaths.insert(fullpath, item);
250          m_dirTreeItems.insert(item, fullpath);
251       }
252    }
253 }
254
255 /*
256  * Executed when the tree item in the directory pane is changed.  This will
257  * allow us to populate the file pane and make this the cwd.
258  */
259 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
260                                          QTreeWidgetItem * /*previousitem*/)
261 {
262    QString fullpath = m_dirTreeItems.value(currentitem);
263    if (fullpath != ""){
264       cwd(fullpath.toUtf8().data());
265       fillDirectory();
266    }
267 }
268
269 void restorePage::okButtonPushed()
270 {
271    printf("In restorePage::okButtonPushed\n");
272    this->hide();
273    m_console->write("done");
274    m_console->notify(true);
275    setConsoleCurrent();
276    closeStackPage();
277    mainWin->resetFocus();
278 }
279
280
281 void restorePage::cancelButtonPushed()
282 {
283    this->hide();
284    m_console->write("quit");
285    m_console->displayToPrompt();
286    mainWin->set_status("Canceled");
287    closeStackPage();
288    m_console->notify(true);
289    mainWin->resetFocus();
290 }
291
292 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
293 {
294    char cmd[1000];
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       /* check for fullpath = "/c:/" */
320       QRegExp regex("^/[a-z]:/");
321       if (regex.indexIn(fullpath,0) == 0)  /* remove leading '/' */
322          fullpath.replace(0,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 }
347
348 /*
349  * Mark selected items
350  */
351 void restorePage::markButtonPushed()
352 {
353    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
354    QTreeWidgetItem *item;
355    char cmd[1000];
356    foreach (item, treeItemList) {
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 }
368
369 /*
370  * Unmark selected items
371  */
372 void restorePage::unmarkButtonPushed()
373 {
374    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
375    QTreeWidgetItem *item;
376    char cmd[1000];
377    foreach (item, treeItemList) {
378       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
379       item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
380       m_console->write_dir(cmd);
381       if (m_console->read() > 0) {
382          strip_trailing_junk(m_console->msg());
383          statusLine->setText(m_console->msg());
384       }
385       Dmsg1(100, "cmd=%s\n", cmd);
386       m_console->discardToPrompt();
387    }
388 }
389
390 /*
391  * Change current working directory 
392  */
393 bool restorePage::cwd(const char *dir)
394 {
395    int stat;
396    char cd_cmd[MAXSTRING];
397
398    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
399    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
400    m_console->write_dir(cd_cmd);
401    lineEdit->clear();
402    if ((stat = m_console->read()) > 0) {
403       m_cwd = m_console->msg();
404       lineEdit->insert(m_cwd);
405       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
406    } else {
407       Dmsg1(000, "stat=%d\n", stat);
408       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
409    }
410    m_console->discardToPrompt();
411    return true;  /* ***FIXME*** return real status */
412 }
413
414 /*
415  * Return cwd when in tree restore mode 
416  */
417 char *restorePage::get_cwd()
418 {
419    int stat;
420    m_console->write_dir(".pwd");
421    Dmsg0(100, "send: .pwd\n");
422    if ((stat = m_console->read()) > 0) {
423       m_cwd = m_console->msg();
424       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
425    } else {
426       Dmsg1(000, "Something went wrong read stat=%d\n", stat);
427       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
428    }
429    m_console->discardToPrompt(); 
430    return m_cwd.toUtf8().data();
431 }
432
433 /*
434  * Save user settings associated with this page
435  */
436 void restorePage::writeSettings()
437 {
438    QSettings settings(m_console->m_dir->name(), "bat");
439    settings.beginGroup("RestorePage");
440    settings.setValue("splitterSizes", splitter->saveState());
441    settings.endGroup();
442 }
443
444 /*
445  * Read and restore user settings associated with this page
446  */
447 void restorePage::readSettings()
448 {
449    QSettings settings(m_console->m_dir->name(), "bat");
450    settings.beginGroup("RestorePage");
451    splitter->restoreState(settings.value("splitterSizes").toByteArray());
452    settings.endGroup();
453 }