]> 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 852d8c9ac5e2c6ed6e71bb113d159eb35536931c..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 Class 
  *
 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()
@@ -77,6 +97,13 @@ void restoreTree::setupPage()
    connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
    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 *)),
@@ -85,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();
@@ -116,90 +168,122 @@ void restoreTree::populateDirectoryTree()
    m_versionExceptionHash.clear();
    m_directoryIconStateHash.clear();
 
-   int clientIndex = clientCombo->currentIndex();
-   int fileSetIndex = fileSetCombo->currentIndex();
-   QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
-   QString clientComboText = clientCombo->itemText(clientIndex);
-   QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
-   bool dropdownChanged = (m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText);
-   int taskcount = 2, ontask = 1;
-   if (dropdownChanged) taskcount += 1;
-//   QString taskCountString = QString("%1").arg(taskcount);
+   updateRefresh();
+   int taskcount = 3, ontask = 1;
+   if (m_dropdownChanged) taskcount += 1;
    
    /* Set progress bars and repaint */
    prBar1->setVisible(true);
    prBar1->setRange(0,taskcount);
    prBar1->setValue(0);
-   prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
+   prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
    prLabel1->setVisible(true);
    prBar2->setVisible(true);
    prBar2->setRange(0,0);
-   prLabel2->setText("Querying Database");
+   prLabel2->setText(tr("Querying Database"));
    prLabel2->setVisible(true);
    repaint();
 
-   if (dropdownChanged) {
-      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 =
-         " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
-         " INNER 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());
-      }
+   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("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
+      prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
       prBar2->setValue(0);
       prBar2->setRange(0,0);
-      prLabel2->setText("Querying Jobs");
+      prLabel2->setText(tr("Querying Jobs"));
       repaint();
       populateJobTable();
-      setJobsCheckedList();
-   } else {
-      setJobsCheckedList();
    }
-
-   QString cmd =
-      "SELECT DISTINCT Path.Path AS Path"
-      " FROM Path"
-      " INNER JOIN File ON (File.PathId=Path.PathId)"
-      " INNER 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());
-   }
-   prBar1->setValue(ontask++);
-   prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
-   prBar2->setValue(0);
-   prLabel2->setText("Processing Directories");
-   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;
+            }
+         }
       }
-      prBar2->setRange(0,directories.count());
+      /* 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();
-      foreach(QString directory, directories) {
-         m_debugCnt += 1;
-         prBar2->setValue(m_debugCnt);
-         parseDirectory(directory);
+      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);
@@ -208,7 +292,7 @@ void restoreTree::populateDirectoryTree()
 }
 
 /*
- *  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()
@@ -225,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;
 }
 
 /*
@@ -237,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());
 
@@ -256,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, "");
@@ -265,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);
       }
@@ -276,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
@@ -304,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("/");
@@ -318,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);
       }
    }
  
@@ -372,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;
    }
 }
 
@@ -392,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));
@@ -410,88 +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 AS FileName"
-      " 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.Path='" + directory + "' AND Filename.Name!=''"
-      " AND Job.Jobid IN (" + m_jobQuery + ")"
-      " ORDER BY FileName";
-   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 *)));
@@ -501,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"
-      " 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 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();
 }
 
 /*
@@ -569,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();
 }
 
@@ -579,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)
 {
@@ -601,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)) {
@@ -637,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++;
          }
       }
@@ -656,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);
+         }
+      }
+   }
 }
 
 /*
@@ -881,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();
@@ -920,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) {
@@ -997,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;
@@ -1038,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;
@@ -1047,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;
@@ -1079,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, "");
@@ -1298,15 +1529,15 @@ void restoreTree::directorySetIcon(int operation, int change, QString &path, QTr
 }
 
 /*
- * Test Button
+ * Restore Button
  */
 void restoreTree::restoreButtonPushed()
 {
    /* Set progress bars and repaint */
    prLabel1->setVisible(true);
-   prLabel1->setText("Task 1 of 3");
+   prLabel1->setText(tr("Task 1 of 3"));
    prLabel2->setVisible(true);
-   prLabel2->setText("Processing Checked directories");
+   prLabel2->setText(tr("Processing Checked directories"));
    prBar1->setVisible(true);
    prBar1->setRange(0, 3);
    prBar1->setValue(0);
@@ -1333,77 +1564,76 @@ void restoreTree::restoreButtonPushed()
    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"
-             " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-             " INNER JOIN Path ON (Path.PathId=File.PathId)"
-             " INNER 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 "
-           " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
-           " INNER JOIN Path ON (Path.PathId=File.PathId)"
-           " INNER 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);
-               vFMCounter += 1;
+               row++;
             }
-            row++;
          }
       }
       ditcount += 1;
@@ -1411,8 +1641,8 @@ void restoreTree::restoreButtonPushed()
       ++diter;
    } /* while (*diter) */
    prBar1->setValue(1);
-   prLabel1->setText("Task 2 of 3");
-   prLabel2->setText("Processing Exceptions");
+   prLabel1->setText( tr("Task 2 of 3"));
+   prLabel2->setText(tr("Processing Exceptions"));
    prBar2->setRange(0, 0);
    repaint();
 
@@ -1449,8 +1679,8 @@ void restoreTree::restoreButtonPushed()
    } /* while ftera.hasNext */
    /* The progress bars for the next step */
    prBar1->setValue(2);
-   prLabel1->setText("Task 3 of 3");
-   prLabel2->setText("Filling Database Table");
+   prLabel1->setText(tr("Task 3 of 3"));
+   prLabel2->setText(tr("Filling Database Table"));
    prBar2->setRange(0, vFMCounter);
    vFMCounter = 0;
    prBar2->setValue(vFMCounter);
@@ -1512,6 +1742,7 @@ void restoreTree::restoreButtonPushed()
       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());
@@ -1528,7 +1759,7 @@ 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, "");
@@ -1538,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 "
-         " 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.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) */
@@ -1578,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, "");
@@ -1588,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"
-          " 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.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();
+   }
+}