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