]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/restore/restoretree.cpp
Fix bat browser to ignore copy jobs. Fix bug #1604
[bacula/bacula] / bacula / src / qt-console / restore / restoretree.cpp
index a3f12108524252b8864ac173652d85f1d75667c3..f39df9bcfe8a993c6adedb4119643410939fa86c 100644 (file)
@@ -1,12 +1,12 @@
 /*
    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
+   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.
 
    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.cpp 4945 2007-05-31 01:24:28Z bartleyd2 $
  *
  *  Restore Class 
  *
 #include "bat.h"
 #include "restoretree.h"
 #include "pages.h"
-#include "restoretreerun.h"
 
 restoreTree::restoreTree()
 {
    setupUi(this);
-   m_name = "Version Browser";
+   m_name = tr("Version Browser");
    pgInitialize();
    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
    thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
 
-   m_closeable = true;
    m_populated = false;
 
-   readSettings();
-   dockPage();
-   m_winRegExpDrive.setPattern("^[a-z]:/$");
-   m_winRegExpPath.setPattern("^[a-z]:/");
-   m_slashregex.setPattern("/");
    m_debugCnt = 0;
    m_debugTrap = true;
+
+   QGridLayout *gridLayout = new QGridLayout(this);
+   gridLayout->setSpacing(6);
+   gridLayout->setMargin(9);
+   gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+
+   m_splitter = new QSplitter(Qt::Vertical, this);
+   QScrollArea *area = new QScrollArea();
+   area->setObjectName(QString::fromUtf8("area"));
+   area->setWidget(widget);
+   area->setWidgetResizable(true);
+   m_splitter->addWidget(area);
+   m_splitter->addWidget(splitter);
+   splitter->setChildrenCollapsible(false);
+
+   gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
+
+   /* progress widgets */
+   prBar1->setVisible(false);
+   prBar2->setVisible(false);
+   prLabel1->setVisible(false);
+   prLabel2->setVisible(false);
+
+   /* Set Defaults for check and spin for limits */
+   limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
+   limitSpinBox->setValue(mainWin->m_recordLimitVal);
+   daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
+   daysSpinBox->setValue(mainWin->m_daysLimitVal);
+   readSettings();
+   m_nullFileNameId = -1;
+   dockPage();
+   setCurrent();
 }
 
 restoreTree::~restoreTree()
@@ -71,8 +95,15 @@ restoreTree::~restoreTree()
 void restoreTree::setupPage()
 {
    connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
-   connect(testButton, SIGNAL(pressed()), this, SLOT(testButtonPushed()));
+   connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
    connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
+   connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
+   connect(clientCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
+   connect(fileSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
+   connect(limitCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
+   connect(daysCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
+   connect(daysSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
+   connect(limitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
    connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
            this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
    connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
@@ -81,23 +112,48 @@ void restoreTree::setupPage()
            this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
    connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
            this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
+   connect(jobTable, SIGNAL(cellClicked(int, int)),
+           this, SLOT(jobTableCellClicked(int, int)));
 
-   QStringList titles = QStringList() << "Directories";
+   QStringList titles = QStringList() << tr("Directories");
    directoryTree->setHeaderLabels(titles);
    clientCombo->addItems(m_console->client_list);
-   fileSetCombo->addItem("Any");
+   fileSetCombo->addItem(tr("Any"));
    fileSetCombo->addItems(m_console->fileset_list);
+   jobCombo->addItem(tr("Any"));
    jobCombo->addItems(m_console->job_list);
 
    directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
 }
 
+void restoreTree::updateRefresh()
+{
+   if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
+   m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
+                       || (m_prevClientCombo != clientCombo->currentText())
+                       || (m_prevFileSetCombo != fileSetCombo->currentText()
+                       || (m_prevLimitSpinBox != limitSpinBox->value())
+                       || (m_prevDaysSpinBox != daysSpinBox->value())
+                       || (m_prevLimitCheckState != limitCheckBox->checkState())
+                       || (m_prevDaysCheckState != daysCheckBox->checkState())
+   );
+   if (m_dropdownChanged) {
+      if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
+      refreshLabel->setText(tr("Refresh From Re-Select"));
+   } else {
+      if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
+      refreshLabel->setText(tr("Refresh From JobChecks"));
+   }
+}
+
 /*
  * When refresh button is pushed, perform a query getting the directories and
  * use parseDirectory and addDirectory to populate the directory tree with items.
  */
 void restoreTree::populateDirectoryTree()
 {
+   m_debugTrap = true;
+   m_debugCnt = 0;
    m_slashTrap = false;
    m_dirPaths.clear();
    directoryTree->clear();
@@ -112,66 +168,131 @@ void restoreTree::populateDirectoryTree()
    m_versionExceptionHash.clear();
    m_directoryIconStateHash.clear();
 
+   updateRefresh();
+   int taskcount = 3, ontask = 1;
+   if (m_dropdownChanged) taskcount += 1;
    
-   int clientIndex = clientCombo->currentIndex();
-   int fileSetIndex = fileSetCombo->currentIndex();
-   QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
-   QString clientComboText = clientCombo->itemText(clientIndex);
-   QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
-   if ((m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText)) {
-      m_prevJobCombo =  jobComboText;
-      m_prevClientCombo = clientComboText;
-      m_prevFileSetCombo = fileSetComboText;
-      if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
-
-      m_condition = " Job.name = '" + jobCombo->itemText(jobCombo->currentIndex()) + "'";
-      if ((clientIndex >= 0) && (clientCombo->itemText(clientIndex) != "Any")) {
-         m_condition.append(" AND Client.Name='" + clientCombo->itemText(clientIndex) + "'");
-      }
-      if ((fileSetIndex >= 0) && (fileSetCombo->itemText(fileSetIndex) != "Any")) {
-         m_condition.append(" AND FileSet.FileSet='" + fileSetCombo->itemText(fileSetIndex) + "'");
-      }
-      m_jobQueryPart =
-         " LEFT OUTER JOIN Client ON (Job.ClientId=Client.ClientId)"
-         " LEFT OUTER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
-         " WHERE" + m_condition +
-         " AND Job.purgedfiles=0";
-      m_jobQuery =
-         "SELECT Job.Jobid"
-         " From Job" + m_jobQueryPart;
-      if (mainWin->m_sqlDebug) {
-         Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
-      }
+   /* Set progress bars and repaint */
+   prBar1->setVisible(true);
+   prBar1->setRange(0,taskcount);
+   prBar1->setValue(0);
+   prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
+   prLabel1->setVisible(true);
+   prBar2->setVisible(true);
+   prBar2->setRange(0,0);
+   prLabel2->setText(tr("Querying Database"));
+   prLabel2->setVisible(true);
+   repaint();
+
+   if (m_dropdownChanged) {
+      m_prevJobCombo = jobCombo->currentText();
+      m_prevClientCombo = clientCombo->currentText();
+      m_prevFileSetCombo = fileSetCombo->currentText();
+      m_prevLimitSpinBox = limitSpinBox->value();
+      m_prevDaysSpinBox = daysSpinBox->value();
+      m_prevLimitCheckState = limitCheckBox->checkState();
+      m_prevDaysCheckState = daysCheckBox->checkState();
+      updateRefresh();
+      prBar1->setValue(ontask++);
+      prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
+      prBar2->setValue(0);
+      prBar2->setRange(0,0);
+      prLabel2->setText(tr("Querying Jobs"));
+      repaint();
       populateJobTable();
-      setJobsCheckedList();
-   } else {
-      setJobsCheckedList();
    }
-
-   QString cmd =
-      "SELECT DISTINCT Path.Path AS Path"
-      " FROM Path"
-      " LEFT OUTER JOIN File ON (File.PathId=Path.PathId)"
-      " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
-      " WHERE Job.Jobid IN (" + m_jobQuery + ")"
-      " ORDER BY Path";
-   if (mainWin->m_sqlDebug) {
-      Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-   }
-   QStringList directories;
-   if (m_console->sql_cmd(cmd, directories)) {
-      if (mainWin->m_miscDebug) {
-         Pmsg1(000, "Done with query %i directories\n", directories.count());
+   setJobsCheckedList();
+   if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
+
+   if (m_checkedJobs != "") {
+      /* First get the filenameid of where the nae is null.  These will be the directories
+       * This could be done in a subquery but postgres's query analyzer won't do the right
+       * thing like I want */
+      if (m_nullFileNameId == -1) {
+         QString cmd = "SELECT FilenameId FROM Filename WHERE name=''";
+         if (mainWin->m_sqlDebug)
+            Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+         QStringList qres;
+         if (m_console->sql_cmd(cmd, qres)) {
+            if (qres.count()) {
+               QStringList fieldlist = qres[0].split("\t");
+               QString field = fieldlist[0];
+               bool ok;
+               int val = field.toInt(&ok, 10);
+               if (ok) m_nullFileNameId = val;
+            }
+         }
       }
-      foreach(QString directory, directories) {
-         m_debugCnt += 1;
-         parseDirectory(directory);
+      /* now create the query to get the list of paths */
+      QString cmd =
+         "SELECT DISTINCT Path.Path AS Path, File.PathId AS PathId"
+         " FROM File"
+         " INNER JOIN Path ON (File.PathId=Path.PathId)";
+      if (m_nullFileNameId != -1)
+         cmd += " WHERE File.FilenameId=" + QString("%1").arg(m_nullFileNameId);
+      else
+         cmd += " WHERE File.FilenameId IN (SELECT FilenameId FROM Filename WHERE Name='')";
+      cmd += " AND File.Jobid IN (" + m_checkedJobs + ")"
+         " ORDER BY Path";
+      if (mainWin->m_sqlDebug)
+         Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+      prBar1->setValue(ontask++);
+      prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
+      prBar2->setValue(0);
+      prBar2->setRange(0,0);
+      prLabel2->setText(tr("Querying for Directories"));
+      repaint();
+      QStringList results;
+      m_directoryPathIdHash.clear();
+      bool querydone = false;
+      if (m_console->sql_cmd(cmd, results)) {
+         if (!querydone) {
+            querydone = true;
+            prLabel2->setText(tr("Processing Directories"));
+            prBar2->setRange(0,results.count());
+            repaint();
+         }
+         if (mainWin->m_miscDebug)
+            Pmsg1(000, "Done with query %i results\n", results.count());
+         QStringList fieldlist;
+         foreach(QString resultline, results) {
+            /* Update progress bar periodically */
+            if ((++m_debugCnt && 0x3FF) == 0) {
+               prBar2->setValue(m_debugCnt);
+            }
+            fieldlist = resultline.split("\t");
+            int fieldcnt = 0;
+            QString field;
+            /* Iterate through fields in the record */
+            foreach (field, fieldlist) {
+               if (fieldcnt == 0 ) {
+                  parseDirectory(field);
+               } else if (fieldcnt == 1) {
+                  bool ok;
+                  int pathid = field.toInt(&ok, 10);
+                  if (ok)
+                     m_directoryPathIdHash.insert(fieldlist[0], pathid);
+               }
+               fieldcnt += 1;
+            }
+         }
+      } else {
+         return;
       }
+   } else {
+     QMessageBox::warning(this, "Bat",
+        tr("No jobs were selected in the job query !!!.\n"
+      "Press OK to continue"),
+      QMessageBox::Ok );
    }
+   prBar1->setVisible(false);
+   prBar2->setVisible(false);
+   prLabel1->setVisible(false);
+   prLabel2->setVisible(false);
 }
 
 /*
- *  Function to set m_jobQuery from the jobs that are checked in the table
+ *  Function to set m_checkedJobs from the jobs that are checked in the table
  *  of jobs
  */     
 void restoreTree::setJobsCheckedList()
@@ -188,10 +309,14 @@ void restoreTree::setJobsCheckedList()
          m_JobsCheckedList += jobItem->text();
          first = false;
          jobItem->setBackground(Qt::green);
-      } else
-         jobItem->setBackground(Qt::gray);
+      } else {
+         if (jobItem->flags())
+            jobItem->setBackground(Qt::gray);
+         else
+            jobItem->setBackground(Qt::darkYellow);
+      }
    }
-   m_jobQuery = m_JobsCheckedList;
+   m_checkedJobs = m_JobsCheckedList;
 }
 
 /*
@@ -200,14 +325,14 @@ void restoreTree::setJobsCheckedList()
  */
 void restoreTree::parseDirectory(QString &dir_in)
 {
-   /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
+   /* m_debugTrap is to only print debugs for a few occurennces of calling parseDirectory
     * instead of printing out what could potentially a whole bunch */
    if (m_debugCnt > 2)
       m_debugTrap = false;
-   /* Clean up the directory string remove some funny char after last '/' */
-   QRegExp rgx("[^/]$");
-   int lastslash = rgx.indexIn(dir_in);
-   dir_in.replace(lastslash, dir_in.length()-lastslash, "");
+   /* Truncate everything after the last / */
+   if (dir_in.right(1) != "/") {
+      dir_in.truncate(dir_in.lastIndexOf("/") + 1);
+   }
    if ((mainWin->m_miscDebug) && (m_debugTrap))
       Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
 
@@ -219,7 +344,7 @@ void restoreTree::parseDirectory(QString &dir_in)
    /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/ 
     * if not added into tree, then try /etc/ and somedir/ if not added, then try
     * / and etc/ .  That should succeed, then add the ones that failed in reverse */
-   while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
+   while (((index = dir_in.lastIndexOf("/", -2)) != -1) && (!done)) {
       direct = path = dir_in;
       path.replace(index+1, dir_in.length()-index-1,"");
       direct.replace(0, index+1, "");
@@ -228,10 +353,11 @@ void restoreTree::parseDirectory(QString &dir_in)
                     .arg(dir_in.length()).arg(index).arg(path).arg(direct);
          Pmsg0(000, msg.toUtf8().data());
       }
-      if (addDirectory(path, direct)) done = true;
+      if (addDirectory(path, direct)) { done = true; }
       else {
-         if ((mainWin->m_miscDebug) && (m_debugTrap))
+         if ((mainWin->m_miscDebug) && (m_debugTrap)) {
             Pmsg0(000, "Saving for later\n");
+         }
          pathAfter.prepend(path);
          dirAfter.prepend(direct);
       }
@@ -239,15 +365,17 @@ void restoreTree::parseDirectory(QString &dir_in)
    }
 
    for (int k=0; k<pathAfter.count(); k++) {
-      if (addDirectory(pathAfter[k], dirAfter[k]))
+      if (addDirectory(pathAfter[k], dirAfter[k])) {
          if ((mainWin->m_miscDebug) && (m_debugTrap))
             Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
-      else
+      } else {
          if ((mainWin->m_miscDebug) && (m_debugTrap))
             Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
+      }
    }
 }
 
+
 /*
  * 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
@@ -267,7 +395,7 @@ bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
 
    if (!m_slashTrap) {
       /* add unix '/' directory first */
-      if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
+      if (m_dirPaths.empty() && !isWin32Path(fullPath)) {
          m_slashTrap = true;
          QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
          QString text("/");
@@ -281,17 +409,20 @@ bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
          m_dirPaths.insert(text, item);
       }
       /* no need to check for windows drive if unix */
-      if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
-         /* this is a windows drive add the base widget */
-         QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
-         item->setText(0, m_cwd);
-         item->setData(0, Qt::UserRole, QVariant(fullPath));
-         item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
-         item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
-         if ((mainWin->m_miscDebug) && (m_debugTrap)) {
-            Pmsg0(000, "Added Base \"letter\":/\n");
+      if (isWin32Path(m_cwd)) {
+         if (!m_dirPaths.contains(m_cwd)) {
+            if (m_cwd.count('/') > 1) { return false; }
+            /* this is a windows drive add the base widget */
+            QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
+            item->setText(0, m_cwd);
+            item->setData(0, Qt::UserRole, QVariant(fullPath));
+            item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
+            item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
+            if ((mainWin->m_miscDebug) && (m_debugTrap)) {
+               Pmsg0(000, "Added Base \"letter\":/\n");
+            }
+            m_dirPaths.insert(m_cwd, item);
          }
-         m_dirPaths.insert(m_cwd, item);
       }
    }
  
@@ -335,10 +466,8 @@ bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
 void restoreTree::currentStackItem()
 {
    if(!m_populated) {
-      if (!m_console->preventInUseConnect())
-         return;
       setupPage();
-      m_populated=true;
+      m_populated = true;
    }
 }
 
@@ -355,9 +484,13 @@ void restoreTree::refreshButtonPushed()
  */
 void restoreTree::jobComboChanged(int)
 {
+   if (jobCombo->currentText() == tr("Any")) {
+      fileSetCombo->setCurrentIndex(fileSetCombo->findText(tr("Any"), Qt::MatchExactly));
+      return;
+   }
    job_defaults job_defs;
 
-   (void)index;
+   //(void)index;
    job_defs.job_name = jobCombo->currentText();
    if (m_console->get_job_defaults(job_defs)) {
       fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
@@ -373,87 +506,106 @@ void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidget
    if (item == NULL)
       return;
 
-   m_fileCheckStateList.clear();
-   disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
-           this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
-   QBrush blackBrush(Qt::black);
-   QString directory = item->data(0, Qt::UserRole).toString();
-   directoryLabel->setText("Present Working Directory : " + directory);
-   QString cmd =
-      "SELECT DISTINCT Filename.Name"
-      " FROM File "
-      " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-      " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-      " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
-      " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
-      " AND Job.Jobid IN (" + m_jobQuery + ")";
-   QStringList headerlist = (QStringList() << "File Name");
    fileTable->clear();
    /* Also clear the version table here */
    versionTable->clear();
    versionFileLabel->setText("");
    versionTable->setRowCount(0);
    versionTable->setColumnCount(0);
+
+   QStringList headerlist = (QStringList() << tr("File Name") << tr("Filename Id"));
    fileTable->setColumnCount(headerlist.size());
    fileTable->setHorizontalHeaderLabels(headerlist);
-
-   if (mainWin->m_sqlDebug) {
-      Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-   }
-   QStringList results;
-   if (m_console->sql_cmd(cmd, results)) {
+   fileTable->setRowCount(0);
    
-      QTableWidgetItem* tableItem;
-      QString field;
-      QStringList fieldlist;
-      fileTable->setRowCount(results.size());
+   m_fileCheckStateList.clear();
+   disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
+           this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
+   QBrush blackBrush(Qt::black);
+   QString directory = item->data(0, Qt::UserRole).toString();
+   directoryLabel->setText(tr("Present Working Directory: %1").arg(directory));
+   int pathid = m_directoryPathIdHash.value(directory, -1);
+   if (pathid != -1) {
+      QString cmd =
+         "SELECT DISTINCT Filename.Name AS FileName, Filename.FilenameId AS FilenameId"
+         " FROM File "
+         " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
+         " WHERE File.PathId=" + QString("%1").arg(pathid) +
+         " AND File.Jobid IN (" + m_checkedJobs + ")"
+         " AND Filename.Name!=''"
+         " ORDER BY FileName";
+      if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
 
-      int row = 0;
-      /* Iterate through the record returned from the query */
-      foreach (QString resultline, results) {
-         /* Iterate through fields in the record */
-         int column = 0;
-         fieldlist = resultline.split("\t");
-         foreach (field, fieldlist) {
-            field = field.trimmed();  /* strip leading & trailing spaces */
-            tableItem = new QTableWidgetItem(field, 1);
-            /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
-             *  | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable 
-             *  | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
-            tableItem->setForeground(blackBrush);
-            /* Just in case a column ever gets added */
-            if (column == 0) {
-               Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
-               tableItem->setFlags(flag);
-               tableItem->setData(Qt::UserRole, QVariant(directory));
-               fileTable->setItem(row, column, tableItem);
-               m_fileCheckStateList.append(Qt::Unchecked);
-               tableItem->setCheckState(Qt::Unchecked);
+      QStringList results;
+      if (m_console->sql_cmd(cmd, results)) {
+      
+         QTableWidgetItem* tableItem;
+         QString field;
+         QStringList fieldlist;
+         fileTable->setRowCount(results.size());
+   
+         int row = 0;
+         /* Iterate through the record returned from the query */
+         foreach (QString resultline, results) {
+            /* Iterate through fields in the record */
+            int column = 0;
+            fieldlist = resultline.split("\t");
+            foreach (field, fieldlist) {
+               field = field.trimmed();  /* strip leading & trailing spaces */
+               tableItem = new QTableWidgetItem(field, 1);
+               /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
+                *  | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable 
+                *  | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
+               tableItem->setForeground(blackBrush);
+               /* Just in case a column ever gets added */
+               if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
+               if (column == 0) {
+                  Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
+                  tableItem->setFlags(flag);
+                  tableItem->setData(Qt::UserRole, QVariant(directory));
+                  fileTable->setItem(row, column, tableItem);
+                  m_fileCheckStateList.append(Qt::Unchecked);
+                  tableItem->setCheckState(Qt::Unchecked);
+               } else if (column == 1) {
+                  Qt::ItemFlags flag = Qt::ItemIsEnabled;
+                  tableItem->setFlags(flag);
+                  bool ok;
+                  int filenameid = field.toInt(&ok, 10);
+                  if (!ok) filenameid = -1;
+                  tableItem->setData(Qt::UserRole, QVariant(filenameid));
+                  fileTable->setItem(row, column, tableItem);
+               }
+               column++;
             }
-            column++;
+            row++;
          }
-         row++;
+         fileTable->setRowCount(row);
       }
-      fileTable->setRowCount(row);
-   }
-   fileTable->resizeColumnsToContents();
-   fileTable->resizeRowsToContents();
-   fileTable->verticalHeader()->hide();
+      fileTable->resizeColumnsToContents();
+      fileTable->resizeRowsToContents();
+      fileTable->verticalHeader()->hide();
+      fileTable->hideColumn(1);
+      if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
+      updateFileTableChecks();
+   } else if (mainWin->m_sqlDebug)
+      Pmsg1(000, "did not perform query, pathid=%i not found\n", pathid);
    connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
-           this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
-   if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
-   updateFileTableChecks();
+          this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
 }
 
 /*
  * Function to populate the version table
  */
-void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
+void restoreTree::fileCurrentItemChanged(QTableWidgetItem *currentFileTableItem, QTableWidgetItem *)
 {
-   if (fileTableItem == NULL)
+   if (currentFileTableItem == NULL)
       return;
 
+   int currentRow = fileTable->row(currentFileTableItem);
+   QTableWidgetItem *fileTableItem = fileTable->item(currentRow, 0);
+   QTableWidgetItem *fileNameIdTableItem = fileTable->item(currentRow, 1);
+   int fileNameId = fileNameIdTableItem->data(Qt::UserRole).toInt();
+
    m_versionCheckStateList.clear();
    disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
@@ -463,66 +615,84 @@ void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTable
    QString directory = fileTableItem->data(Qt::UserRole).toString();
 
    QBrush blackBrush(Qt::black);
-   QString cmd = 
-      "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
-      " FROM File"
-      " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-      " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-      " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
-      " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
-      " AND Job.Jobid IN (" + m_jobQuery + ")"
-      " ORDER BY Job.EndTime DESC";
-
-   QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
+
+   QStringList headerlist = (QStringList() 
+      << tr("Job Id") << tr("Type") << tr("End Time") << tr("Hash") << tr("FileId") << tr("Job Type") << tr("First Volume"));
    versionTable->clear();
    versionTable->setColumnCount(headerlist.size());
    versionTable->setHorizontalHeaderLabels(headerlist);
-
-   if (mainWin->m_sqlDebug) {
-      Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-   }
-   QStringList results;
-   if (m_console->sql_cmd(cmd, results)) {
+   versionTable->setRowCount(0);
    
-      QTableWidgetItem* tableItem;
-      QString field;
-      QStringList fieldlist;
-      versionTable->setRowCount(results.size());
-
-      int row = 0;
-      /* Iterate through the record returned from the query */
-      foreach (QString resultline, results) {
-         fieldlist = resultline.split("\t");
-         int column = 0;
-         /* remove directory */
-         if (fieldlist[0].trimmed() != "") {
-            /* Iterate through fields in the record */
-            foreach (field, fieldlist) {
-               field = field.trimmed();  /* strip leading & trailing spaces */
-               tableItem = new QTableWidgetItem(field, 1);
-               tableItem->setFlags(0);
-               tableItem->setForeground(blackBrush);
-               tableItem->setData(Qt::UserRole, QVariant(directory));
-               versionTable->setItem(row, column, tableItem);
-
-               if (column == 0) {
-                  Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
-                  tableItem->setFlags(flag);
-                  m_versionCheckStateList.append(Qt::Unchecked);
-                  tableItem->setCheckState(Qt::Unchecked);
+   int pathid = m_directoryPathIdHash.value(directory, -1);
+   if ((pathid != -1) && (fileNameId != -1)) {
+      QString cmd = 
+         "SELECT Job.JobId AS JobId, Job.Level AS Type,"
+           " Job.EndTime AS EndTime, File.MD5 AS MD5,"
+           " File.FileId AS FileId, Job.Type AS JobType,"
+           " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume"
+         " FROM File"
+         " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
+         " INNER JOIN Path ON (Path.PathId=File.PathId)"
+         " INNER JOIN Job ON (File.JobId=Job.JobId)"
+         " WHERE Path.PathId=" + QString("%1").arg(pathid) +
+         //" AND Filename.Name='" + file + "'"
+         " AND Filename.FilenameId=" + QString("%1").arg(fileNameId) +
+         " AND Job.Jobid IN (" + m_checkedJobs + ")"
+         " ORDER BY Job.EndTime DESC";
+   
+      if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+      QStringList results;
+      if (m_console->sql_cmd(cmd, results)) {
+      
+         QTableWidgetItem* tableItem;
+         QString field;
+         QStringList fieldlist;
+         versionTable->setRowCount(results.size());
+   
+         int row = 0;
+         /* Iterate through the record returned from the query */
+         foreach (QString resultline, results) {
+            fieldlist = resultline.split("\t");
+            int column = 0;
+            /* remove directory */
+            if (fieldlist[0].trimmed() != "") {
+               /* Iterate through fields in the record */
+               foreach (field, fieldlist) {
+                  field = field.trimmed();  /* strip leading & trailing spaces */
+                  if (column == 5 ) {
+                     QByteArray jtype(field.trimmed().toAscii());
+                     if (jtype.size()) {
+                        field = job_type_to_str(jtype[0]);
+                     }
+                  }
+                  tableItem = new QTableWidgetItem(field, 1);
+                  tableItem->setFlags(0);
+                  tableItem->setForeground(blackBrush);
+                  tableItem->setData(Qt::UserRole, QVariant(directory));
+                  versionTable->setItem(row, column, tableItem);
+                  if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
+                  if (column == 0) {
+                     Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
+                     tableItem->setFlags(flag);
+                     m_versionCheckStateList.append(Qt::Unchecked);
+                     tableItem->setCheckState(Qt::Unchecked);
+                  }
+                  column++;
                }
-               column++;
+               row++;
             }
-            row++;
          }
       }
+      versionTable->resizeColumnsToContents();
+      versionTable->resizeRowsToContents();
+      versionTable->verticalHeader()->hide();
+      updateVersionTableChecks();
+   } else {
+      if (mainWin->m_sqlDebug)
+         Pmsg2(000, "not querying : pathid=%i fileNameId=%i\n", pathid, fileNameId);
    }
-   versionTable->resizeColumnsToContents();
-   versionTable->resizeRowsToContents();
-   versionTable->verticalHeader()->hide();
    connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
-   updateVersionTableChecks();
 }
 
 /*
@@ -531,8 +701,9 @@ void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTable
 void restoreTree::writeSettings()
 {
    QSettings settings(m_console->m_dir->name(), "bat");
-   settings.beginGroup("RestoreTree");
-   settings.setValue("splitterSizes", splitter->saveState());
+   settings.beginGroup(m_groupText);
+   settings.setValue(m_splitText1, m_splitter->saveState());
+   settings.setValue(m_splitText2, splitter->saveState());
    settings.endGroup();
 }
 
@@ -541,16 +712,20 @@ void restoreTree::writeSettings()
  */
 void restoreTree::readSettings()
 {
+   m_groupText = tr("RestoreTreePage");
+   m_splitText1 = "splitterSizes1_3";
+   m_splitText2 = "splitterSizes2_3";
    QSettings settings(m_console->m_dir->name(), "bat");
-   settings.beginGroup("RestoreTree");
-   splitter->restoreState(settings.value("splitterSizes").toByteArray());
+   settings.beginGroup(m_groupText);
+   if (settings.contains(m_splitText1)) { m_splitter->restoreState(settings.value(m_splitText1).toByteArray()); }
+   if (settings.contains(m_splitText2)) { splitter->restoreState(settings.value(m_splitText2).toByteArray()); }
    settings.endGroup();
 }
 
 /*
  * This is a funcion to accomplish the one thing I struggled to figure out what
  * was taking so long.  It add the icons, but after the tree is made.  Seemed to
- * work fast after changing from svg to png file for graphic.
+ * work fast after changing from png to png file for graphic.
  */
 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
 {
@@ -563,23 +738,57 @@ void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
 }
 
 /*
- * I wanted a table to show what jobs meet the criterion and are being used to
+ * Show what jobs meet the criteria and are being used to
  * populate the directory tree and file and version tables.
  */
 void restoreTree::populateJobTable()
 {
    QBrush blackBrush(Qt::black);
-   QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
+
+   if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
+   QStringList headerlist = (QStringList() 
+      << tr("Job Id") << tr("End Time") << tr("Level") << tr("Type")
+      << tr("Name") << tr("Purged") << tr("TU") << tr("TD"));
+   m_toggleUpIndex = headerlist.indexOf(tr("TU"));
+   m_toggleDownIndex = headerlist.indexOf(tr("TD"));
+   int purgedIndex = headerlist.indexOf(tr("Purged"));
+   int typeIndex = headerlist.indexOf(tr("Type"));
    jobTable->clear();
    jobTable->setColumnCount(headerlist.size());
    jobTable->setHorizontalHeaderLabels(headerlist);
    QString jobQuery =
-      "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
-      " FROM Job" + m_jobQueryPart +
-      " ORDER BY Job.EndTime DESC";
-   if (mainWin->m_sqlDebug) {
-      Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
+      "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime,"
+      " Job.Level AS Level, Job.Type AS Type,"
+      " Job.Name AS JobName, Job.purgedfiles AS Purged"
+      " FROM Job"
+      /* INNER JOIN FileSet eliminates all restore jobs */
+      " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
+      " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
+      " WHERE"
+      " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
+      " Client.Name='" + clientCombo->currentText() + "'";
+   if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != tr("Any"))) {
+      jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
    }
+   if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != tr("Any"))) {
+      jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
+   }
+   /* If Limit check box For limit by days is checked  */
+   if (daysCheckBox->checkState() == Qt::Checked) {
+      QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
+      QString since = stamp.toString(Qt::ISODate);
+      jobQuery += " AND Job.Starttime>'" + since + "'";
+   }
+   //jobQuery += " AND Job.purgedfiles=0";
+   jobQuery += " ORDER BY Job.EndTime DESC";
+   /* If Limit check box for limit records returned is checked  */
+   if (limitCheckBox->checkState() == Qt::Checked) {
+      QString limit;
+      limit.setNum(limitSpinBox->value());
+      jobQuery += " LIMIT " + limit;
+   }
+   if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
+
 
    QStringList results;
    if (m_console->sql_cmd(jobQuery, results)) {
@@ -599,18 +808,43 @@ void restoreTree::populateJobTable()
             /* Iterate through fields in the record */
             foreach (field, fieldlist) {
                field = field.trimmed();  /* strip leading & trailing spaces */
-               tableItem = new QTableWidgetItem(field, 1);
-               tableItem->setFlags(0);
-               tableItem->setForeground(blackBrush);
-               jobTable->setItem(row, column, tableItem);
-               if (column == 0) {
-                  Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
-                  tableItem->setFlags(flag);
-                  tableItem->setCheckState(Qt::Checked);
-                  tableItem->setBackground(Qt::green);
+               if (field != "") {
+                  if (column == typeIndex) {
+                     QByteArray jtype(field.trimmed().toAscii());
+                     if (jtype.size()) {
+                        field = job_type_to_str(jtype[0]);
+                     }
+                  }
+                  tableItem = new QTableWidgetItem(field, 1);
+                  tableItem->setFlags(0);
+                  tableItem->setForeground(blackBrush);
+                  jobTable->setItem(row, column, tableItem);
+                  if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
+                  if (column == 0) {
+                     bool ok;
+                     int purged = fieldlist[purgedIndex].toInt(&ok, 10); 
+                     if (!((ok) && (purged == 1))) {
+                        Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
+                        tableItem->setFlags(flag);
+                        tableItem->setCheckState(Qt::Checked);
+                        tableItem->setBackground(Qt::green);
+                     } else {
+                        tableItem->setFlags(0);
+                        tableItem->setCheckState(Qt::Unchecked);
+                     }
+                  }
+                  column++;
                }
-               column++;
             }
+            tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
+            tableItem->setFlags(0);
+            tableItem->setForeground(blackBrush);
+            jobTable->setItem(row, column, tableItem);
+            column++;
+            tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
+            tableItem->setFlags(0);
+            tableItem->setForeground(blackBrush);
+            jobTable->setItem(row, column, tableItem);
             row++;
          }
       }
@@ -618,6 +852,37 @@ void restoreTree::populateJobTable()
    jobTable->resizeColumnsToContents();
    jobTable->resizeRowsToContents();
    jobTable->verticalHeader()->hide();
+   jobTable->hideColumn(purgedIndex);
+}
+
+void restoreTree::jobTableCellClicked(int row, int column)
+{
+   if (column == m_toggleUpIndex){
+      int cnt;
+      for (cnt=0; cnt<row+1; cnt++) {
+         QTableWidgetItem *item = jobTable->item(cnt, 0);
+         if (item->flags()) {
+            Qt::CheckState state = item->checkState();
+            if (state == Qt::Checked)
+               item->setCheckState(Qt::Unchecked);
+            else if (state == Qt::Unchecked)
+               item->setCheckState(Qt::Checked);
+         }
+      }
+   }
+   if (column == m_toggleDownIndex){
+      int cnt, max = jobTable->rowCount();
+      for (cnt=row; cnt<max; cnt++) {
+         QTableWidgetItem *item = jobTable->item(cnt, 0);
+         if (item->flags()) {
+            Qt::CheckState state = item->checkState();
+            if (state == Qt::Checked)
+               item->setCheckState(Qt::Unchecked);
+            else if (state == Qt::Unchecked)
+               item->setCheckState(Qt::Checked);
+         }
+      }
+   }
 }
 
 /*
@@ -843,13 +1108,14 @@ void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
 
    /* determine the default state */
    Qt::CheckState defState;
+   if (mainWin->m_sqlDebug) Pmsg1(000, "row=%d\n", row);
    if (row == 0) {
       defState = Qt::PartiallyChecked;
       if (fileState == Qt::Unchecked)
          defState = Qt::Unchecked;
-   }
-   else
+   } else {
       defState = Qt::Unchecked;
+   }
 
    /* determine if it is already in the versionExceptionHash */
    QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
@@ -882,7 +1148,7 @@ void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
       m_versionExceptionHash.remove(fullPath);
    } else if (prevState != curState) {
       if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "  THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
-      if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
+      if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked)) {
          if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
          m_versionExceptionHash.insert(fullPath, thisJobNum);
          if (fileState != Qt::Checked) {
@@ -959,6 +1225,7 @@ void restoreTree::updateFileTableChecks()
    int rcnt = fileTable->rowCount();
    for (int row=0; row<rcnt; row++) {
       QTableWidgetItem* item = fileTable->item(row, 0);
+      if (!item) { return; }
 
       Qt::CheckState curState = item->checkState();
       Qt::CheckState newState = Qt::PartiallyChecked;
@@ -1000,6 +1267,7 @@ void restoreTree::updateVersionTableChecks()
 
    /* deterimine the default state from the state of the file */
    QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
+   if (!fileTableItem) { return; }
    Qt::CheckState fileState = fileTableItem->checkState();
    QString file = fileTableItem->text();
    QString fullPath = dirName + file;
@@ -1009,6 +1277,7 @@ void restoreTree::updateVersionTableChecks()
    int cnt = versionTable->rowCount();
    for (int row=0; row<cnt; row++) {
       QTableWidgetItem* item = versionTable->item(row, 0);
+      if (!item) { break; }
 
       Qt::CheckState curState = item->checkState();
       Qt::CheckState newState = Qt::Unchecked;
@@ -1041,7 +1310,7 @@ void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in
    bool done = false;
    QString fullPath = fullPath_in;
    QString direct, path;
-   while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
+   while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
       direct = path = fullPath;
       path.replace(index+1, fullPath.length()-index-1, "");
       direct.replace(0, index+1, "");
@@ -1260,94 +1529,122 @@ void restoreTree::directorySetIcon(int operation, int change, QString &path, QTr
 }
 
 /*
- * Test Button
+ * Restore Button
  */
-void restoreTree::testButtonPushed()
+void restoreTree::restoreButtonPushed()
 {
+   /* Set progress bars and repaint */
+   prLabel1->setVisible(true);
+   prLabel1->setText(tr("Task 1 of 3"));
+   prLabel2->setVisible(true);
+   prLabel2->setText(tr("Processing Checked directories"));
+   prBar1->setVisible(true);
+   prBar1->setRange(0, 3);
+   prBar1->setValue(0);
+   prBar2->setVisible(true);
+   prBar2->setRange(0, 0);
+   repaint();
    QMultiHash<int, QString> versionFilesMulti;
+   int vFMCounter = 0;
    QHash <QString, bool> fullPathDone;
    QHash <QString, int> fileIndexHash;
    if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
-      Pmsg0(000, "In restoreTree::testButtonPushed\n");
+      Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
+   /* Use a tree widget item iterator to count directories for the progress bar */
+   QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
+   int ditcount = 0;
+   while (*diterc) {
+      ditcount += 1;
+      ++diterc;
+   } /* while (*diterc) */
+   prBar2->setRange(0, ditcount);
+   prBar2->setValue(0);
+   ditcount = 0;
    /* Use a tree widget item iterator filtering for Checked Items */
    QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
    while (*diter) {
       QString directory = (*diter)->data(0, Qt::UserRole).toString();
-      if (mainWin->m_rtRestore1Debug)
-      Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
-      /* With a checked directory, query for the files in the directory */
-
-      QString cmd =
-         "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
-         " FROM"
-         " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
-           " FROM File"
-             " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-             " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-             " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
-           " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
-           "  AND Job.Jobid IN (" + m_jobQuery + ")"
-           " GROUP BY Filename.Name"
-         ") t1, File "
-           " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-           " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-           " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
-         " WHERE"
-           " Path.Path='" + directory + "'"
-           " AND Filename.Name=t1.Filename"
-           " AND Job.Jobid=t1.JobId"
-         " ORDER BY Filename";
-
-      if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-      QStringList results;
-      if (m_console->sql_cmd(cmd, results)) {
-      
-         QStringList fieldlist;
+      int pathid = m_directoryPathIdHash.value(directory, -1);
+      if (pathid != -1) {
+         if (mainWin->m_rtRestore1Debug)
+            Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
+         /* With a checked directory, query for the files in the directory */
    
-         int row = 0;
-         /* Iterate through the record returned from the query */
-         foreach (QString resultline, results) {
-            /* Iterate through fields in the record */
-            int column = 0;
-            QString fullPath = "";
-            Qt::CheckState fileExcpState = (Qt::CheckState)4;
-            fieldlist = resultline.split("\t");
-            int version = 0;
-            int fileIndex = 0;
-            foreach (QString field, fieldlist) {
-               if (column == 0) {
-                  fullPath = directory + field;
-               }
-               if (column == 1) {
-                  version = field.toInt();
+         QString cmd =
+            "SELECT Filename.Name AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
+            " FROM"
+            " ( SELECT File.FilenameId AS FilenameId, MAX(Job.JobId) AS JobId"
+              " FROM File"
+              " INNER JOIN Job ON (Job.JobId=File.JobId)"
+              " WHERE File.PathId=" + QString("%1").arg(pathid) +
+              " AND Job.Jobid IN (" + m_checkedJobs + ")"
+              " GROUP BY File.FilenameId"
+            ") t1, File "
+              " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
+              " INNER JOIN Job ON (Job.JobId=File.JobId)"
+              " WHERE File.PathId=" + QString("%1").arg(pathid) +
+              " AND File.FilenameId=t1.FilenameId"
+              " AND Job.Jobid=t1.JobId"
+            " ORDER BY Filename";
+   
+         if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+         QStringList results;
+         if (m_console->sql_cmd(cmd, results)) {
+            QStringList fieldlist;
+      
+            int row = 0;
+            /* Iterate through the record returned from the query */
+            foreach (QString resultline, results) {
+               /* Iterate through fields in the record */
+               int column = 0;
+               QString fullPath = "";
+               Qt::CheckState fileExcpState = (Qt::CheckState)4;
+               fieldlist = resultline.split("\t");
+               int version = 0;
+               int fileIndex = 0;
+               foreach (QString field, fieldlist) {
+                  if (column == 0) {
+                     fullPath = directory + field;
+                  }
+                  if (column == 1) {
+                     version = field.toInt();
+                  }
+                  if (column == 2) {
+                     fileIndex = field.toInt();
+                  }
+                  column++;
                }
-               if (column == 2) {
-                  fileIndex = field.toInt();
+               fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
+               
+               int excpVersion = m_versionExceptionHash.value(fullPath, 0);
+               if (fileExcpState != Qt::Unchecked) {
+                  QString debugtext;
+                  if (excpVersion != 0) {
+                     debugtext = QString("*E* version=%1").arg(excpVersion);
+                     version = excpVersion;
+                     fileIndex = queryFileIndex(fullPath, excpVersion);
+                  } else
+                     debugtext = QString("___ version=%1").arg(version);
+                  if (mainWin->m_rtRestore1Debug)
+                     Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
+                  fullPathDone.insert(fullPath, 1);
+                  fileIndexHash.insert(fullPath, fileIndex);
+                  versionFilesMulti.insert(version, fullPath);
+                  vFMCounter += 1;
                }
-               column++;
-            }
-            fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
-            
-            int excpVersion = m_versionExceptionHash.value(fullPath, 0);
-            if (fileExcpState != Qt::Unchecked) {
-               QString debugtext;
-               if (excpVersion != 0) {
-                  debugtext = QString("*E* version=%1").arg(excpVersion);
-                  version = excpVersion;
-                  fileIndex = queryFileIndex(fullPath, excpVersion);
-               } else
-                  debugtext = QString("___ version=%1").arg(version);
-               if (mainWin->m_rtRestore1Debug)
-                  Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
-               fullPathDone.insert(fullPath, 1);
-               fileIndexHash.insert(fullPath, fileIndex);
-               versionFilesMulti.insert(version, fullPath);
+               row++;
             }
-            row++;
          }
       }
+      ditcount += 1;
+      prBar2->setValue(ditcount);
       ++diter;
    } /* while (*diter) */
+   prBar1->setValue(1);
+   prLabel1->setText( tr("Task 2 of 3"));
+   prLabel2->setText(tr("Processing Exceptions"));
+   prBar2->setRange(0, 0);
+   repaint();
 
    /* There may be some exceptions not accounted for yet with fullPathDone */
    QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
@@ -1375,10 +1672,19 @@ void restoreTree::testButtonPushed()
             if (mainWin->m_rtRestore1Debug)
                Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
             versionFilesMulti.insert(version, fullPath);
+            vFMCounter += 1;
             fileIndexHash.insert(fullPath, fileIndex);
          } /* if fullPathDone.value(fullPath, 0) == 0 */
       } /* if state != 0 */
    } /* while ftera.hasNext */
+   /* The progress bars for the next step */
+   prBar1->setValue(2);
+   prLabel1->setText(tr("Task 3 of 3"));
+   prLabel2->setText(tr("Filling Database Table"));
+   prBar2->setRange(0, vFMCounter);
+   vFMCounter = 0;
+   prBar2->setValue(vFMCounter);
+   repaint();
 
    /* now for the final spit out of the versions and lists of files for each version */
    QHash<int, int> doneKeys;
@@ -1412,27 +1718,48 @@ void restoreTree::testButtonPushed()
             int fileIndex = fileIndexHash.value(ffullPath);
             if (mainWin->m_rtRestore2Debug) Pmsg2(000, "  file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
             QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
-            if (mainWin->m_sqlDebug)
-               Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
+            if (mainWin->m_rtRestore3Debug)
+               Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
             QStringList results;
             if (!m_console->sql_cmd(sqlcmd, results))
                Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
+            prBar2->setValue(++vFMCounter);
          } /* foreach fullPathList */
          doneKeys.insert(fversion,1);
          jobList.append(fversion);
       } /*  if (doneKeys.value(fversion, 0) == 0) */
    } /* while (vFMiter.hasNext()) */
    if (tempTable != "") {
-      QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
-      new restoreTreeRunPage(tempTable, m_prevClientCombo, jobList, pageSelectorTreeWidgetItem);
+      /* a table was made, lets run the job */
+      QString jobOption = " jobid=\"";
+      bool first = true;
+      /* create a list of jobs comma separated */
+      foreach (int job, jobList) {
+         if (first) first = false;
+         else jobOption += ",";
+         jobOption += QString("%1").arg(job);
+      }
+      jobOption += "\"";
+      QString cmd = QString("restore");
+      cmd += jobOption +
+             " client=\"" + m_prevClientCombo + "\"" +
+             " file=\"?" + tempTable + "\" done";
+      if (mainWin->m_commandDebug)
+         Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
+      consoleCommand(cmd);
    }
+   /* turn off the progress widgets */
+   prBar1->setVisible(false);
+   prBar2->setVisible(false);
+   prLabel1->setVisible(false);
+   prLabel2->setVisible(false);
 }
 
 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
 {
    int qversion = 0;
    QString directory, fileName;
-   int index = m_slashregex.lastIndexIn(fullPath, -2);
+   int index = fullPath.lastIndexOf("/", -2);
    if (index != -1) {
       directory = fileName = fullPath;
       directory.replace(index+1, fullPath.length()-index-1, "");
@@ -1442,35 +1769,38 @@ int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
                     .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
          Pmsg0(000, msg.toUtf8().data());
       }
-      /* so now we need the latest version from the database */
-      QString cmd =
-         "SELECT MAX(Job.JobId)"
-         " FROM File "
-         " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-         " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-         " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
-         " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
-         " AND Job.Jobid IN (" + m_jobQuery + ")"
-         " AND Filename.Name='" + fileName + "'"
-         " GROUP BY Filename.Name";
-      if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-      QStringList results;
-      if (m_console->sql_cmd(cmd, results)) {
-         QStringList fieldlist;
-         int row = 0;
-         /* Iterate through the record returned from the query */
-         foreach (QString resultline, results) {
-            /* Iterate through fields in the record */
-            int column = 0;
-            fieldlist = resultline.split("\t");
-            foreach (QString field, fieldlist) {
-               if (column == 0) {
-                  qversion = field.toInt();
+      int pathid = m_directoryPathIdHash.value(directory, -1);
+      if (pathid != -1) {
+         /* so now we need the latest version from the database */
+         QString cmd =
+            "SELECT MAX(Job.JobId)"
+            " FROM File "
+            " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
+            " INNER JOIN Job ON (File.JobId=Job.JobId)"
+            " WHERE File.PathId=" + QString("%1").arg(pathid) +
+            " AND Job.Jobid IN (" + m_checkedJobs + ")"
+            " AND Filename.Name='" + fileName + "'"
+            " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
+            " GROUP BY Filename.Name";
+    
+         if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+         QStringList results;
+         if (m_console->sql_cmd(cmd, results)) {
+            QStringList fieldlist;
+            int row = 0;
+            /* Iterate through the record returned from the query */
+            foreach (QString resultline, results) {
+               /* Iterate through fields in the record */
+               int column = 0;
+               fieldlist = resultline.split("\t");
+               foreach (QString field, fieldlist) {
+                  if (column == 0) {
+                     qversion = field.toInt();
+                  }
+                  column++;
                }
-               column++;
+               row++;
             }
-            row++;
          }
       }
    } /* if (index != -1) */
@@ -1482,7 +1812,8 @@ int restoreTree::queryFileIndex(QString &fullPath, int jobId)
 {
    int qfileIndex = 0;
    QString directory, fileName;
-   int index = m_slashregex.lastIndexIn(fullPath, -2);
+   int index = fullPath.lastIndexOf("/", -2);
+   if (mainWin->m_sqlDebug) Pmsg1(000, "Index=%d\n", index);
    if (index != -1) {
       directory = fileName = fullPath;
       directory.replace(index+1, fullPath.length()-index-1, "");
@@ -1492,39 +1823,48 @@ int restoreTree::queryFileIndex(QString &fullPath, int jobId)
                     .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
          Pmsg0(000, msg.toUtf8().data());
       }
-      /* so now we need the latest version from the database */
-      QString cmd =
-         "SELECT"
-          " File.FileIndex"
-         " FROM File"
-          " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-          " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
-          " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
-         " WHERE"
-          " Path.Path='" + directory + "'"
-          " AND Filename.Name='" + fileName + "'"
-          " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
-         " GROUP BY File.FileIndex";
-      if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
-      QStringList results;
-      if (m_console->sql_cmd(cmd, results)) {
-         QStringList fieldlist;
-         int row = 0;
-         /* Iterate through the record returned from the query */
-         foreach (QString resultline, results) {
-            /* Iterate through fields in the record */
-            int column = 0;
-            fieldlist = resultline.split("\t");
-            foreach (QString field, fieldlist) {
-               if (column == 0) {
-                  qfileIndex = field.toInt();
+      int pathid = m_directoryPathIdHash.value(directory, -1);
+      if (pathid != -1) {
+         /* so now we need the latest version from the database */
+         QString cmd =
+            "SELECT"
+             " File.FileIndex"
+            " FROM File"
+             " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
+             " INNER JOIN Job ON (File.JobId=Job.JobId)"
+            " WHERE File.PathId=" + QString("%1").arg(pathid) +
+             " AND Filename.Name='" + fileName + "'"
+             " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
+            " GROUP BY File.FileIndex";
+         if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
+         QStringList results;
+         if (m_console->sql_cmd(cmd, results)) {
+            QStringList fieldlist;
+            int row = 0;
+            /* Iterate through the record returned from the query */
+            foreach (QString resultline, results) {
+               /* Iterate through fields in the record */
+               int column = 0;
+               fieldlist = resultline.split("\t");
+               foreach (QString field, fieldlist) {
+                  if (column == 0) {
+                     qfileIndex = field.toInt();
+                  }
+                  column++;
                }
-               column++;
+               row++;
             }
-            row++;
          }
       }
    } /* if (index != -1) */
+   if (mainWin->m_sqlDebug) Pmsg1(000, "qfileIndex=%d\n", qfileIndex);
    return qfileIndex;
 }
+
+
+void restoreTree::PgSeltreeWidgetClicked()
+{
+   if (!isOnceDocked()) {
+      dockPage();
+   }
+}