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) : Pages()
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;
198 if (mainWin->m_miscDebug) {
199 QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
203 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
206 if (isWin32Path(fullpath)) {
207 if (mainWin->m_miscDebug) Pmsg0(dbglvl, "Windows drive\n");
208 if (fullpath.left(1) == "/") {
209 fullpath.replace(0, 1, ""); /* strip leading / */
211 /* If drive and not already in add it */
212 if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
213 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
214 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
215 item->setText(0, fullpath.toUtf8().data());
216 if (mainWin->m_miscDebug) {
217 Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
219 m_dirPaths.insert(fullpath, item);
220 m_dirTreeItems.insert(item, fullpath);
221 directoryWidget->setCurrentItem(NULL);
224 // Unix add / first if not already there
225 if (m_dirPaths.empty()) {
226 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
227 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
230 item->setText(0, text.toUtf8().data());
231 if (mainWin->m_miscDebug) {
232 Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
234 m_dirPaths.insert(text, item);
235 m_dirTreeItems.insert(item, text);
239 /* Does it already exist ?? */
240 if (!m_dirPaths.contains(fullpath)) {
241 QTreeWidgetItem *item = NULL;
242 if (isWin32Path(fullpath)) {
243 /* this is the base widget */
244 item = new QTreeWidgetItem(directoryWidget);
245 item->setText(0, fullpath.toUtf8().data());
246 if (mainWin->m_miscDebug) Pmsg1(dbglvl, "Windows: %s\n", fullpath.toUtf8().data());
247 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
249 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
251 /* new directories to add */
252 item = new QTreeWidgetItem(parent);
253 item->setText(0, newdir.toUtf8().data());
254 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
255 directoryWidget->expandItem(parent);
256 if (mainWin->m_miscDebug) {
257 Pmsg1(dbglvl, "%s\n", newdir.toUtf8().data());
261 if (mainWin->m_miscDebug) {
262 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
265 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
269 /* insert into both forward and reverse hash */
271 if (mainWin->m_miscDebug) {
272 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
274 m_dirPaths.insert(fullpath, item);
275 m_dirTreeItems.insert(item, fullpath);
281 * Executed when the tree item in the directory pane is changed. This will
282 * allow us to populate the file pane and make this the cwd.
284 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
285 QTreeWidgetItem * /*previousitem*/)
287 QString fullpath = m_dirTreeItems.value(currentitem);
288 statusLine->setText("");
289 if (fullpath != "") {
290 cwd(fullpath.toUtf8().data());
295 void restorePage::okButtonPushed()
298 m_console->write(m_conn, "done");
299 m_console->notify(m_conn, true);
302 mainWin->resetFocus();
306 void restorePage::cancelButtonPushed()
309 m_console->write(m_conn, "quit");
310 m_console->displayToPrompt(m_conn);
311 mainWin->set_status(tr("Canceled"));
313 m_console->notify(m_conn, true);
314 mainWin->resetFocus();
317 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
320 statusLine->setText("");
321 if (column == 0) { /* mark/unmark */
322 mainWin->waitEnter();
323 if (item->data(0, Qt::UserRole).toBool()) {
324 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
325 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
326 item->setData(0, Qt::UserRole, false);
328 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
329 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
330 item->setData(0, Qt::UserRole, true);
332 m_console->write_dir(m_conn, cmd, false);
333 if (m_console->read(m_conn) > 0) {
334 strip_trailing_junk(m_console->msg(m_conn));
335 statusLine->setText(m_console->msg(m_conn));
337 m_console->displayToPrompt(m_conn);
342 * Double clicking other than column 0 means to decend into
343 * the directory -- or nothing if it is not a directory.
345 if (item->text(1).endsWith("/")) {
346 QString fullpath = m_cwd + item->text(1);
347 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
348 if (mainWin->m_miscDebug) {
349 Pmsg1(dbglvl, "%s\n", fullpath.toUtf8().data());
352 directoryWidget->setCurrentItem(item);
354 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
357 if (mainWin->m_miscDebug) Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
363 * If up button pushed, making the parent tree widget current will call fill
366 void restorePage::upButtonPushed()
369 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
371 directoryWidget->setCurrentItem(item);
373 statusLine->setText("");
377 * Mark selected items
379 void restorePage::markButtonPushed()
381 mainWin->waitEnter();
382 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
383 QTreeWidgetItem *item;
386 statusLine->setText("");
387 foreach (item, treeItemList) {
389 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
390 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
391 m_console->write_dir(m_conn, cmd, false);
392 if (m_console->read(m_conn) > 0) {
393 strip_trailing_junk(m_console->msg(m_conn));
394 statusLine->setText(m_console->msg(m_conn));
396 Dmsg1(dbglvl, "cmd=%s\n", cmd);
397 m_console->discardToPrompt(m_conn);
400 mainWin->set_status("Nothing selected, nothing done");
401 statusLine->setText("Nothing selected, nothing done");
407 * Unmark selected items
409 void restorePage::unmarkButtonPushed()
411 mainWin->waitEnter();
412 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
413 QTreeWidgetItem *item;
416 statusLine->setText("");
417 foreach (item, treeItemList) {
419 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
420 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
421 m_console->write_dir(m_conn, cmd, false);
422 if (m_console->read(m_conn) > 0) {
423 strip_trailing_junk(m_console->msg(m_conn));
424 statusLine->setText(m_console->msg(m_conn));
426 Dmsg1(dbglvl, "cmd=%s\n", cmd);
427 m_console->discardToPrompt(m_conn);
430 mainWin->set_status(tr("Nothing selected, nothing done"));
431 statusLine->setText(tr("Nothing selected, nothing done"));
437 * Change current working directory
439 bool restorePage::cwd(const char *dir)
442 char cd_cmd[MAXSTRING];
444 mainWin->waitEnter();
445 statusLine->setText("");
446 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
447 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
448 m_console->write_dir(m_conn, cd_cmd, false);
450 if ((stat = m_console->read(m_conn)) > 0) {
451 m_cwd = m_console->msg(m_conn);
452 lineEdit->insert(m_cwd);
453 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
455 Dmsg1(dbglvl, "stat=%d\n", stat);
456 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
458 m_console->discardToPrompt(m_conn);
460 return true; /* ***FIXME*** return real status */
464 * Return cwd when in tree restore mode
466 char *restorePage::get_cwd()
469 mainWin->waitEnter();
470 m_console->write_dir(m_conn, ".pwd", false);
471 Dmsg0(dbglvl, "send: .pwd\n");
472 if ((stat = m_console->read(m_conn)) > 0) {
473 m_cwd = m_console->msg(m_conn);
474 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
476 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
477 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
479 m_console->discardToPrompt(m_conn);
481 return m_cwd.toUtf8().data();
485 * Save user settings associated with this page
487 void restorePage::writeSettings()
489 QSettings settings(m_console->m_dir->name(), "bat");
490 settings.beginGroup("RestorePage");
491 settings.setValue(m_splitText, splitter->saveState());
496 * Read and restore user settings associated with this page
498 void restorePage::readSettings()
500 m_splitText = "splitterSizes_2";
501 QSettings settings(m_console->m_dir->name(), "bat");
502 settings.beginGroup("RestorePage");
503 if (settings.contains(m_splitText)) {
504 splitter->restoreState(settings.value(m_splitText).toByteArray());