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