]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/restore/restore.cpp
bat: Add pattern filter and make restore to start from brestore
[bacula/bacula] / bacula / src / qt-console / restore / restore.cpp
index 13145ed16433dfcfc7cb13b92affac85a953880d..8b3dad760a83bd4fb0f682cf954c94ec85c78e68 100644 (file)
@@ -1,34 +1,32 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation plus additions
-   that are listed in the file LICENSE.
+   modify it under the terms of version three of the GNU Affero General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
 
    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Bacula® is a registered trademark of John Walker.
+   Bacula® is a registered trademark of Kern Sibbald.
    The licensor of Bacula is the Free Software Foundation Europe
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
  
 /*
- *   Version $Id$
- *
  *  Restore Class 
  *
  *   Kern Sibbald, February MMVII
 #include "bat.h"
 #include "restore.h"
 
-restoreDialog::restoreDialog(Console *console)
+static const int dbglvl = 100;
+
+restorePage::restorePage(int conn)
 {
-   m_console = console;
-  
-   m_console->setEnabled(false);
+   Dmsg1(dbglvl, "Construcing restorePage Instance connection %i\n", conn);
+   m_conn = conn;
+   QStringList titles;
+
    setupUi(this);
+   m_name = tr("Restore Select");
+   pgInitialize();
+   QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
+   thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/restore.png")));
+
+   m_console->notify(m_conn, false);          /* this should already be off */
+
    connect(fileWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), 
            this, SLOT(fileDoubleClicked(QTreeWidgetItem *, int)));
+   connect(directoryWidget, SIGNAL(
+           currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+           this, SLOT(directoryItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+   connect(upButton, SIGNAL(pressed()), this, SLOT(upButtonPushed()));
+   connect(markButton, SIGNAL(pressed()), this, SLOT(markButtonPushed()));
+   connect(unmarkButton, SIGNAL(pressed()), this, SLOT(unmarkButtonPushed()));
+   connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
+   connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
+
+   fileWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
+   fileWidget->addAction(actionMark);
+   fileWidget->addAction(actionUnMark);
+   connect(actionMark, SIGNAL(triggered()), this, SLOT(markButtonPushed()));
+   connect(actionUnMark, SIGNAL(triggered()), this, SLOT(unmarkButtonPushed()));
+
    setFont(m_console->get_font());
-   m_console->displayToPrompt();
+   m_console->displayToPrompt(m_conn);
+
+   titles << tr("Mark") << tr("File") << tr("Mode") << tr("User") 
+          << tr("Group") << tr("Size") << tr("Date");
+   fileWidget->setHeaderLabels(titles);
+
+   get_cwd();
+
+   readSettings();
+   /* wait was entered from pre-restore 
+    * will exit, but will reenter in fillDirectory */
+   mainWin->waitExit();
    fillDirectory();
+   dockPage();
+   setCurrent();
    this->show();
+   if (mainWin->m_miscDebug) Pmsg0(000, "Leave restorePage\n");
+}
+
+restorePage::~restorePage()
+{
+   writeSettings();
 }
 
 /*
  * Fill the fileWidget box with the contents of the current directory
  */
-void restoreDialog::fillDirectory()
+void restorePage::fillDirectory()
 {
-   char cd_cmd[MAXSTRING];
+   mainWin->waitEnter();
    char modes[20], user[20], group[20], size[20], date[30];
    char marked[10];
    int pnl, fnl;
    POOLMEM *file = get_pool_memory(PM_FNAME);
    POOLMEM *path = get_pool_memory(PM_FNAME);
-   QStringList titles;
-
-   titles << "Mark" << "File" << "Mode" << "User" << "Group" << "Size" << "Date";
-   fileWidget->setHeaderLabels(titles);
 
-   char *dir = get_cwd();
-   bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"\n", dir);
-   Dmsg2(100, "dir=%s cmd=%s\n", dir, cd_cmd);
-   m_console->write_dir(cd_cmd);
-   m_console->discardToPrompt();
-
-   m_console->write_dir("dir");
-   QList<QTreeWidgetItem *> items;
+   fileWidget->clear();
+   m_console->write_dir(m_conn, "dir", false);
+   QList<QTreeWidgetItem *> treeItemList;
    QStringList item;
-   while (m_console->read() > 0) {
-      char *p = m_console->msg();
+   m_rx.setPattern("has no children\\.$");
+   bool first = true;
+   while (m_console->read(m_conn) > 0) {
+      char *p = m_console->msg(m_conn);
       char *l;
       strip_trailing_junk(p);
-      if (*p == '$' || !*p) {
-         continue;
+      if (*p == '$' || !*p) { continue; }
+      if (first) {
+         if (m_rx.indexIn(QString(p)) != -1) { continue; }
+         first = false;
       }
       l = p;
       skip_nonspaces(&p);             /* permissions */
@@ -123,71 +160,349 @@ void restoreDialog::fillDirectory()
       split_path_and_filename(p, &path, &pnl, &file, &fnl);
       item.clear();
       item << "" << file << modes << user << group << size << date;
+      if (item[1].endsWith("/")) {
+         addDirectory(item[1]);
+      }
       QTreeWidgetItem *ti = new QTreeWidgetItem((QTreeWidget *)0, item);
       ti->setTextAlignment(5, Qt::AlignRight); /* right align size */
-      items.append(ti);
+      if (strcmp(marked, "*") == 0) {
+         ti->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
+         ti->setData(0, Qt::UserRole, true);
+      } else {
+         ti->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
+         ti->setData(0, Qt::UserRole, false);
+      }
+      treeItemList.append(ti);
    }
    fileWidget->clear();
-   fileWidget->insertTopLevelItems(0, items);
+   fileWidget->insertTopLevelItems(0, treeItemList);
+   for (int i=0; i<7; i++) {
+      fileWidget->resizeColumnToContents(i);
+   }
 
    free_pool_memory(file);
    free_pool_memory(path);
+   mainWin->waitExit();
 }
 
-void restoreDialog::accept()
+/*
+ * Function called from fill directory when a directory is found to see if this
+ * directory exists in the directory pane and then add it to the directory pane
+ */
+void restorePage::addDirectory(QString &newdirr)
+{
+   QString newdir = newdirr;
+   QString fullpath = m_cwd + newdirr;
+   bool ok = true;
+   bool windrive = false;
+
+   if (mainWin->m_miscDebug) {
+      QString msg = QString(tr("In addDirectory cwd \"%1\" newdir \"%2\" fullpath \"%3\"\n"))
+                    .arg(m_cwd)
+                    .arg(newdir)
+                    .arg(fullpath);
+      Pmsg0(dbglvl, msg.toUtf8().data());
+   }
+
+   if (isWin32Path(newdir)) {
+      /* this is a windows drive */
+      if (mainWin->m_miscDebug) {
+         Pmsg0(dbglvl, "Found windows drive\n");
+      }
+      windrive = true;
+   }
+   
+   if (windrive) {
+      if (fullpath.left(1) == "/") {
+         fullpath.replace(0, 1, "");           /* strip leading / */
+      }
+      /* If drive and not already in add it */
+      if (fullpath.length() == 3 && !m_dirPaths.contains(fullpath)) {
+         QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
+         item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
+         item->setText(0, fullpath.toUtf8().data());
+         if (mainWin->m_miscDebug) {
+            Pmsg1(dbglvl, "Pre Inserting %s\n",fullpath.toUtf8().data());
+         }
+         m_dirPaths.insert(fullpath, item);
+         m_dirTreeItems.insert(item, fullpath);
+         directoryWidget->setCurrentItem(NULL);
+      }
+   } else {
+      // Unix add / first if not already there 
+      if (m_dirPaths.empty()) {
+         QTreeWidgetItem *item = new QTreeWidgetItem(directoryWidget);
+         item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
+            
+         QString text("/");
+         item->setText(0, text.toUtf8().data());
+         if (mainWin->m_miscDebug) {
+            Pmsg1(dbglvl, "Pre Inserting %s\n",text.toUtf8().data());
+         }
+         m_dirPaths.insert(text, item);
+         m_dirTreeItems.insert(item, text);
+      }
+   }
+   /* Does it already exist ?? */
+   if (!m_dirPaths.contains(fullpath)) {
+      QTreeWidgetItem *item = NULL;
+      if (windrive) {
+         /* this is the base widget */
+         item = new QTreeWidgetItem(directoryWidget);
+         item->setText(0, fullpath.toUtf8().data());
+         item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
+      } else {
+         QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
+         if (parent) {
+            /* new directories to add */
+            item = new QTreeWidgetItem(parent);
+            item->setText(0, newdir.toUtf8().data());
+            item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
+            directoryWidget->expandItem(parent);
+         } else {
+            ok = false;
+            if (mainWin->m_miscDebug) {
+               QString msg = QString(tr("In else of if parent cwd \"%1\" newdir \"%2\"\n"))
+                    .arg(m_cwd)
+                    .arg(newdir);
+               Pmsg0(dbglvl, msg.toUtf8().data());
+            }
+         }
+      }
+      /* insert into both forward and reverse hash */
+      if (ok) {
+         if (mainWin->m_miscDebug) {
+            Pmsg1(dbglvl, "Inserting %s\n",fullpath.toUtf8().data());
+         }
+         m_dirPaths.insert(fullpath, item);
+         m_dirTreeItems.insert(item, fullpath);
+      }
+   }
+}
+
+/*
+ * Executed when the tree item in the directory pane is changed.  This will
+ * allow us to populate the file pane and make this the cwd.
+ */
+void restorePage::directoryItemChanged(QTreeWidgetItem *currentitem,
+                                         QTreeWidgetItem * /*previousitem*/)
+{
+   QString fullpath = m_dirTreeItems.value(currentitem);
+   statusLine->setText("");
+   if (fullpath != "") {
+      cwd(fullpath.toUtf8().data());
+      fillDirectory();
+   }
+}
+
+void restorePage::okButtonPushed()
 {
    this->hide();
-   m_console->write("done");
-   delete this;
-   m_console->setEnabled(true);
+   m_console->write(m_conn, "done");
+   m_console->notify(m_conn, true);
+   setConsoleCurrent();
+   closeStackPage();
    mainWin->resetFocus();
 }
 
 
-void restoreDialog::reject()
+void restorePage::cancelButtonPushed()
 {
    this->hide();
-   m_console->write("quit");
-   mainWin->set_status("Canceled");
-   delete this;
-   m_console->setEnabled(true);
+   m_console->write(m_conn, "quit");
+   m_console->displayToPrompt(m_conn);
+   mainWin->set_status(tr("Canceled"));
+   closeStackPage();
+   m_console->notify(m_conn, true);
    mainWin->resetFocus();
 }
 
-void restoreDialog::fileDoubleClicked(QTreeWidgetItem *item, int column)
+void restorePage::fileDoubleClicked(QTreeWidgetItem *item, int column)
 {
    char cmd[1000];
-//   printf("cwd=%s Text=%s column=%d\n", m_cwd.toUtf8().data(), 
-//          item->text(1).toUtf8().data(), column);
+   statusLine->setText("");
    if (column == 0) {                 /* mark/unmark */
-      if (item->text(0) == "*") {
-         bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"\n", item->text(1).toUtf8().data());
-         item->setText(0, " ");
+      mainWin->waitEnter();
+      if (item->data(0, Qt::UserRole).toBool()) {
+         bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
+         item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
+         item->setData(0, Qt::UserRole, false);
       } else {
-         bsnprintf(cmd, sizeof(cmd), "mark \"%s\"\n", item->text(1).toUtf8().data());
-         item->setText(0, "*");
+         bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
+         item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
+         item->setData(0, Qt::UserRole, true);
+      }
+      m_console->write_dir(m_conn, cmd, false);
+      if (m_console->read(m_conn) > 0) {
+         strip_trailing_junk(m_console->msg(m_conn));
+         statusLine->setText(m_console->msg(m_conn));
       }
-      m_console->write(cmd);
-//    printf("cmd=%s", cmd);
-      m_console->displayToPrompt();
+      m_console->displayToPrompt(m_conn);
+      mainWin->waitExit();
       return;
+   }    
+   /* 
+    * Double clicking other than column 0 means to decend into
+    *  the directory -- or nothing if it is not a directory.
+    */
+   if (item->text(1).endsWith("/")) {
+      QString fullpath = m_cwd + item->text(1);
+      QTreeWidgetItem *item = m_dirPaths.value(fullpath);
+      if (item) {
+         directoryWidget->setCurrentItem(item);
+      } else {
+         QString msg = QString("DoubleClick else of item column %1 fullpath %2\n")
+              .arg(column,10)
+              .arg(fullpath);
+         Pmsg0(dbglvl, msg.toUtf8().data());
+      }
    }
 }
 
+/*
+ * If up button pushed, making the parent tree widget current will call fill
+ * directory.
+ */
+void restorePage::upButtonPushed()
+{
+   cwd("..");
+   QTreeWidgetItem *item = m_dirPaths.value(m_cwd);
+   if (item) {
+      directoryWidget->setCurrentItem(item);
+   }
+   statusLine->setText("");
+}
+
+/*
+ * Mark selected items
+ */
+void restorePage::markButtonPushed()
+{
+   mainWin->waitEnter();
+   QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
+   QTreeWidgetItem *item;
+   char cmd[1000];
+   int count = 0;
+   statusLine->setText("");
+   foreach (item, treeItemList) {
+      count++;
+      bsnprintf(cmd, sizeof(cmd), "mark \"%s\"", item->text(1).toUtf8().data());
+      item->setIcon(0, QIcon(QString::fromUtf8(":images/check.png")));
+      m_console->write_dir(m_conn, cmd, false);
+      if (m_console->read(m_conn) > 0) {
+         strip_trailing_junk(m_console->msg(m_conn));
+         statusLine->setText(m_console->msg(m_conn));
+      }
+      Dmsg1(dbglvl, "cmd=%s\n", cmd);
+      m_console->discardToPrompt(m_conn);
+   }
+   if (count == 0) {
+      mainWin->set_status("Nothing selected, nothing done");
+      statusLine->setText("Nothing selected, nothing done");
+   }
+   mainWin->waitExit();
+}
+
+/*
+ * Unmark selected items
+ */
+void restorePage::unmarkButtonPushed()
+{
+   mainWin->waitEnter();
+   QList<QTreeWidgetItem *> treeItemList = fileWidget->selectedItems();
+   QTreeWidgetItem *item;
+   char cmd[1000];
+   int count = 0;
+   statusLine->setText("");
+   foreach (item, treeItemList) {
+      count++;
+      bsnprintf(cmd, sizeof(cmd), "unmark \"%s\"", item->text(1).toUtf8().data());
+      item->setIcon(0, QIcon(QString::fromUtf8(":images/unchecked.png")));
+      m_console->write_dir(m_conn, cmd, false);
+      if (m_console->read(m_conn) > 0) {
+         strip_trailing_junk(m_console->msg(m_conn));
+         statusLine->setText(m_console->msg(m_conn));
+      }
+      Dmsg1(dbglvl, "cmd=%s\n", cmd);
+      m_console->discardToPrompt(m_conn);
+   }
+   if (count == 0) {
+      mainWin->set_status(tr("Nothing selected, nothing done"));
+      statusLine->setText(tr("Nothing selected, nothing done"));
+   }
+   mainWin->waitExit();
+}
+
+/*
+ * Change current working directory 
+ */
+bool restorePage::cwd(const char *dir)
+{
+   int stat;
+   char cd_cmd[MAXSTRING];
+
+   mainWin->waitEnter();
+   statusLine->setText("");
+   bsnprintf(cd_cmd, sizeof(cd_cmd), "cd \"%s\"", dir);
+   Dmsg2(dbglvl, "dir=%s cmd=%s\n", dir, cd_cmd);
+   m_console->write_dir(m_conn, cd_cmd, false);
+   lineEdit->clear();
+   if ((stat = m_console->read(m_conn)) > 0) {
+      m_cwd = m_console->msg(m_conn);
+      lineEdit->insert(m_cwd);
+      Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
+   } else {
+      Dmsg1(dbglvl, "stat=%d\n", stat);
+      QMessageBox::critical(this, "Error", tr("cd command failed"), QMessageBox::Ok);
+   }
+   m_console->discardToPrompt(m_conn);
+   mainWin->waitExit();
+   return true;  /* ***FIXME*** return real status */
+}
+
 /*
  * Return cwd when in tree restore mode 
  */
-char *restoreDialog::get_cwd()
+char *restorePage::get_cwd()
 {
    int stat;
-   m_console->write_dir(".pwd");
-   Dmsg0(100, "send: .pwd\n");
-   if ((stat = m_console->read()) > 0) {
-      m_cwd = m_console->msg();
-      Dmsg2(100, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg());
+   mainWin->waitEnter();
+   m_console->write_dir(m_conn, ".pwd", false);
+   Dmsg0(dbglvl, "send: .pwd\n");
+   if ((stat = m_console->read(m_conn)) > 0) {
+      m_cwd = m_console->msg(m_conn);
+      Dmsg2(dbglvl, "cwd=%s msg=%s\n", m_cwd.toUtf8().data(), m_console->msg(m_conn));
    } else {
-      Dmsg1(000, "stat=%d\n", stat);
+      Dmsg1(dbglvl, "Something went wrong read stat=%d\n", stat);
+      QMessageBox::critical(this, "Error", tr(".pwd command failed"), QMessageBox::Ok);
    }
-   m_console->displayToPrompt(); 
+   m_console->discardToPrompt(m_conn); 
+   mainWin->waitExit();
    return m_cwd.toUtf8().data();
 }
+
+/*
+ * Save user settings associated with this page
+ */
+void restorePage::writeSettings()
+{
+   QSettings settings(m_console->m_dir->name(), "bat");
+   settings.beginGroup("RestorePage");
+   settings.setValue(m_splitText, splitter->saveState());
+   settings.endGroup();
+}
+
+/*
+ * Read and restore user settings associated with this page
+ */
+void restorePage::readSettings()
+{
+   m_splitText = "splitterSizes_2";
+   QSettings settings(m_console->m_dir->name(), "bat");
+   settings.beginGroup("RestorePage");
+   if (settings.contains(m_splitText)) { 
+      splitter->restoreState(settings.value(m_splitText).toByteArray());
+   }
+   settings.endGroup();
+}