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;
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 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 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 Pmsg1(dbglvl, "%s\n", newdir.toUtf8().data());
259 if (mainWin->m_miscDebug) {
260 QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
263 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
267 /* insert into both forward and reverse hash */
269 if (mainWin->m_miscDebug) {
270 Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
272 m_dirPaths.insert(fullpath, item);
273 m_dirTreeItems.insert(item, fullpath);
279 * Executed when the tree item in the directory pane is changed. This will
280 * allow us to populate the file pane and make this the cwd.
282 void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
283 QTreeWidgetItem * /*previousitem*/)
285 QString fullpath = m_dirTreeItems.value(currentitem);
286 statusLine->setText("");
287 if (fullpath != "") {
288 cwd(fullpath.toUtf8().data());
293 void restorePage::okButtonPushed()
296 m_console->write(m_conn, "done");
297 m_console->notify(m_conn, true);
300 mainWin->resetFocus();
304 void restorePage::cancelButtonPushed()
307 m_console->write(m_conn, "quit");
308 m_console->displayToPrompt(m_conn);
309 mainWin->set_status(tr("Canceled"));
311 m_console->notify(m_conn, true);
312 mainWin->resetFocus();
315 void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
318 statusLine->setText("");
319 if (column == 0) { /* mark/unmark */
320 mainWin->waitEnter();
321 if (item->data(0, Qt::UserRole).toBool()) {
322 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
323 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
324 item->setData(0, Qt::UserRole, false);
326 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
327 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
328 item->setData(0, Qt::UserRole, true);
330 m_console->write_dir(m_conn, cmd, false);
331 if (m_console->read(m_conn) > 0) {
332 strip_trailing_junk(m_console->msg(m_conn));
333 statusLine->setText(m_console->msg(m_conn));
335 m_console->displayToPrompt(m_conn);
340 * Double clicking other than column 0 means to decend into
341 * the directory -- or nothing if it is not a directory.
343 if (item->text(1).endsWith("/")) {
344 QString fullpath = m_cwd + item->text(1);
345 QTreeWidgetItem *item = m_dirPaths.value(fullpath);
346 Pmsg1(dbglvl, "%s\n", fullpath.toUtf8().data());
348 directoryWidget->setCurrentItem(item);
350 QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
353 Pmsg1(dbglvl, "%s\n", msg.toUtf8().data());
359 * If up button pushed, making the parent tree widget current will call fill
362 void restorePage::upButtonPushed()
365 QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
367 directoryWidget->setCurrentItem(item);
369 statusLine->setText("");
373 * Mark selected items
375 void restorePage::markButtonPushed()
377 mainWin->waitEnter();
378 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
379 QTreeWidgetItem *item;
382 statusLine->setText("");
383 foreach (item, treeItemList) {
385 bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
386 item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
387 m_console->write_dir(m_conn, cmd, false);
388 if (m_console->read(m_conn) > 0) {
389 strip_trailing_junk(m_console->msg(m_conn));
390 statusLine->setText(m_console->msg(m_conn));
392 Dmsg1(dbglvl, "cmd=%s\n", cmd);
393 m_console->discardToPrompt(m_conn);
396 mainWin->set_status("Nothing selected, nothing done");
397 statusLine->setText("Nothing selected, nothing done");
403 * Unmark selected items
405 void restorePage::unmarkButtonPushed()
407 mainWin->waitEnter();
408 QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
409 QTreeWidgetItem *item;
412 statusLine->setText("");
413 foreach (item, treeItemList) {
415 bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
416 item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
417 m_console->write_dir(m_conn, cmd, false);
418 if (m_console->read(m_conn) > 0) {
419 strip_trailing_junk(m_console->msg(m_conn));
420 statusLine->setText(m_console->msg(m_conn));
422 Dmsg1(dbglvl, "cmd=%s\n", cmd);
423 m_console->discardToPrompt(m_conn);
426 mainWin->set_status(tr("Nothing selected, nothing done"));
427 statusLine->setText(tr("Nothing selected, nothing done"));
433 * Change current working directory
435 bool restorePage::cwd(const char *dir)
438 char cd_cmd[MAXSTRING];
440 mainWin->waitEnter();
441 statusLine->setText("");
442 bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
443 Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
444 m_console->write_dir(m_conn, cd_cmd, false);
446 if ((stat = m_console->read(m_conn)) > 0) {
447 m_cwd = m_console->msg(m_conn);
448 lineEdit->insert(m_cwd);
449 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
451 Dmsg1(dbglvl, "stat=%d\n", stat);
452 QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
454 m_console->discardToPrompt(m_conn);
456 return true; /* ***FIXME*** return real status */
460 * Return cwd when in tree restore mode
462 char *restorePage::get_cwd()
465 mainWin->waitEnter();
466 m_console->write_dir(m_conn, ".pwd", false);
467 Dmsg0(dbglvl, "send: .pwd\n");
468 if ((stat = m_console->read(m_conn)) > 0) {
469 m_cwd = m_console->msg(m_conn);
470 Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
472 Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
473 QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
475 m_console->discardToPrompt(m_conn);
477 return m_cwd.toUtf8().data();
481 * Save user settings associated with this page
483 void restorePage::writeSettings()
485 QSettings settings(m_console->m_dir->name(), "bat");
486 settings.beginGroup("RestorePage");
487 settings.setValue(m_splitText, splitter->saveState());
492 * Read and restore user settings associated with this page
494 void restorePage::readSettings()
496 m_splitText = "splitterSizes_2";
497 QSettings settings(m_console->m_dir->name(), "bat");
498 settings.beginGroup("RestorePage");
499 if (settings.contains(m_splitText)) {
500 splitter->restoreState(settings.value(m_splitText).toByteArray());