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