2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
23 * Kern Sibbald, February MMVII
30 static const int dbglvl = 100;
32 restorePage::restorePage(int conn) : Pages()
34 Dmsg1(dbglvl, "Construcing restorePage Instance connection %i\n", conn);
39 m_name = tr("Restore Select");
41 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
42 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
44 m_console->notify(m_conn, false); /* this should already be off */
46 connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
47 this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
48 connect(directoryWidget, SIGNAL(
49 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
50 this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
51 connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
52 connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
53 connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
54 connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
55 connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
57 fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
58 fileWidget->addAction(actionMark);
59 fileWidget->addAction(actionUnMark);
60 connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
61 connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
63 setFont(m_console->get_font());
64 m_console->displayToPrompt(m_conn);
66 titles << tr("Mark") << tr("File") << tr("Mode") << tr("User")
67 << tr("Group") << tr("Size") << tr("Date");
68 fileWidget->setHeaderLabels(titles);
73 /* wait was entered from pre-restore
74 * will exit, but will reenter in fillDirectory */
80 if (mainWin->m_miscDebug) Pmsg0(000, "Leave restorePage\n");
83 restorePage::~restorePage()
89 * Fill the fileWidget box with the contents of the current directory
91 void restorePage::fillDirectory()
94 char modes[20], user[20], group[20], size[20], date[30];
97 POOLMEM *file = get_pool_memory(PM_FNAME);
98 POOLMEM *path = get_pool_memory(PM_FNAME);
101 m_console->write_dir(m_conn, "dir", false);
102 QList<QTreeWidgetItem *> treeItemList;
104 m_rx.setPattern("has no children\\.$");
106 while (m_console->read(m_conn) > 0) {
107 char *p = m_console->msg(m_conn);
109 strip_trailing_junk(p);
110 if (*p == '$' || !*p) { continue; }
112 if (m_rx.indexIn(QString(p)) != -1) { continue; }
116 skip_nonspaces(&p); /* permissions */
118 bstrncpy(modes, l, sizeof(modes));
120 skip_nonspaces(&p); /* link count */
124 skip_nonspaces(&p); /* user */
127 bstrncpy(user, l, sizeof(user));
129 skip_nonspaces(&p); /* group */
131 bstrncpy(group, l, sizeof(group));
134 skip_nonspaces(&p); /* size */
136 bstrncpy(size, l, sizeof(size));
139 skip_nonspaces(&p); /* date/time */
143 bstrncpy(date, l, sizeof(date));
146 bstrncpy(marked, "*", sizeof(marked));
149 bstrncpy(marked, " ", sizeof(marked));
151 split_path_and_filename(p, &path, &pnl, &file, &fnl);
153 item << "" << file << modes << user << group << size << date;
154 if (item[1].endsWith("/")) {
155 addDirectory(item[1]);
157 QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
158 ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
159 if (strcmp(marked, "*") == 0) {
160 ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
161 ti->setData(0, Qt::UserRole, true);
163 ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
164 ti->setData(0, Qt::UserRole, false);
166 treeItemList.append(ti);
169 fileWidget->insertTopLevelItems(0, treeItemList);
170 for (int i=0; i<7; i++) {
171 fileWidget->resizeColumnToContents(i);
174 free_pool_memory(file);
175 free_pool_memory(path);
180 * Function called from fill directory when a directory is found to see if this
181 * directory exists in the directory pane and then add it to the directory pane
183 void restorePage::addDirectory(QString &newdirr)
185 QString newdir = newdirr;
186 QString fullpath = m_cwd + newdirr;
189 if (mainWin->m_miscDebug) {
190 QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
194 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
197 if (isWin32Path(fullpath)) {
198 if (mainWin->m_miscDebug) Pmsg0(dbglvl, "Windows drive\n");
199 if (fullpath.left(1) == "/") {
200 fullpath.replace(0, 1, ""); /* strip leading / */
202 /* If drive and not already in add it */
203 if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
204 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
205 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
206 item->setText(0, fullpath.toUtf8().data());
207 if (mainWin->m_miscDebug) {
208 Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
210 m_dirPaths.insert(fullpath, item);
211 m_dirTreeItems.insert(item, fullpath);
212 directoryWidget->setCurrentItem(NULL);
215 // Unix add / first if not already there
216 if (m_dirPaths.empty()) {
217 QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
218 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
221 item->setText(0, text.toUtf8().data());
222 if (mainWin->m_miscDebug) {
223 Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
225 m_dirPaths.insert(text, item);
226 m_dirTreeItems.insert(item, text);
230 /* Does it already exist ?? */
231 if (!m_dirPaths.contains(fullpath)) {
232 QTreeWidgetItem *item = NULL;
233 if (isWin32Path(fullpath)) {
234 /* this is the base widget */
235 item = new QTreeWidgetItem(directoryWidget);
236 item->setText(0, fullpath.toUtf8().data());
237 if (mainWin->m_miscDebug) Pmsg1(dbglvl, "Windows: %s\n", fullpath.toUtf8().data());
238 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
240 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
242 /* new directories to add */
243 item = new QTreeWidgetItem(parent);
244 item->setText(0, newdir.toUtf8().data());
245 item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
246 directoryWidget->expandItem(parent);
247 if (mainWin->m_miscDebug) {
248 Pmsg1(dbglvl, "%s\n", newdir.toUtf8().data());
252 if (mainWin->m_miscDebug) {
253 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
256 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
260 /* insert into both forward and reverse hash */
262 if (mainWin->m_miscDebug) {
263 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
265 m_dirPaths.insert(fullpath, item);
266 m_dirTreeItems.insert(item, fullpath);
272 * Executed when the tree item in the directory pane is changed. This will
273 * allow us to populate the file pane and make this the cwd.
275 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
276 QTreeWidgetItem * /*previousitem*/)
278 QString fullpath = m_dirTreeItems.value(currentitem);
279 statusLine->setText("");
280 if (fullpath != "") {
281 cwd(fullpath.toUtf8().data());
286 void restorePage::okButtonPushed()
289 m_console->write(m_conn, "done");
290 m_console->notify(m_conn, true);
293 mainWin->resetFocus();
297 void restorePage::cancelButtonPushed()
300 m_console->write(m_conn, "quit");
301 m_console->displayToPrompt(m_conn);
302 mainWin->set_status(tr("Canceled"));
304 m_console->notify(m_conn, true);
305 mainWin->resetFocus();
308 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
311 statusLine->setText("");
312 if (column == 0) { /* mark/unmark */
313 mainWin->waitEnter();
314 if (item->data(0, Qt::UserRole).toBool()) {
315 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
316 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
317 item->setData(0, Qt::UserRole, false);
319 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
320 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
321 item->setData(0, Qt::UserRole, true);
323 m_console->write_dir(m_conn, cmd, false);
324 if (m_console->read(m_conn) > 0) {
325 strip_trailing_junk(m_console->msg(m_conn));
326 statusLine->setText(m_console->msg(m_conn));
328 m_console->displayToPrompt(m_conn);
333 * Double clicking other than column 0 means to decend into
334 * the directory -- or nothing if it is not a directory.
336 if (item->text(1).endsWith("/")) {
337 QString fullpath = m_cwd + item->text(1);
338 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
339 if (mainWin->m_miscDebug) {
340 Pmsg1(dbglvl, "%s\n", fullpath.toUtf8().data());
343 directoryWidget->setCurrentItem(item);
345 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
348 if (mainWin->m_miscDebug) Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
354 * If up button pushed, making the parent tree widget current will call fill
357 void restorePage::upButtonPushed()
360 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
362 directoryWidget->setCurrentItem(item);
364 statusLine->setText("");
368 * Mark selected items
370 void restorePage::markButtonPushed()
372 mainWin->waitEnter();
373 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
374 QTreeWidgetItem *item;
377 statusLine->setText("");
378 foreach (item, treeItemList) {
380 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
381 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
382 m_console->write_dir(m_conn, cmd, false);
383 if (m_console->read(m_conn) > 0) {
384 strip_trailing_junk(m_console->msg(m_conn));
385 statusLine->setText(m_console->msg(m_conn));
387 Dmsg1(dbglvl, "cmd=%s\n", cmd);
388 m_console->discardToPrompt(m_conn);
391 mainWin->set_status("Nothing selected, nothing done");
392 statusLine->setText("Nothing selected, nothing done");
398 * Unmark selected items
400 void restorePage::unmarkButtonPushed()
402 mainWin->waitEnter();
403 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
404 QTreeWidgetItem *item;
407 statusLine->setText("");
408 foreach (item, treeItemList) {
410 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
411 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
412 m_console->write_dir(m_conn, cmd, false);
413 if (m_console->read(m_conn) > 0) {
414 strip_trailing_junk(m_console->msg(m_conn));
415 statusLine->setText(m_console->msg(m_conn));
417 Dmsg1(dbglvl, "cmd=%s\n", cmd);
418 m_console->discardToPrompt(m_conn);
421 mainWin->set_status(tr("Nothing selected, nothing done"));
422 statusLine->setText(tr("Nothing selected, nothing done"));
428 * Change current working directory
430 bool restorePage::cwd(const char *dir)
433 char cd_cmd[MAXSTRING];
435 mainWin->waitEnter();
436 statusLine->setText("");
437 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
438 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
439 m_console->write_dir(m_conn, cd_cmd, false);
441 if ((stat = m_console->read(m_conn)) > 0) {
442 m_cwd = m_console->msg(m_conn);
443 lineEdit->insert(m_cwd);
444 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
446 Dmsg1(dbglvl, "stat=%d\n", stat);
447 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
449 m_console->discardToPrompt(m_conn);
451 return true; /* ***FIXME*** return real status */
455 * Return cwd when in tree restore mode
457 char *restorePage::get_cwd()
460 mainWin->waitEnter();
461 m_console->write_dir(m_conn, ".pwd", false);
462 Dmsg0(dbglvl, "send: .pwd\n");
463 if ((stat = m_console->read(m_conn)) > 0) {
464 m_cwd = m_console->msg(m_conn);
465 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
467 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
468 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
470 m_console->discardToPrompt(m_conn);
472 return m_cwd.toUtf8().data();
476 * Save user settings associated with this page
478 void restorePage::writeSettings()
480 QSettings settings(m_console->m_dir->name(), "bat");
481 settings.beginGroup("RestorePage");
482 settings.setValue(m_splitText, splitter->saveState());
487 * Read and restore user settings associated with this page
489 void restorePage::readSettings()
491 m_splitText = "splitterSizes_2";
492 QSettings settings(m_console->m_dir->name(), "bat");
493 settings.beginGroup("RestorePage");
494 if (settings.contains(m_splitText)) {
495 splitter->restoreState(settings.value(m_splitText).toByteArray());