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 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.
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 */
56 connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
57 this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
58 connect(directoryWidget, SIGNAL(
59 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
60 this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
61 connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
62 connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
63 connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
64 connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
65 connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
67 fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
68 fileWidget->addAction(actionMark);
69 fileWidget->addAction(actionUnMark);
70 connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
71 connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
73 setFont(m_console->get_font());
74 m_console->displayToPrompt(m_conn);
76 titles << tr("Mark") << tr("File") << tr("Mode") << tr("User")
77 << tr("Group") << tr("Size") << tr("Date");
78 fileWidget->setHeaderLabels(titles);
83 /* wait was entered from pre-restore
84 * will exit, but will reenter in fillDirectory */
90 if (mainWin->m_miscDebug) Pmsg0(000, "Leave restorePage\n");
93 restorePage::~restorePage()
99 * Fill the fileWidget box with the contents of the current directory
101 void restorePage::fillDirectory()
103 mainWin->waitEnter();
104 char modes[20], user[20], group[20], size[20], date[30];
107 POOLMEM *file = get_pool_memory(PM_FNAME);
108 POOLMEM *path = get_pool_memory(PM_FNAME);
111 m_console->write_dir(m_conn, "dir", false);
112 QList<QTreeWidgetItem *> treeItemList;
114 m_rx.setPattern("has no children\\.$");
116 while (m_console->read(m_conn) > 0) {
117 char *p = m_console->msg(m_conn);
119 strip_trailing_junk(p);
120 if (*p == '$' || !*p) { continue; }
122 if (m_rx.indexIn(QString(p)) != -1) { continue; }
126 skip_nonspaces(&p); /* permissions */
128 bstrncpy(modes, l, sizeof(modes));
130 skip_nonspaces(&p); /* link count */
134 skip_nonspaces(&p); /* user */
137 bstrncpy(user, l, sizeof(user));
139 skip_nonspaces(&p); /* group */
141 bstrncpy(group, l, sizeof(group));
144 skip_nonspaces(&p); /* size */
146 bstrncpy(size, l, sizeof(size));
149 skip_nonspaces(&p); /* date/time */
153 bstrncpy(date, l, sizeof(date));
156 bstrncpy(marked, "*", sizeof(marked));
159 bstrncpy(marked, " ", sizeof(marked));
161 split_path_and_filename(p, &path, &pnl, &file, &fnl);
163 item << "" << file << modes << user << group << size << date;
164 if (item[1].endsWith("/")) {
165 addDirectory(item[1]);
167 QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
168 ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
169 if (strcmp(marked, "*") == 0) {
170 ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
171 ti->setData(0, Qt::UserRole, true);
173 ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
174 ti->setData(0, Qt::UserRole, false);
176 treeItemList.append(ti);
179 fileWidget->insertTopLevelItems(0, treeItemList);
180 for (int i=0; i<7; i++) {
181 fileWidget->resizeColumnToContents(i);
184 free_pool_memory(file);
185 free_pool_memory(path);
190 * Function called from fill directory when a directory is found to see if this
191 * directory exists in the directory pane and then add it to the directory pane
193 void restorePage::addDirectory(QString &newdirr)
195 QString newdir = newdirr;
196 QString fullpath = m_cwd + newdirr;
198 bool windrive = false;
200 if (mainWin->m_miscDebug) {
201 QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
205 Pmsg0(dbglvl, msg.toUtf8().data());
208 if (isWin32Path(newdir)) {
209 /* this is a windows drive */
210 if (mainWin->m_miscDebug) {
211 Pmsg0(dbglvl, "Found windows drive\n");
217 if (fullpath.left(1) == "/") {
218 fullpath.replace(0, 1, ""); /* strip leading / */
220 /* If drive and not already in add it */
221 if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
222 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
223 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
224 item->setText(0, fullpath.toUtf8().data());
225 if (mainWin->m_miscDebug) {
226 Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
228 m_dirPaths.insert(fullpath, item);
229 m_dirTreeItems.insert(item, fullpath);
230 directoryWidget->setCurrentItem(NULL);
233 // Unix add / first if not already there
234 if (m_dirPaths.empty()) {
235 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
236 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
239 item->setText(0, text.toUtf8().data());
240 if (mainWin->m_miscDebug) {
241 Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
243 m_dirPaths.insert(text, item);
244 m_dirTreeItems.insert(item, text);
248 /* Does it already exist ?? */
249 if (!m_dirPaths.contains(fullpath)) {
250 QTreeWidgetItem *item = NULL;
252 /* this is the base widget */
253 item = new QTreeWidgetItem(directoryWidget);
254 item->setText(0, fullpath.toUtf8().data());
255 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
257 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
259 /* new directories to add */
260 item = new QTreeWidgetItem(parent);
261 item->setText(0, newdir.toUtf8().data());
262 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
263 directoryWidget->expandItem(parent);
266 if (mainWin->m_miscDebug) {
267 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
270 Pmsg0(dbglvl, msg.toUtf8().data());
274 /* insert into both forward and reverse hash */
276 if (mainWin->m_miscDebug) {
277 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
279 m_dirPaths.insert(fullpath, item);
280 m_dirTreeItems.insert(item, fullpath);
286 * Executed when the tree item in the directory pane is changed. This will
287 * allow us to populate the file pane and make this the cwd.
289 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
290 QTreeWidgetItem * /*previousitem*/)
292 QString fullpath = m_dirTreeItems.value(currentitem);
293 statusLine->setText("");
294 if (fullpath != "") {
295 cwd(fullpath.toUtf8().data());
300 void restorePage::okButtonPushed()
303 m_console->write(m_conn, "done");
304 m_console->notify(m_conn, true);
307 mainWin->resetFocus();
311 void restorePage::cancelButtonPushed()
314 m_console->write(m_conn, "quit");
315 m_console->displayToPrompt(m_conn);
316 mainWin->set_status(tr("Canceled"));
318 m_console->notify(m_conn, true);
319 mainWin->resetFocus();
322 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
325 statusLine->setText("");
326 if (column == 0) { /* mark/unmark */
327 mainWin->waitEnter();
328 if (item->data(0, Qt::UserRole).toBool()) {
329 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
330 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
331 item->setData(0, Qt::UserRole, false);
333 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
334 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
335 item->setData(0, Qt::UserRole, true);
337 m_console->write_dir(m_conn, cmd, false);
338 if (m_console->read(m_conn) > 0) {
339 strip_trailing_junk(m_console->msg(m_conn));
340 statusLine->setText(m_console->msg(m_conn));
342 m_console->displayToPrompt(m_conn);
347 * Double clicking other than column 0 means to decend into
348 * the directory -- or nothing if it is not a directory.
350 if (item->text(1).endsWith("/")) {
351 QString fullpath = m_cwd + item->text(1);
352 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
354 directoryWidget->setCurrentItem(item);
356 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
359 Pmsg0(dbglvl, msg.toUtf8().data());
365 * If up button pushed, making the parent tree widget current will call fill
368 void restorePage::upButtonPushed()
371 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
373 directoryWidget->setCurrentItem(item);
375 statusLine->setText("");
379 * Mark selected items
381 void restorePage::markButtonPushed()
383 mainWin->waitEnter();
384 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
385 QTreeWidgetItem *item;
388 statusLine->setText("");
389 foreach (item, treeItemList) {
391 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
392 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
393 m_console->write_dir(m_conn, cmd, false);
394 if (m_console->read(m_conn) > 0) {
395 strip_trailing_junk(m_console->msg(m_conn));
396 statusLine->setText(m_console->msg(m_conn));
398 Dmsg1(dbglvl, "cmd=%s\n", cmd);
399 m_console->discardToPrompt(m_conn);
402 mainWin->set_status("Nothing selected, nothing done");
403 statusLine->setText("Nothing selected, nothing done");
409 * Unmark selected items
411 void restorePage::unmarkButtonPushed()
413 mainWin->waitEnter();
414 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
415 QTreeWidgetItem *item;
418 statusLine->setText("");
419 foreach (item, treeItemList) {
421 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
422 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
423 m_console->write_dir(m_conn, cmd, false);
424 if (m_console->read(m_conn) > 0) {
425 strip_trailing_junk(m_console->msg(m_conn));
426 statusLine->setText(m_console->msg(m_conn));
428 Dmsg1(dbglvl, "cmd=%s\n", cmd);
429 m_console->discardToPrompt(m_conn);
432 mainWin->set_status(tr("Nothing selected, nothing done"));
433 statusLine->setText(tr("Nothing selected, nothing done"));
439 * Change current working directory
441 bool restorePage::cwd(const char *dir)
444 char cd_cmd[MAXSTRING];
446 mainWin->waitEnter();
447 statusLine->setText("");
448 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
449 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
450 m_console->write_dir(m_conn, cd_cmd, false);
452 if ((stat = m_console->read(m_conn)) > 0) {
453 m_cwd = m_console->msg(m_conn);
454 lineEdit->insert(m_cwd);
455 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
457 Dmsg1(dbglvl, "stat=%d\n", stat);
458 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
460 m_console->discardToPrompt(m_conn);
462 return true; /* ***FIXME*** return real status */
466 * Return cwd when in tree restore mode
468 char *restorePage::get_cwd()
471 mainWin->waitEnter();
472 m_console->write_dir(m_conn, ".pwd", false);
473 Dmsg0(dbglvl, "send: .pwd\n");
474 if ((stat = m_console->read(m_conn)) > 0) {
475 m_cwd = m_console->msg(m_conn);
476 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
478 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
479 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
481 m_console->discardToPrompt(m_conn);
483 return m_cwd.toUtf8().data();
487 * Save user settings associated with this page
489 void restorePage::writeSettings()
491 QSettings settings(m_console->m_dir->name(), "bat");
492 settings.beginGroup("RestorePage");
493 settings.setValue(m_splitText, splitter->saveState());
498 * Read and restore user settings associated with this page
500 void restorePage::readSettings()
502 m_splitText = "splitterSizes_2";
503 QSettings settings(m_console->m_dir->name(), "bat");
504 settings.beginGroup("RestorePage");
505 if (settings.contains(m_splitText)) {
506 splitter->restoreState(settings.value(m_splitText).toByteArray());