]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restore.cpp
Joblist: change page select widget name to "JobList"
[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    setFont(m_console->get_font());
65    m_console->displayToPrompt();
66
67    titles << "Mark" << "File" << "Mode" << "User" << "Group" << "Size" << "Date";
68    fileWidget->setHeaderLabels(titles);
69
70    get_cwd();
71
72    fillDirectory();
73    dockPage();
74    setCurrent();
75    this->show();
76 }
77
78 /*
79  * Fill the fileWidget box with the contents of the current directory
80  */
81 void restorePage::fillDirectory()
82 {
83    char modes[20], user[20], group[20], size[20], date[30];
84    char marked[10];
85    int pnl, fnl;
86    POOLMEM *file = get_pool_memory(PM_FNAME);
87    POOLMEM *path = get_pool_memory(PM_FNAME);
88
89    fileWidget->clear();
90    m_console->write_dir("dir");
91    QList<QTreeWidgetItem *> treeItemList;
92    QStringList item;
93    while (m_console->read() > 0) {
94       char *p = m_console->msg();
95       char *l;
96       strip_trailing_junk(p);
97       if (*p == '$' || !*p) {
98          continue;
99       }
100       l = p;
101       skip_nonspaces(&p);             /* permissions */
102       *p++ = 0;
103       bstrncpy(modes, l, sizeof(modes));
104       skip_spaces(&p);
105       skip_nonspaces(&p);             /* link count */
106       *p++ = 0;
107       skip_spaces(&p);
108       l = p;
109       skip_nonspaces(&p);             /* user */
110       *p++ = 0;
111       skip_spaces(&p);
112       bstrncpy(user, l, sizeof(user));
113       l = p;
114       skip_nonspaces(&p);             /* group */
115       *p++ = 0;
116       bstrncpy(group, l, sizeof(group));
117       skip_spaces(&p);
118       l = p;
119       skip_nonspaces(&p);             /* size */
120       *p++ = 0;
121       bstrncpy(size, l, sizeof(size));
122       skip_spaces(&p);
123       l = p;
124       skip_nonspaces(&p);             /* date/time */
125       skip_spaces(&p);
126       skip_nonspaces(&p);
127       *p++ = 0;
128       bstrncpy(date, l, sizeof(date));
129       skip_spaces(&p);
130       if (*p == '*') {
131          bstrncpy(marked, "*", sizeof(marked));
132          p++;
133       } else {
134          bstrncpy(marked, " ", sizeof(marked));
135       }
136       split_path_and_filename(p, &path, &pnl, &file, &fnl);
137       item.clear();
138       item << "" << file << modes << user << group << size << date;
139       if (item[1].endsWith("/")) {
140          addDirectory(item[1]);
141       }
142       QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
143       ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
144       if (strcmp(marked, "*") == 0) {
145          ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
146          ti->setData(0, Qt::UserRole, true);
147       } else {
148          ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
149          ti->setData(0, Qt::UserRole, false);
150       }
151       treeItemList.append(ti);
152    }
153    fileWidget->clear();
154    fileWidget->insertTopLevelItems(0, treeItemList);
155    for (int i=0; i<7; i++) {
156       fileWidget->resizeColumnToContents(i);
157    }
158
159    free_pool_memory(file);
160    free_pool_memory(path);
161 }
162
163 /*
164  * Function called from fill directory when a directory is found to see if this
165  * directory exists in the directory pane and then add it to the directory pane
166  */
167 void restorePage::addDirectory(QString &newdirr)
168 {
169    QString newdir = newdirr;
170    QString fullpath = m_cwd + newdirr;
171    QRegExp regex("^/[a-z]:/$");
172    bool ok = true;
173    bool windrive = false;
174
175    if (mainWin->m_miscDebug) {
176       QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
177                     .arg(m_cwd)
178                     .arg(newdir);
179       Pmsg0(000, msg.toUtf8().data());
180    }
181
182    /* add unix '/' directory first */
183    if (m_dirPaths.empty() && (regex.indexIn(fullpath,0) == -1)) {
184       QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
185       item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
186       
187       QString text("/");
188       item->setText(0, text.toUtf8().data());
189       if (mainWin->m_miscDebug) {
190          Pmsg1(000, "Pre Inserting %s\n",text.toUtf8().data());
191       }
192       m_dirPaths.insert(text, item);
193       m_dirTreeItems.insert(item, text);
194    }
195
196    if (regex.indexIn(fullpath,0) == 0) {
197       /* this is a windows drive */
198       if (mainWin->m_miscDebug) {
199          Pmsg0(000, "Need to do windows \"letter\":/\n");
200       }
201       fullpath.replace(0,1,"");
202       windrive = true;
203    }
204  
205    /* is it already existent ?? */
206    if (!m_dirPaths.contains(fullpath)) {
207       QTreeWidgetItem *item = NULL;
208       if (windrive) {
209          /* this is the base widget */
210          item = new QTreeWidgetItem(directoryWidget);
211          item->setText(0, fullpath.toUtf8().data());
212          item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
213       } else {
214          QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
215          if (parent) {
216             /* new directories to add */
217             item = new QTreeWidgetItem(parent);
218             item->setText(0, newdir.toUtf8().data());
219             item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.svg")));
220             directoryWidget->expandItem(parent);
221          } else {
222             ok = false;
223             if (mainWin->m_miscDebug) {
224                QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
225                     .arg(m_cwd)
226                     .arg(newdir);
227                Pmsg0(000, msg.toUtf8().data());
228             }
229          }
230       }
231       /* insert into both forward and reverse hash */
232       if (ok) {
233          if (mainWin->m_miscDebug) {
234             Pmsg1(000, "Inserting %s\n",fullpath.toUtf8().data());
235          }
236          m_dirPaths.insert(fullpath, item);
237          m_dirTreeItems.insert(item, fullpath);
238       }
239    }
240 }
241
242 /*
243  * Executed when the tree item in the directory pane is changed.  This will
244  * allow us to populate the file pane and make this the cwd.
245  */
246 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
247                                          QTreeWidgetItem * /*previousitem*/)
248 {
249    QString fullpath = m_dirTreeItems.value(currentitem);
250    if (fullpath != ""){
251       cwd(fullpath.toUtf8().data());
252       fillDirectory();
253    }
254 }
255
256 void restorePage::okButtonPushed()
257 {
258    this->hide();
259    m_console->write("done");
260    m_console->notify(true);
261    setConsoleCurrent();
262    closeStackPage();
263    mainWin->resetFocus();
264 }
265
266
267 void restorePage::cancelButtonPushed()
268 {
269    this->hide();
270    m_console->write("quit");
271    m_console->displayToPrompt();
272    mainWin->set_status("Canceled");
273    closeStackPage();
274    m_console->notify(true);
275    mainWin->resetFocus();
276 }
277
278 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
279 {
280    char cmd[1000];
281    if (column == 0) {                 /* mark/unmark */
282       if (item->data(0, Qt::UserRole).toBool()) {
283          bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
284          item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
285          item->setData(0, Qt::UserRole, false);
286       } else {
287          bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
288          item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
289          item->setData(0, Qt::UserRole, true);
290       }
291       m_console->write_dir(cmd);
292       if (m_console->read() > 0) {
293          strip_trailing_junk(m_console->msg());
294          statusLine->setText(m_console->msg());
295       }
296       m_console->displayToPrompt();
297       return;
298    }    
299    /* 
300     * Double clicking other than column 0 means to decend into
301     *  the directory -- or nothing if it is not a directory.
302     */
303    if (item->text(1).endsWith("/")) {
304       QString fullpath = m_cwd + item->text(1);
305       /* check for fullpath = "/c:/" */
306       QRegExp regex("^/[a-z]:/");
307       if (regex.indexIn(fullpath,0) == 0)  /* remove leading '/' */
308          fullpath.replace(0,1,"");
309       QTreeWidgetItem *item = m_dirPaths.value(fullpath);
310       if (item) {
311          directoryWidget->setCurrentItem(item);
312       } else {
313          QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
314               .arg(column,10)
315               .arg(fullpath);
316          Pmsg0(000, msg.toUtf8().data());
317       }
318    }
319 }
320
321 /*
322  * If up button pushed, making the parent tree widget current will call fill
323  * directory.
324  */
325 void restorePage::upButtonPushed()
326 {
327    cwd("..");
328    QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
329    if (item) {
330       directoryWidget->setCurrentItem(item);
331    }
332 }
333
334 /*
335  * Mark selected items
336  */
337 void restorePage::markButtonPushed()
338 {
339    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
340    QTreeWidgetItem *item;
341    char cmd[1000];
342    foreach (item, treeItemList) {
343       bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
344       item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
345       m_console->write_dir(cmd);
346       if (m_console->read() > 0) {
347          strip_trailing_junk(m_console->msg());
348          statusLine->setText(m_console->msg());
349       }
350       Dmsg1(100, "cmd=%s\n", cmd);
351       m_console->discardToPrompt();
352    }
353 }
354
355 /*
356  * Unmark selected items
357  */
358 void restorePage::unmarkButtonPushed()
359 {
360    QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
361    QTreeWidgetItem *item;
362    char cmd[1000];
363    foreach (item, treeItemList) {
364       bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
365       item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
366       m_console->write_dir(cmd);
367       if (m_console->read() > 0) {
368          strip_trailing_junk(m_console->msg());
369          statusLine->setText(m_console->msg());
370       }
371       Dmsg1(100, "cmd=%s\n", cmd);
372       m_console->discardToPrompt();
373    }
374 }
375
376 /*
377  * Change current working directory 
378  */
379 bool restorePage::cwd(const char *dir)
380 {
381    int stat;
382    char cd_cmd[MAXSTRING];
383
384    bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
385    Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
386    m_console->write_dir(cd_cmd);
387    lineEdit->clear();
388    if ((stat = m_console->read()) > 0) {
389       m_cwd = m_console->msg();
390       lineEdit->insert(m_cwd);
391       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
392    } else {
393       Dmsg1(000, "stat=%d\n", stat);
394       QMessageBox::critical(this, "Error", "cd command failed", QMessageBox::Ok);
395    }
396    m_console->discardToPrompt();
397    return true;  /* ***FIXME*** return real status */
398 }
399
400 /*
401  * Return cwd when in tree restore mode 
402  */
403 char *restorePage::get_cwd()
404 {
405    int stat;
406    m_console->write_dir(".pwd");
407    Dmsg0(100, "send: .pwd\n");
408    if ((stat = m_console->read()) > 0) {
409       m_cwd = m_console->msg();
410       Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
411    } else {
412       Dmsg1(000, "Something went wrong read stat=%d\n", stat);
413       QMessageBox::critical(this, "Error", ".pwd command failed", QMessageBox::Ok);
414    }
415    m_console->discardToPrompt(); 
416    return m_cwd.toUtf8().data();
417 }