2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
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 three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
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.
18 You should have received a copy of the GNU Affero 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
23 Bacula® is a registered trademark of Kern Sibbald.
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.
32 * Kern Sibbald, February MMVII
39 static const int dbglvl = 100;
41 restorePage::restorePage(int conn)
43 Dmsg1(dbglvl, "Construcing restorePage Instance connection %i\n", conn);
48 m_name = tr("Restore Select");
50 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
51 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
53 m_console->notify(m_conn, false); /* this should already be off */
55 connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
56 this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
57 connect(directoryWidget, SIGNAL(
58 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
59 this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
60 connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
61 connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
62 connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
63 connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
64 connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
66 fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
67 fileWidget->addAction(actionMark);
68 fileWidget->addAction(actionUnMark);
69 connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
70 connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
72 setFont(m_console->get_font());
73 m_console->displayToPrompt(m_conn);
75 titles << tr("Mark") << tr("File") << tr("Mode") << tr("User")
76 << tr("Group") << tr("Size") << tr("Date");
77 fileWidget->setHeaderLabels(titles);
82 /* wait was entered from pre-restore
83 * will exit, but will reenter in fillDirectory */
89 if (mainWin->m_miscDebug) Pmsg0(000, "Leave restorePage\n");
92 restorePage::~restorePage()
98 * Fill the fileWidget box with the contents of the current directory
100 void restorePage::fillDirectory()
102 mainWin->waitEnter();
103 char modes[20], user[20], group[20], size[20], date[30];
106 POOLMEM *file = get_pool_memory(PM_FNAME);
107 POOLMEM *path = get_pool_memory(PM_FNAME);
110 m_console->write_dir(m_conn, "dir", false);
111 QList<QTreeWidgetItem *> treeItemList;
113 m_rx.setPattern("has no children\\.$");
115 while (m_console->read(m_conn) > 0) {
116 char *p = m_console->msg(m_conn);
118 strip_trailing_junk(p);
119 if (*p == '$' || !*p) { continue; }
121 if (m_rx.indexIn(QString(p)) != -1) { continue; }
125 skip_nonspaces(&p); /* permissions */
127 bstrncpy(modes, l, sizeof(modes));
129 skip_nonspaces(&p); /* link count */
133 skip_nonspaces(&p); /* user */
136 bstrncpy(user, l, sizeof(user));
138 skip_nonspaces(&p); /* group */
140 bstrncpy(group, l, sizeof(group));
143 skip_nonspaces(&p); /* size */
145 bstrncpy(size, l, sizeof(size));
148 skip_nonspaces(&p); /* date/time */
152 bstrncpy(date, l, sizeof(date));
155 bstrncpy(marked, "*", sizeof(marked));
158 bstrncpy(marked, " ", sizeof(marked));
160 split_path_and_filename(p, &path, &pnl, &file, &fnl);
162 item << "" << file << modes << user << group << size << date;
163 if (item[1].endsWith("/")) {
164 addDirectory(item[1]);
166 QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
167 ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
168 if (strcmp(marked, "*") == 0) {
169 ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
170 ti->setData(0, Qt::UserRole, true);
172 ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
173 ti->setData(0, Qt::UserRole, false);
175 treeItemList.append(ti);
178 fileWidget->insertTopLevelItems(0, treeItemList);
179 for (int i=0; i<7; i++) {
180 fileWidget->resizeColumnToContents(i);
183 free_pool_memory(file);
184 free_pool_memory(path);
189 * Function called from fill directory when a directory is found to see if this
190 * directory exists in the directory pane and then add it to the directory pane
192 void restorePage::addDirectory(QString &newdirr)
194 QString newdir = newdirr;
195 QString fullpath = m_cwd + newdirr;
197 bool windrive = false;
199 if (mainWin->m_miscDebug) {
200 QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
204 Pmsg0(dbglvl, msg.toUtf8().data());
207 if (isWin32Path(newdir)) {
208 /* this is a windows drive */
209 if (mainWin->m_miscDebug) {
210 Pmsg0(dbglvl, "Found windows drive\n");
216 if (fullpath.left(1) == "/") {
217 fullpath.replace(0, 1, ""); /* strip leading / */
219 /* If drive and not already in add it */
220 if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
221 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
222 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
223 item->setText(0, fullpath.toUtf8().data());
224 if (mainWin->m_miscDebug) {
225 Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
227 m_dirPaths.insert(fullpath, item);
228 m_dirTreeItems.insert(item, fullpath);
229 directoryWidget->setCurrentItem(NULL);
232 // Unix add / first if not already there
233 if (m_dirPaths.empty()) {
234 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
235 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
238 item->setText(0, text.toUtf8().data());
239 if (mainWin->m_miscDebug) {
240 Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
242 m_dirPaths.insert(text, item);
243 m_dirTreeItems.insert(item, text);
247 /* Does it already exist ?? */
248 if (!m_dirPaths.contains(fullpath)) {
249 QTreeWidgetItem *item = NULL;
251 /* this is the base widget */
252 item = new QTreeWidgetItem(directoryWidget);
253 item->setText(0, fullpath.toUtf8().data());
254 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
256 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
258 /* new directories to add */
259 item = new QTreeWidgetItem(parent);
260 item->setText(0, newdir.toUtf8().data());
261 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
262 directoryWidget->expandItem(parent);
265 if (mainWin->m_miscDebug) {
266 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
269 Pmsg0(dbglvl, msg.toUtf8().data());
273 /* insert into both forward and reverse hash */
275 if (mainWin->m_miscDebug) {
276 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
278 m_dirPaths.insert(fullpath, item);
279 m_dirTreeItems.insert(item, fullpath);
285 * Executed when the tree item in the directory pane is changed. This will
286 * allow us to populate the file pane and make this the cwd.
288 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
289 QTreeWidgetItem * /*previousitem*/)
291 QString fullpath = m_dirTreeItems.value(currentitem);
292 statusLine->setText("");
293 if (fullpath != "") {
294 cwd(fullpath.toUtf8().data());
299 void restorePage::okButtonPushed()
302 m_console->write(m_conn, "done");
303 m_console->notify(m_conn, true);
306 mainWin->resetFocus();
310 void restorePage::cancelButtonPushed()
313 m_console->write(m_conn, "quit");
314 m_console->displayToPrompt(m_conn);
315 mainWin->set_status(tr("Canceled"));
317 m_console->notify(m_conn, true);
318 mainWin->resetFocus();
321 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
324 statusLine->setText("");
325 if (column == 0) { /* mark/unmark */
326 mainWin->waitEnter();
327 if (item->data(0, Qt::UserRole).toBool()) {
328 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
329 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
330 item->setData(0, Qt::UserRole, false);
332 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
333 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
334 item->setData(0, Qt::UserRole, true);
336 m_console->write_dir(m_conn, cmd, false);
337 if (m_console->read(m_conn) > 0) {
338 strip_trailing_junk(m_console->msg(m_conn));
339 statusLine->setText(m_console->msg(m_conn));
341 m_console->displayToPrompt(m_conn);
346 * Double clicking other than column 0 means to decend into
347 * the directory -- or nothing if it is not a directory.
349 if (item->text(1).endsWith("/")) {
350 QString fullpath = m_cwd + item->text(1);
351 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
353 directoryWidget->setCurrentItem(item);
355 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
358 Pmsg0(dbglvl, msg.toUtf8().data());
364 * If up button pushed, making the parent tree widget current will call fill
367 void restorePage::upButtonPushed()
370 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
372 directoryWidget->setCurrentItem(item);
374 statusLine->setText("");
378 * Mark selected items
380 void restorePage::markButtonPushed()
382 mainWin->waitEnter();
383 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
384 QTreeWidgetItem *item;
387 statusLine->setText("");
388 foreach (item, treeItemList) {
390 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
391 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
392 m_console->write_dir(m_conn, cmd, false);
393 if (m_console->read(m_conn) > 0) {
394 strip_trailing_junk(m_console->msg(m_conn));
395 statusLine->setText(m_console->msg(m_conn));
397 Dmsg1(dbglvl, "cmd=%s\n", cmd);
398 m_console->discardToPrompt(m_conn);
401 mainWin->set_status("Nothing selected, nothing done");
402 statusLine->setText("Nothing selected, nothing done");
408 * Unmark selected items
410 void restorePage::unmarkButtonPushed()
412 mainWin->waitEnter();
413 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
414 QTreeWidgetItem *item;
417 statusLine->setText("");
418 foreach (item, treeItemList) {
420 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
421 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
422 m_console->write_dir(m_conn, cmd, false);
423 if (m_console->read(m_conn) > 0) {
424 strip_trailing_junk(m_console->msg(m_conn));
425 statusLine->setText(m_console->msg(m_conn));
427 Dmsg1(dbglvl, "cmd=%s\n", cmd);
428 m_console->discardToPrompt(m_conn);
431 mainWin->set_status(tr("Nothing selected, nothing done"));
432 statusLine->setText(tr("Nothing selected, nothing done"));
438 * Change current working directory
440 bool restorePage::cwd(const char *dir)
443 char cd_cmd[MAXSTRING];
445 mainWin->waitEnter();
446 statusLine->setText("");
447 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
448 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
449 m_console->write_dir(m_conn, cd_cmd, false);
451 if ((stat = m_console->read(m_conn)) > 0) {
452 m_cwd = m_console->msg(m_conn);
453 lineEdit->insert(m_cwd);
454 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
456 Dmsg1(dbglvl, "stat=%d\n", stat);
457 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
459 m_console->discardToPrompt(m_conn);
461 return true; /* ***FIXME*** return real status */
465 * Return cwd when in tree restore mode
467 char *restorePage::get_cwd()
470 mainWin->waitEnter();
471 m_console->write_dir(m_conn, ".pwd", false);
472 Dmsg0(dbglvl, "send: .pwd\n");
473 if ((stat = m_console->read(m_conn)) > 0) {
474 m_cwd = m_console->msg(m_conn);
475 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
477 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
478 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
480 m_console->discardToPrompt(m_conn);
482 return m_cwd.toUtf8().data();
486 * Save user settings associated with this page
488 void restorePage::writeSettings()
490 QSettings settings(m_console->m_dir->name(), "bat");
491 settings.beginGroup("RestorePage");
492 settings.setValue(m_splitText, splitter->saveState());
497 * Read and restore user settings associated with this page
499 void restorePage::readSettings()
501 m_splitText = "splitterSizes_2";
502 QSettings settings(m_console->m_dir->name(), "bat");
503 settings.beginGroup("RestorePage");
504 if (settings.contains(m_splitText)) {
505 splitter->restoreState(settings.value(m_splitText).toByteArray());