]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
kes Fix listing performance problems in bat. Pointed out by
[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    if (fullpath != ""){
262       cwd(fullpath.toUtf8().data());
263       fillDirectory();
264    }
265 }
266
267 void restorePage::okButtonPushed()
268 {
269    printf("In restorePage::okButtonPushed\n");
270    this->hide();
271    m_console->write("done");
272    m_console->notify(true);
273    setConsoleCurrent();
274    closeStackPage();
275    mainWin->resetFocus();
276 }
277
278
279 void restorePage::cancelButtonPushed()
280 {
281    this->hide();
282    m_console->write("quit");
283    m_console->displayToPrompt();
284    mainWin->set_status("Canceled");
285    closeStackPage();
286    m_console->notify(true);
287    mainWin->resetFocus();
288 }
289
290 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
291 {
292    char cmd[1000];
293    if (column == 0) {                 /* mark/unmark */
294       if (item->data(0, Qt::UserRole).toBool()) {
295          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
296          item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
297          item->setData(0, Qt::UserRole, false);
298       } else {
299          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
300          item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
301          item->setData(0, Qt::UserRole, true);
302       }
303       m_console->write_dir(cmd);
304       if (m_console->read() > 0) {
305          strip_trailing_junk(m_console->msg());
306          statusLine->setText(m_console->msg());
307       }
308       m_console->displayToPrompt();
309       return;
310    }    
311    /* 
312     * Double clicking other than column 0 means to decend into
313     *  the directory -- or nothing if it is not a directory.
314     */
315    if (item->text(1).endsWith("/")) {
316       QString fullpath = m_cwd + item->text(1);
317       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
318       if (item) {
319          directoryWidget->setCurrentItem(item);
320       } else {
321          QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
322               .arg(column,10)
323               .arg(fullpath);
324          Pmsg0(000, msg.toUtf8().data());
325       }
326    }
327 }
328
329 /*
330  * If up button pushed, making the parent tree widget current will call fill
331  * directory.
332  */
333 void restorePage::upButtonPushed()
334 {
335    cwd("..");
336    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
337    if (item) {
338       directoryWidget->setCurrentItem(item);
339    }
340 }
341
342 /*
343  * Mark selected items
344  */
345 void restorePage::markButtonPushed()
346 {
347    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
348    QTreeWidgetItem *item;
349    char cmd[1000];
350    foreach (item, treeItemList) {
351       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
352       item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
353       m_console->write_dir(cmd);
354       if (m_console->read() > 0) {
355          strip_trailing_junk(m_console->msg());
356          statusLine->setText(m_console->msg());
357       }
358       Dmsg1(100, "cmd=%s\n", cmd);
359       m_console->discardToPrompt();
360    }
361 }
362
363 /*
364  * Unmark selected items
365  */
366 void restorePage::unmarkButtonPushed()
367 {
368    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
369    QTreeWidgetItem *item;
370    char cmd[1000];
371    foreach (item, treeItemList) {
372       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
373       item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
374       m_console->write_dir(cmd);
375       if (m_console->read() > 0) {
376          strip_trailing_junk(m_console->msg());
377          statusLine->setText(m_console->msg());
378       }
379       Dmsg1(100, "cmd=%s\n", cmd);
380       m_console->discardToPrompt();
381    }
382 }
383
384 /*
385  * Change current working directory 
386  */
387 bool restorePage::cwd(const char *dir)
388 {
389    int stat;
390    char cd_cmd[MAXSTRING];
391
392    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
393    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
394    m_console->write_dir(cd_cmd);
395    lineEdit->clear();
396    if ((stat = m_console->read()) > 0) {
397       m_cwd = m_console->msg();
398       lineEdit->insert(m_cwd);
399       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
400    } else {
401       Dmsg1(000, "stat=%d\n", stat);
402       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
403    }
404    m_console->discardToPrompt();
405    return true;  /* ***FIXME*** return real status */
406 }
407
408 /*
409  * Return cwd when in tree restore mode 
410  */
411 char *restorePage::get_cwd()
412 {
413    int stat;
414    m_console->write_dir(".pwd");
415    Dmsg0(100, "send: .pwd\n");
416    if ((stat = m_console->read()) > 0) {
417       m_cwd = m_console->msg();
418       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
419    } else {
420       Dmsg1(000, "Something went wrong read stat=%d\n", stat);
421       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
422    }
423    m_console->discardToPrompt(); 
424    return m_cwd.toUtf8().data();
425 }
426
427 /*
428  * Save user settings associated with this page
429  */
430 void restorePage::writeSettings()
431 {
432    QSettings settings(m_console->m_dir->name(), "bat");
433    settings.beginGroup("RestorePage");
434    settings.setValue("splitterSizes", splitter->saveState());
435    settings.endGroup();
436 }
437
438 /*
439  * Read and restore user settings associated with this page
440  */
441 void restorePage::readSettings()
442 {
443    QSettings settings(m_console->m_dir->name(), "bat");
444    settings.beginGroup("RestorePage");
445    splitter->restoreState(settings.value("splitterSizes").toByteArray());
446    settings.endGroup();
447 }