]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Working directory pane in restore. Will get this into the stack next.
[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 restoreDialog::restoreDialog(Console *console )
42 {
43    QStringList titles;
44
45    m_console = console;
46    m_console->notify(false);          /* this should already be off */
47
48    setupUi(this);
49    connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), 
50            this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
51    connect(directoryWidget, SIGNAL(
52            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
53            this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
54    connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
55    connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
56    connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
57    setFont(m_console->get_font());
58    m_console->displayToPrompt();
59
60
61    titles << "Mark" << "File" << "Mode" << "User" << "Group" << "Size" << "Date";
62    fileWidget->setHeaderLabels(titles);
63
64    get_cwd();
65    fillDirectory();
66    this->show();
67 }
68
69 /*
70  * Fill the fileWidget box with the contents of the current directory
71  */
72 void restoreDialog::fillDirectory()
73 {
74    char modes[20], user[20], group[20], size[20], date[30];
75    char marked[10];
76    int pnl, fnl;
77    POOLMEM *file = get_pool_memory(PM_FNAME);
78    POOLMEM *path = get_pool_memory(PM_FNAME);
79
80    fileWidget->clear();
81    m_console->write_dir("dir");
82    QList<QTreeWidgetItem *> treeItemList;
83    QStringList item;
84    while (m_console->read() > 0) {
85       char *p = m_console->msg();
86       char *l;
87       strip_trailing_junk(p);
88       if (*p == '$' || !*p) {
89          continue;
90       }
91       l = p;
92       skip_nonspaces(&p);             /* permissions */
93       *p++ = 0;
94       bstrncpy(modes, l, sizeof(modes));
95       skip_spaces(&p);
96       skip_nonspaces(&p);             /* link count */
97       *p++ = 0;
98       skip_spaces(&p);
99       l = p;
100       skip_nonspaces(&p);             /* user */
101       *p++ = 0;
102       skip_spaces(&p);
103       bstrncpy(user, l, sizeof(user));
104       l = p;
105       skip_nonspaces(&p);             /* group */
106       *p++ = 0;
107       bstrncpy(group, l, sizeof(group));
108       skip_spaces(&p);
109       l = p;
110       skip_nonspaces(&p);             /* size */
111       *p++ = 0;
112       bstrncpy(size, l, sizeof(size));
113       skip_spaces(&p);
114       l = p;
115       skip_nonspaces(&p);             /* date/time */
116       skip_spaces(&p);
117       skip_nonspaces(&p);
118       *p++ = 0;
119       bstrncpy(date, l, sizeof(date));
120       skip_spaces(&p);
121       if (*p == '*') {
122          bstrncpy(marked, "*", sizeof(marked));
123          p++;
124       } else {
125          bstrncpy(marked, " ", sizeof(marked));
126       }
127       split_path_and_filename(p, &path, &pnl, &file, &fnl);
128       item.clear();
129       item << marked << file << modes << user << group << size << date;
130       if (item[1].endsWith("/")) {
131          addDirectory(item[1]);
132        }
133       QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
134       ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
135       treeItemList.append(ti);
136    }
137    fileWidget->clear();
138    fileWidget->insertTopLevelItems(0, treeItemList);
139    for (int i=0; i<7; i++) {
140       fileWidget->resizeColumnToContents(i);
141    }
142
143    free_pool_memory(file);
144    free_pool_memory(path);
145 }
146
147 /*
148  * Function called from fill directory when a directory is found to see if this
149  * directory exists in the directory pane and then add it to the directory pane
150  */
151 void restoreDialog::addDirectory(QString &newdir)
152 {
153    QString fullpath ;
154
155    /* if this is the base dir, strip off the leading "/" */
156    if (m_cwd == "/"){
157       fullpath = newdir;
158    } else {
159       fullpath = m_cwd + newdir;
160    }
161    /* is it already existent ?? */
162    if (!m_dirPaths.contains(fullpath)) {
163       QTreeWidgetItem *item = NULL;
164       if (m_dirPaths.empty()) {
165          /* this is the base widget */
166          item = new QTreeWidgetItem(directoryWidget);
167          item->setText(0, newdir.toUtf8().data());
168       } else {
169          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
170          if (parent) {
171             /* new directories to add */
172             item = new QTreeWidgetItem(parent);
173             item->setText(0, newdir.toUtf8().data());
174             directoryWidget->expandItem(parent);
175          }
176       }
177       /* insert into both forward and reverse hash */
178       m_dirPaths.insert(fullpath, item);
179       m_dirTreeItems.insert(item, fullpath);
180    }
181 }
182
183 /*
184  * Executed when the tree item in the directory pane is changed.  This will
185  * allow us to populate the file pane and make this the cwd.
186  */
187 void restoreDialog::directoryItemChanged(QTreeWidgetItem *currentitem,
188                                          QTreeWidgetItem * /*previousitem*/)
189 {
190    QString fullpath = m_dirTreeItems.value(currentitem);
191    if (fullpath != ""){
192       cwd(fullpath.toUtf8().data());
193       fillDirectory();
194    }
195 }
196
197 void restoreDialog::accept()
198 {
199    this->hide();
200    m_console->write("done");
201    m_console->notify(true);
202    delete this;
203    mainWin->resetFocus();
204 }
205
206
207 void restoreDialog::reject()
208 {
209    this->hide();
210    m_console->write("quit");
211    mainWin->set_status("Canceled");
212    delete this;
213    m_console->notify(true);
214    mainWin->resetFocus();
215 }
216
217 void restoreDialog::fileDoubleClicked(QTreeWidgetItem *item, int column)
218 {
219    char cmd[1000];
220    if (column == 0) {                 /* mark/unmark */
221       if (item->text(0) == "*") {
222          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
223          item->setText(0, " ");
224       } else {
225          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
226          item->setText(0, "*");
227       }
228       m_console->write_dir(cmd);
229       if (m_console->read() > 0) {
230          strip_trailing_junk(m_console->msg());
231          statusLine->setText(m_console->msg());
232       }
233       m_console->displayToPrompt();
234       return;
235    }    
236    /* 
237     * Double clicking other than column 0 means to decend into
238     *  the directory -- or nothing if it is not a directory.
239     */
240    if (item->text(1).endsWith("/")) {
241       QString fullpath = m_cwd + item->text(1);
242       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
243       if (item) {
244          directoryWidget->setCurrentItem(item);
245       }
246    }
247 }
248
249 /*
250  * If up button pushed, making the parent tree widget current will call fill
251  * directory.
252  */
253 void restoreDialog::upButtonPushed()
254 {
255    cwd("..");
256    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
257    if (item) {
258       directoryWidget->setCurrentItem(item);
259    }
260 }
261
262 /*
263  * Mark selected items
264  */
265 void restoreDialog::markButtonPushed()
266 {
267    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
268    QTreeWidgetItem *item;
269    char cmd[1000];
270    foreach (item, treeItemList) {
271       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
272       item->setText(0, "*");
273       m_console->write_dir(cmd);
274       if (m_console->read() > 0) {
275          strip_trailing_junk(m_console->msg());
276          statusLine->setText(m_console->msg());
277       }
278       Dmsg1(100, "cmd=%s\n", cmd);
279       m_console->discardToPrompt();
280    }
281 }
282
283 /*
284  * Unmark selected items
285  */
286 void restoreDialog::unmarkButtonPushed()
287 {
288    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
289    QTreeWidgetItem *item;
290    char cmd[1000];
291    foreach (item, treeItemList) {
292       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
293       item->setText(0, " ");
294       m_console->write_dir(cmd);
295       if (m_console->read() > 0) {
296          strip_trailing_junk(m_console->msg());
297          statusLine->setText(m_console->msg());
298       }
299       Dmsg1(100, "cmd=%s\n", cmd);
300       m_console->discardToPrompt();
301    }
302 }
303
304 /*
305  * Change current working directory 
306  */
307 bool restoreDialog::cwd(const char *dir)
308 {
309    int stat;
310    char cd_cmd[MAXSTRING];
311
312    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
313    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
314    m_console->write_dir(cd_cmd);
315    lineEdit->clear();
316    if ((stat = m_console->read()) > 0) {
317       m_cwd = m_console->msg();
318       lineEdit->insert(m_cwd);
319       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
320    } else {
321       Dmsg1(000, "stat=%d\n", stat);
322       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
323    }
324    m_console->discardToPrompt();
325    return true;  /* ***FIXME*** return real status */
326 }
327
328 /*
329  * Return cwd when in tree restore mode 
330  */
331 char *restoreDialog::get_cwd()
332 {
333    int stat;
334    m_console->write_dir(".pwd");
335    Dmsg0(100, "send: .pwd\n");
336    if ((stat = m_console->read()) > 0) {
337       m_cwd = m_console->msg();
338       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
339    } else {
340       Dmsg1(000, "stat=%d\n", stat);
341       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
342       Dmsg1(000, "stat=%d\n", stat);
343    }
344    m_console->discardToPrompt(); 
345    return m_cwd.toUtf8().data();
346 }