2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2009 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 two of the GNU 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 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.
34 * Kern Sibbald, February MMVII
41 static const int dbglvl = 100;
43 restorePage::restorePage(int conn)
45 Dmsg1(dbglvl, "Construcing restorePage Instance connection %i\n", conn);
50 m_name = tr("Restore Select");
52 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
53 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
55 m_console->notify(m_conn, false); /* this should already be off */
58 connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
59 this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
60 connect(directoryWidget, SIGNAL(
61 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
62 this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
63 connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
64 connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
65 connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
66 connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
67 connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
69 fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
70 fileWidget->addAction(actionMark);
71 fileWidget->addAction(actionUnMark);
72 connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
73 connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
75 setFont(m_console->get_font());
76 m_console->displayToPrompt(m_conn);
78 titles << tr("Mark") << tr("File") << tr("Mode") << tr("User")
79 << tr("Group") << tr("Size") << tr("Date");
80 fileWidget->setHeaderLabels(titles);
85 /* wait was entered from pre-restore
86 * will exit, but will reenter in fillDirectory */
94 restorePage::~restorePage()
100 * Fill the fileWidget box with the contents of the current directory
102 void restorePage::fillDirectory()
104 mainWin->waitEnter();
105 char modes[20], user[20], group[20], size[20], date[30];
108 POOLMEM *file = get_pool_memory(PM_FNAME);
109 POOLMEM *path = get_pool_memory(PM_FNAME);
112 m_console->write_dir(m_conn, "dir", false);
113 QList<QTreeWidgetItem *> treeItemList;
115 m_rx.setPattern("has no children\\.$");
117 while (m_console->read(m_conn) > 0) {
118 char *p = m_console->msg(m_conn);
120 strip_trailing_junk(p);
121 if (*p == '$' || !*p) { continue; }
123 if (m_rx.indexIn(QString(p)) != -1) { continue; }
127 skip_nonspaces(&p); /* permissions */
129 bstrncpy(modes, l, sizeof(modes));
131 skip_nonspaces(&p); /* link count */
135 skip_nonspaces(&p); /* user */
138 bstrncpy(user, l, sizeof(user));
140 skip_nonspaces(&p); /* group */
142 bstrncpy(group, l, sizeof(group));
145 skip_nonspaces(&p); /* size */
147 bstrncpy(size, l, sizeof(size));
150 skip_nonspaces(&p); /* date/time */
154 bstrncpy(date, l, sizeof(date));
157 bstrncpy(marked, "*", sizeof(marked));
160 bstrncpy(marked, " ", sizeof(marked));
162 split_path_and_filename(p, &path, &pnl, &file, &fnl);
164 item << "" << file << modes << user << group << size << date;
165 if (item[1].endsWith("/")) {
166 addDirectory(item[1]);
168 QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
169 ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
170 if (strcmp(marked, "*") == 0) {
171 ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
172 ti->setData(0, Qt::UserRole, true);
174 ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
175 ti->setData(0, Qt::UserRole, false);
177 treeItemList.append(ti);
180 fileWidget->insertTopLevelItems(0, treeItemList);
181 for (int i=0; i<7; i++) {
182 fileWidget->resizeColumnToContents(i);
185 free_pool_memory(file);
186 free_pool_memory(path);
191 * Function called from fill directory when a directory is found to see if this
192 * directory exists in the directory pane and then add it to the directory pane
194 void restorePage::addDirectory(QString &newdirr)
196 QString newdir = newdirr;
197 QString fullpath = m_cwd + newdirr;
199 bool windrive = false;
201 if (mainWin->m_miscDebug) {
202 QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
206 Pmsg0(dbglvl, msg.toUtf8().data());
209 if (isWin32Path(newdir)) {
210 /* this is a windows drive */
211 if (mainWin->m_miscDebug) {
212 Pmsg0(dbglvl, "Found windows drive\n");
218 if (fullpath.left(1) == "/") {
219 fullpath.replace(0, 1, ""); /* strip leading / */
221 /* If drive and not already in add it */
222 if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
223 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
224 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
225 item->setText(0, fullpath.toUtf8().data());
226 if (mainWin->m_miscDebug) {
227 Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
229 m_dirPaths.insert(fullpath, item);
230 m_dirTreeItems.insert(item, fullpath);
231 directoryWidget->setCurrentItem(NULL);
234 // Unix add / first if not already there
235 if (m_dirPaths.empty()) {
236 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
237 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
240 item->setText(0, text.toUtf8().data());
241 if (mainWin->m_miscDebug) {
242 Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
244 m_dirPaths.insert(text, item);
245 m_dirTreeItems.insert(item, text);
249 /* Does it already exist ?? */
250 if (!m_dirPaths.contains(fullpath)) {
251 QTreeWidgetItem *item = NULL;
253 /* this is the base widget */
254 item = new QTreeWidgetItem(directoryWidget);
255 item->setText(0, fullpath.toUtf8().data());
256 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
258 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
260 /* new directories to add */
261 item = new QTreeWidgetItem(parent);
262 item->setText(0, newdir.toUtf8().data());
263 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
264 directoryWidget->expandItem(parent);
267 if (mainWin->m_miscDebug) {
268 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
271 Pmsg0(dbglvl, msg.toUtf8().data());
275 /* insert into both forward and reverse hash */
277 if (mainWin->m_miscDebug) {
278 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
280 m_dirPaths.insert(fullpath, item);
281 m_dirTreeItems.insert(item, fullpath);
287 * Executed when the tree item in the directory pane is changed. This will
288 * allow us to populate the file pane and make this the cwd.
290 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
291 QTreeWidgetItem * /*previousitem*/)
293 QString fullpath = m_dirTreeItems.value(currentitem);
294 statusLine->setText("");
296 cwd(fullpath.toUtf8().data());
301 void restorePage::okButtonPushed()
304 m_console->write(m_conn, "done");
305 m_console->notify(m_conn, true);
308 mainWin->resetFocus();
312 void restorePage::cancelButtonPushed()
315 m_console->write(m_conn, "quit");
316 m_console->displayToPrompt(m_conn);
317 mainWin->set_status(tr("Canceled"));
319 m_console->notify(m_conn, true);
320 mainWin->resetFocus();
323 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
326 statusLine->setText("");
327 if (column == 0) { /* mark/unmark */
328 mainWin->waitEnter();
329 if (item->data(0, Qt::UserRole).toBool()) {
330 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
331 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
332 item->setData(0, Qt::UserRole, false);
334 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
335 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
336 item->setData(0, Qt::UserRole, true);
338 m_console->write_dir(m_conn, cmd, false);
339 if (m_console->read(m_conn) > 0) {
340 strip_trailing_junk(m_console->msg(m_conn));
341 statusLine->setText(m_console->msg(m_conn));
343 m_console->displayToPrompt(m_conn);
348 * Double clicking other than column 0 means to decend into
349 * the directory -- or nothing if it is not a directory.
351 if (item->text(1).endsWith("/")) {
352 QString fullpath = m_cwd + item->text(1);
353 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
355 directoryWidget->setCurrentItem(item);
357 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
360 Pmsg0(dbglvl, msg.toUtf8().data());
366 * If up button pushed, making the parent tree widget current will call fill
369 void restorePage::upButtonPushed()
372 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
374 directoryWidget->setCurrentItem(item);
376 statusLine->setText("");
380 * Mark selected items
382 void restorePage::markButtonPushed()
384 mainWin->waitEnter();
385 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
386 QTreeWidgetItem *item;
389 statusLine->setText("");
390 foreach (item, treeItemList) {
392 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
393 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
394 m_console->write_dir(m_conn, cmd, false);
395 if (m_console->read(m_conn) > 0) {
396 strip_trailing_junk(m_console->msg(m_conn));
397 statusLine->setText(m_console->msg(m_conn));
399 Dmsg1(dbglvl, "cmd=%s\n", cmd);
400 m_console->discardToPrompt(m_conn);
403 mainWin->set_status("Nothing selected, nothing done");
404 statusLine->setText("Nothing selected, nothing done");
410 * Unmark selected items
412 void restorePage::unmarkButtonPushed()
414 mainWin->waitEnter();
415 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
416 QTreeWidgetItem *item;
419 statusLine->setText("");
420 foreach (item, treeItemList) {
422 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
423 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
424 m_console->write_dir(m_conn, cmd, false);
425 if (m_console->read(m_conn) > 0) {
426 strip_trailing_junk(m_console->msg(m_conn));
427 statusLine->setText(m_console->msg(m_conn));
429 Dmsg1(dbglvl, "cmd=%s\n", cmd);
430 m_console->discardToPrompt(m_conn);
433 mainWin->set_status(tr("Nothing selected, nothing done"));
434 statusLine->setText(tr("Nothing selected, nothing done"));
440 * Change current working directory
442 bool restorePage::cwd(const char *dir)
445 char cd_cmd[MAXSTRING];
447 mainWin->waitEnter();
448 statusLine->setText("");
449 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
450 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
451 m_console->write_dir(m_conn, cd_cmd, false);
453 if ((stat = m_console->read(m_conn)) > 0) {
454 m_cwd = m_console->msg(m_conn);
455 lineEdit->insert(m_cwd);
456 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
458 Dmsg1(dbglvl, "stat=%d\n", stat);
459 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
461 m_console->discardToPrompt(m_conn);
463 return true; /* ***FIXME*** return real status */
467 * Return cwd when in tree restore mode
469 char *restorePage::get_cwd()
472 mainWin->waitEnter();
473 m_console->write_dir(m_conn, ".pwd", false);
474 Dmsg0(dbglvl, "send: .pwd\n");
475 if ((stat = m_console->read(m_conn)) > 0) {
476 m_cwd = m_console->msg(m_conn);
477 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
479 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
480 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
482 m_console->discardToPrompt(m_conn);
484 return m_cwd.toUtf8().data();
488 * Save user settings associated with this page
490 void restorePage::writeSettings()
492 QSettings settings(m_console->m_dir->name(), "bat");
493 settings.beginGroup("RestorePage");
494 m_splitText = "splitterSizes_2";
495 settings.setValue(m_splitText, splitter->saveState());
500 * Read and restore user settings associated with this page
502 void restorePage::readSettings()
504 QSettings settings(m_console->m_dir->name(), "bat");
505 settings.beginGroup("RestorePage");
506 if (settings.contains(m_splitText)) { splitter->restoreState(settings.value(m_splitText).toByteArray()); }