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