]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/restoretree.cpp
Put controls in a scroll area for JobList and restore tree. Then put the scroll
[bacula/bacula] / bacula / src / qt-console / restore / restoretree.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28  
29 /*
30  *   Version $Id$
31  *
32  *  Restore Class 
33  *
34  *   Kern Sibbald, February MMVII
35  *
36  */ 
37
38 #include "bat.h"
39 #include "restoretree.h"
40 #include "pages.h"
41
42 restoreTree::restoreTree()
43 {
44    setupUi(this);
45    m_name = "Version Browser";
46    pgInitialize();
47    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48    thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
49
50    m_closeable = true;
51    m_populated = false;
52
53    readSettings();
54    dockPage();
55    m_winRegExpDrive.setPattern("^[a-z]:/$");
56    m_winRegExpPath.setPattern("^[a-z]:/");
57    m_slashregex.setPattern("/");
58    m_debugCnt = 0;
59    m_debugTrap = true;
60
61    QGridLayout *m_gridLayout = new QGridLayout(this);
62    m_gridLayout->setSpacing(6);
63    m_gridLayout->setMargin(9);
64    m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
65
66    QSplitter *splitter_2 = new QSplitter(Qt::Vertical, this);
67    QScrollArea *area = new QScrollArea();
68    area->setObjectName(QString::fromUtf8("area"));
69    area->setWidget(widget);
70    area->setWidgetResizable(true);
71    splitter_2->addWidget(splitter);
72    splitter_2->addWidget(area);
73
74    m_gridLayout->addWidget(splitter_2, 0, 0, 1, 1);
75
76    /* progress widgets */
77    prBar1->setVisible(false);
78    prBar2->setVisible(false);
79    prLabel1->setVisible(false);
80    prLabel2->setVisible(false);
81
82    /* Set Defaults for check and spin for limits */
83    limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
84    limitSpinBox->setValue(mainWin->m_recordLimitVal);
85    daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
86    daysSpinBox->setValue(mainWin->m_daysLimitVal);
87 }
88
89 restoreTree::~restoreTree()
90 {
91    writeSettings();
92 }
93
94 /*
95  * Called from the constructor to set up the page widgets and connections.
96  */
97 void restoreTree::setupPage()
98 {
99    connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
100    connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
101    connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
102    connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
103            this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
104    connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
105            this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
106    connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
107            this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
108    connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
109            this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
110
111    QStringList titles = QStringList() << "Directories";
112    directoryTree->setHeaderLabels(titles);
113    clientCombo->addItems(m_console->client_list);
114    fileSetCombo->addItem("Any");
115    fileSetCombo->addItems(m_console->fileset_list);
116    jobCombo->addItem("Any");
117    jobCombo->addItems(m_console->job_list);
118
119    directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
120 }
121
122 /*
123  * When refresh button is pushed, perform a query getting the directories and
124  * use parseDirectory and addDirectory to populate the directory tree with items.
125  */
126 void restoreTree::populateDirectoryTree()
127 {
128    m_slashTrap = false;
129    m_dirPaths.clear();
130    directoryTree->clear();
131    fileTable->clear();
132    fileTable->setRowCount(0);
133    fileTable->setColumnCount(0);
134    versionTable->clear();
135    versionTable->setRowCount(0);
136    versionTable->setColumnCount(0);
137    m_fileExceptionHash.clear();
138    m_fileExceptionMulti.clear();
139    m_versionExceptionHash.clear();
140    m_directoryIconStateHash.clear();
141
142    QString jobComboText = jobCombo->currentText();
143    QString clientComboText = clientCombo->currentText();
144    QString fileSetComboText = fileSetCombo->currentText();
145    if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobComboText.toUtf8().data());
146    bool dropdownChanged = (m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText);
147    int taskcount = 2, ontask = 1;
148    if (dropdownChanged) taskcount += 1;
149 //   QString taskCountString = QString("%1").arg(taskcount);
150    
151    /* Set progress bars and repaint */
152    prBar1->setVisible(true);
153    prBar1->setRange(0,taskcount);
154    prBar1->setValue(0);
155    prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
156    prLabel1->setVisible(true);
157    prBar2->setVisible(true);
158    prBar2->setRange(0,0);
159    prLabel2->setText("Querying Database");
160    prLabel2->setVisible(true);
161    repaint();
162
163    if (dropdownChanged) {
164       m_prevJobCombo =  jobComboText;
165       m_prevClientCombo = clientComboText;
166       m_prevFileSetCombo = fileSetComboText;
167       if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
168
169       QString condition = " Client.Name='" + clientCombo->itemText(clientCombo->currentIndex()) + "'";
170       if ((jobCombo->currentIndex() >= 0) && (jobComboText != "Any")) {
171          condition.append(" AND Job.name = '" + jobComboText + "'");
172       }
173       if ((fileSetCombo->currentIndex() >= 0) && (fileSetComboText != "Any")) {
174          condition.append(" AND FileSet.FileSet='" + fileSetComboText + "'");
175       }
176       /* If Limit check box For limit by days is checked  */
177       if (daysCheckBox->checkState() == Qt::Checked) {
178          QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
179          QString since = stamp.toString(Qt::ISODate);
180          condition.append(" AND Job.Starttime>'" + since + "'");
181       }
182       m_jobQueryPart =
183          " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
184          " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
185          " WHERE" + condition +
186          " AND Job.purgedfiles=0";
187       m_jobQuery =
188          "SELECT Job.Jobid"
189          " From Job" + m_jobQueryPart;
190       /* If Limit check box for limit records returned is checked  */
191       if (limitCheckBox->checkState() == Qt::Checked) {
192          QString limit;
193          limit.setNum(limitSpinBox->value());
194          m_jobQuery += " LIMIT " + limit;
195       }
196
197       if (mainWin->m_sqlDebug) {
198          Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
199       }
200       prBar1->setValue(ontask++);
201       prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
202       prBar2->setValue(0);
203       prBar2->setRange(0,0);
204       prLabel2->setText("Querying Jobs");
205       repaint();
206       populateJobTable();
207       setJobsCheckedList();
208    } else {
209       setJobsCheckedList();
210    }
211
212    QString cmd =
213       "SELECT DISTINCT Path.Path AS Path"
214       " FROM Path"
215       " INNER JOIN File ON (File.PathId=Path.PathId)"
216       " INNER JOIN Job ON (File.JobId=Job.JobId)"
217       " WHERE Job.Jobid IN (" + m_jobQuery + ")"
218       " ORDER BY Path";
219    if (mainWin->m_sqlDebug) {
220       Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
221    }
222    prBar1->setValue(ontask++);
223    prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
224    prBar2->setValue(0);
225    prLabel2->setText("Processing Directories");
226    QStringList directories;
227    if (m_console->sql_cmd(cmd, directories)) {
228       if (mainWin->m_miscDebug) {
229          Pmsg1(000, "Done with query %i directories\n", directories.count());
230       }
231       prBar2->setRange(0,directories.count());
232       repaint();
233       foreach(QString directory, directories) {
234          m_debugCnt += 1;
235          prBar2->setValue(m_debugCnt);
236          parseDirectory(directory);
237       }
238    }
239    prBar1->setVisible(false);
240    prBar2->setVisible(false);
241    prLabel1->setVisible(false);
242    prLabel2->setVisible(false);
243 }
244
245 /*
246  *  Function to set m_jobQuery from the jobs that are checked in the table
247  *  of jobs
248  */     
249 void restoreTree::setJobsCheckedList()
250 {
251    m_JobsCheckedList = "";
252    bool first = true;
253    /* Update the items in the version table */
254    int cnt = jobTable->rowCount();
255    for (int row=0; row<cnt; row++) {
256       QTableWidgetItem* jobItem = jobTable->item(row, 0);
257       if (jobItem->checkState() == Qt::Checked) {
258          if (!first)
259             m_JobsCheckedList += ",";
260          m_JobsCheckedList += jobItem->text();
261          first = false;
262          jobItem->setBackground(Qt::green);
263       } else
264          jobItem->setBackground(Qt::gray);
265    }
266    m_jobQuery = m_JobsCheckedList;
267 }
268
269 /*
270  * Function to parse a directory into all possible subdirectories, then add to
271  * The tree.
272  */
273 void restoreTree::parseDirectory(QString &dir_in)
274 {
275    /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
276     * instead of printing out what could potentially a whole bunch */
277    if (m_debugCnt > 2)
278       m_debugTrap = false;
279    /* Clean up the directory string remove some funny char after last '/' */
280    QRegExp rgx("[^/]$");
281    int lastslash = rgx.indexIn(dir_in);
282    dir_in.replace(lastslash, dir_in.length()-lastslash, "");
283    if ((mainWin->m_miscDebug) && (m_debugTrap))
284       Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
285
286    /* split and add if not in yet */
287    QString direct, path;
288    int index;
289    bool done = false;
290    QStringList pathAfter, dirAfter;
291    /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/ 
292     * if not added into tree, then try /etc/ and somedir/ if not added, then try
293     * / and etc/ .  That should succeed, then add the ones that failed in reverse */
294    while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
295       direct = path = dir_in;
296       path.replace(index+1, dir_in.length()-index-1,"");
297       direct.replace(0, index+1, "");
298       if ((mainWin->m_miscDebug) && (m_debugTrap)) {
299          QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
300                     .arg(dir_in.length()).arg(index).arg(path).arg(direct);
301          Pmsg0(000, msg.toUtf8().data());
302       }
303       if (addDirectory(path, direct)) done = true;
304       else {
305          if ((mainWin->m_miscDebug) && (m_debugTrap))
306             Pmsg0(000, "Saving for later\n");
307          pathAfter.prepend(path);
308          dirAfter.prepend(direct);
309       }
310       dir_in = path;
311    }
312
313    for (int k=0; k<pathAfter.count(); k++) {
314       if (addDirectory(pathAfter[k], dirAfter[k]))
315          if ((mainWin->m_miscDebug) && (m_debugTrap))
316             Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
317       else
318          if ((mainWin->m_miscDebug) && (m_debugTrap))
319             Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
320    }
321 }
322
323 /*
324  * Function called from fill directory when a directory is found to see if this
325  * directory exists in the directory pane and then add it to the directory pane
326  */
327 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
328 {
329    QString newdir = newdirr;
330    QString fullPath = m_cwd + newdirr;
331    bool ok = true, added = false;
332
333    if ((mainWin->m_miscDebug) && (m_debugTrap)) {
334       QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
335                     .arg(m_cwd)
336                     .arg(newdir);
337       Pmsg0(000, msg.toUtf8().data());
338    }
339
340    if (!m_slashTrap) {
341       /* add unix '/' directory first */
342       if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
343          m_slashTrap = true;
344          QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
345          QString text("/");
346          item->setText(0, text.toUtf8().data());
347          item->setData(0, Qt::UserRole, QVariant(text));
348          item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
349          item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
350          if ((mainWin->m_miscDebug) && (m_debugTrap)) {
351             Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
352          }
353          m_dirPaths.insert(text, item);
354       }
355       /* no need to check for windows drive if unix */
356       if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
357          /* this is a windows drive add the base widget */
358          QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
359          item->setText(0, m_cwd);
360          item->setData(0, Qt::UserRole, QVariant(fullPath));
361          item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
362          item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
363          if ((mainWin->m_miscDebug) && (m_debugTrap)) {
364             Pmsg0(000, "Added Base \"letter\":/\n");
365          }
366          m_dirPaths.insert(m_cwd, item);
367       }
368    }
369  
370    /* is it already existent ?? */
371    if (!m_dirPaths.contains(fullPath)) {
372       QTreeWidgetItem *item = NULL;
373       QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
374       if (parent) {
375          /* new directories to add */
376          item = new QTreeWidgetItem(parent);
377          item->setText(0, newdir.toUtf8().data());
378          item->setData(0, Qt::UserRole, QVariant(fullPath));
379          item->setCheckState(0, Qt::Unchecked);
380          /* Store the current state of the check status in column 1, which at
381           * this point has no text*/
382          item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
383       } else {
384          ok = false;
385          if ((mainWin->m_miscDebug) && (m_debugTrap)) {
386             QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
387                  .arg(m_cwd)
388                  .arg(newdir);
389             Pmsg0(000, msg.toUtf8().data());
390          }
391       }
392       /* insert into hash */
393       if (ok) {
394          if ((mainWin->m_miscDebug) && (m_debugTrap)) {
395             Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
396          }
397          m_dirPaths.insert(fullPath, item);
398          added = true;
399       }
400    }
401    return added;
402 }
403
404 /*
405  * Virtual function which is called when this page is visible on the stack
406  */
407 void restoreTree::currentStackItem()
408 {
409    if(!m_populated) {
410       if (!m_console->preventInUseConnect())
411          return;
412       setupPage();
413       m_populated=true;
414    }
415 }
416
417 /*
418  * Populate the tree when refresh button pushed.
419  */
420 void restoreTree::refreshButtonPushed()
421 {
422    populateDirectoryTree();
423 }
424
425 /*
426  * Set the values of non-job combo boxes to the job defaults
427  */
428 void restoreTree::jobComboChanged(int)
429 {
430    if (jobCombo->currentText() == "Any") {
431       fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
432       return;
433    }
434    job_defaults job_defs;
435
436    (void)index;
437    job_defs.job_name = jobCombo->currentText();
438    if (m_console->get_job_defaults(job_defs)) {
439       fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
440       clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
441    }
442 }
443
444 /*
445  * Function to populate the file list table
446  */
447 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
448 {
449    if (item == NULL)
450       return;
451
452    m_fileCheckStateList.clear();
453    disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
454            this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
455    QBrush blackBrush(Qt::black);
456    QString directory = item->data(0, Qt::UserRole).toString();
457    directoryLabel->setText("Present Working Directory : " + directory);
458    QString cmd =
459       "SELECT DISTINCT Filename.Name AS FileName"
460       " FROM File "
461       " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
462       " INNER JOIN Path ON (Path.PathId=File.PathId)"
463       " INNER JOIN Job ON (File.JobId=Job.JobId)"
464       " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
465       " AND Job.Jobid IN (" + m_jobQuery + ")"
466       " ORDER BY FileName";
467  
468    QStringList headerlist = (QStringList() << "File Name");
469    fileTable->clear();
470    /* Also clear the version table here */
471    versionTable->clear();
472    versionFileLabel->setText("");
473    versionTable->setRowCount(0);
474    versionTable->setColumnCount(0);
475    fileTable->setColumnCount(headerlist.size());
476    fileTable->setHorizontalHeaderLabels(headerlist);
477
478    if (mainWin->m_sqlDebug) {
479       Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
480    }
481    QStringList results;
482    if (m_console->sql_cmd(cmd, results)) {
483    
484       QTableWidgetItem* tableItem;
485       QString field;
486       QStringList fieldlist;
487       fileTable->setRowCount(results.size());
488
489       int row = 0;
490       /* Iterate through the record returned from the query */
491       foreach (QString resultline, results) {
492          /* Iterate through fields in the record */
493          int column = 0;
494          fieldlist = resultline.split("\t");
495          foreach (field, fieldlist) {
496             field = field.trimmed();  /* strip leading & trailing spaces */
497             tableItem = new QTableWidgetItem(field, 1);
498             /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
499              *  | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable 
500              *  | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
501             tableItem->setForeground(blackBrush);
502             /* Just in case a column ever gets added */
503             if (column == 0) {
504                Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
505                tableItem->setFlags(flag);
506                tableItem->setData(Qt::UserRole, QVariant(directory));
507                fileTable->setItem(row, column, tableItem);
508                m_fileCheckStateList.append(Qt::Unchecked);
509                tableItem->setCheckState(Qt::Unchecked);
510             }
511             column++;
512          }
513          row++;
514       }
515       fileTable->setRowCount(row);
516    }
517    fileTable->resizeColumnsToContents();
518    fileTable->resizeRowsToContents();
519    fileTable->verticalHeader()->hide();
520    connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
521            this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
522    if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
523    updateFileTableChecks();
524 }
525
526 /*
527  * Function to populate the version table
528  */
529 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
530 {
531    if (fileTableItem == NULL)
532       return;
533
534    m_versionCheckStateList.clear();
535    disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
536            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
537
538    QString file = fileTableItem->text();
539    versionFileLabel->setText(file);
540    QString directory = fileTableItem->data(Qt::UserRole).toString();
541
542    QBrush blackBrush(Qt::black);
543    QString cmd = 
544       "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
545       " FROM File"
546       " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
547       " INNER JOIN Path ON (Path.PathId=File.PathId)"
548       " INNER JOIN Job ON (File.JobId=Job.JobId)"
549       " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
550       " AND Job.Jobid IN (" + m_jobQuery + ")"
551       " ORDER BY Job.EndTime DESC";
552
553    QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
554    versionTable->clear();
555    versionTable->setColumnCount(headerlist.size());
556    versionTable->setHorizontalHeaderLabels(headerlist);
557
558    if (mainWin->m_sqlDebug) {
559       Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
560    }
561    QStringList results;
562    if (m_console->sql_cmd(cmd, results)) {
563    
564       QTableWidgetItem* tableItem;
565       QString field;
566       QStringList fieldlist;
567       versionTable->setRowCount(results.size());
568
569       int row = 0;
570       /* Iterate through the record returned from the query */
571       foreach (QString resultline, results) {
572          fieldlist = resultline.split("\t");
573          int column = 0;
574          /* remove directory */
575          if (fieldlist[0].trimmed() != "") {
576             /* Iterate through fields in the record */
577             foreach (field, fieldlist) {
578                field = field.trimmed();  /* strip leading & trailing spaces */
579                tableItem = new QTableWidgetItem(field, 1);
580                tableItem->setFlags(0);
581                tableItem->setForeground(blackBrush);
582                tableItem->setData(Qt::UserRole, QVariant(directory));
583                versionTable->setItem(row, column, tableItem);
584
585                if (column == 0) {
586                   Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
587                   tableItem->setFlags(flag);
588                   m_versionCheckStateList.append(Qt::Unchecked);
589                   tableItem->setCheckState(Qt::Unchecked);
590                }
591                column++;
592             }
593             row++;
594          }
595       }
596    }
597    versionTable->resizeColumnsToContents();
598    versionTable->resizeRowsToContents();
599    versionTable->verticalHeader()->hide();
600    connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
601            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
602    updateVersionTableChecks();
603 }
604
605 /*
606  * Save user settings associated with this page
607  */
608 void restoreTree::writeSettings()
609 {
610    QSettings settings(m_console->m_dir->name(), "bat");
611    settings.beginGroup("RestoreTree");
612    settings.setValue("splitterSizes", splitter->saveState());
613    settings.endGroup();
614 }
615
616 /*
617  * Read and restore user settings associated with this page
618  */
619 void restoreTree::readSettings()
620 {
621    QSettings settings(m_console->m_dir->name(), "bat");
622    settings.beginGroup("RestoreTree");
623    splitter->restoreState(settings.value("splitterSizes").toByteArray());
624    settings.endGroup();
625 }
626
627 /*
628  * This is a funcion to accomplish the one thing I struggled to figure out what
629  * was taking so long.  It add the icons, but after the tree is made.  Seemed to
630  * work fast after changing from svg to png file for graphic.
631  */
632 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
633 {
634    int childCount = item->childCount();
635    for (int i=0; i<childCount; i++) {
636       QTreeWidgetItem *child = item->child(i);
637       if (child->icon(0).isNull())
638          child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
639    }
640 }
641
642 /*
643  * I wanted a table to show what jobs meet the criterion and are being used to
644  * populate the directory tree and file and version tables.
645  */
646 void restoreTree::populateJobTable()
647 {
648    QBrush blackBrush(Qt::black);
649    QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
650    jobTable->clear();
651    jobTable->setColumnCount(headerlist.size());
652    jobTable->setHorizontalHeaderLabels(headerlist);
653    QString jobQuery =
654       "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
655       " FROM Job" + m_jobQueryPart +
656       " ORDER BY Job.EndTime DESC";
657    /* If Limit check box for limit records returned is checked  */
658    if (limitCheckBox->checkState() == Qt::Checked) {
659       QString limit;
660       limit.setNum(limitSpinBox->value());
661       jobQuery += " LIMIT " + limit;
662    }
663    if (mainWin->m_sqlDebug) {
664       Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
665    }
666
667    QStringList results;
668    if (m_console->sql_cmd(jobQuery, results)) {
669    
670       QTableWidgetItem* tableItem;
671       QString field;
672       QStringList fieldlist;
673       jobTable->setRowCount(results.size());
674
675       int row = 0;
676       /* Iterate through the record returned from the query */
677       foreach (QString resultline, results) {
678          fieldlist = resultline.split("\t");
679          int column = 0;
680          /* remove directory */
681          if (fieldlist[0].trimmed() != "") {
682             /* Iterate through fields in the record */
683             foreach (field, fieldlist) {
684                field = field.trimmed();  /* strip leading & trailing spaces */
685                tableItem = new QTableWidgetItem(field, 1);
686                tableItem->setFlags(0);
687                tableItem->setForeground(blackBrush);
688                jobTable->setItem(row, column, tableItem);
689                if (column == 0) {
690                   Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
691                   tableItem->setFlags(flag);
692                   tableItem->setCheckState(Qt::Checked);
693                   tableItem->setBackground(Qt::green);
694                }
695                column++;
696             }
697             row++;
698          }
699       }
700    }
701    jobTable->resizeColumnsToContents();
702    jobTable->resizeRowsToContents();
703    jobTable->verticalHeader()->hide();
704 }
705
706 /*
707  * When a directory item is "changed" check the state of the checkable item
708  * to see if it is different than what it was which is stored in Qt::UserRole
709  * of the 2nd column, column 1, of the tree widget.
710  */
711 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
712 {
713    Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
714    Qt::CheckState curState = item->checkState(0);
715    QTreeWidgetItem* parent = item->parent();
716    Qt::CheckState parState;
717    if (parent) parState = parent->checkState(0);
718    else parState = (Qt::CheckState)3;
719    if (mainWin->m_rtDirICDebug) {
720       QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
721          .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
722       Pmsg1(000, "%s", msg.toUtf8().data()); }
723    /* I only care when the check state changes */
724    if (prevState == curState) {
725       if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
726       return;
727    }
728
729    if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
730       if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
731       directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
732       curState = Qt::PartiallyChecked;
733    }
734    if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
735       if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
736       directoryTreeDisconnectedSet(item, Qt::Unchecked);
737       curState = Qt::Unchecked;
738    }
739    if (mainWin->m_rtDirICDebug) {
740       QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
741          .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
742       Pmsg1(000, "%s", msg.toUtf8().data()); }
743
744    item->setData(1, Qt::UserRole, QVariant(curState));
745    Qt::CheckState childState = curState;
746    if (childState == Qt::Checked)
747       childState = Qt::PartiallyChecked;
748    setCheckofChildren(item, childState);
749
750    /* Remove items from the exception lists.  The multi exception list is my index
751     * of what exceptions can be removed when the directory is known*/
752    QString directory = item->data(0, Qt::UserRole).toString();
753    QStringList fullPathList = m_fileExceptionMulti.values(directory);
754    int fullPathListCount = fullPathList.count();
755    if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
756    foreach (QString fullPath, fullPathList) {
757       /* If there is no value in the hash for the key fullPath a value of 3 will be returned
758        * which will match no Qt::xxx values */
759       Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
760       if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
761       if (hashState == Qt::Unchecked) {
762          fileExceptionRemove(fullPath, directory);
763          m_versionExceptionHash.remove(fullPath);
764          if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
765       }
766       if (hashState == Qt::Checked) {
767          fileExceptionRemove(fullPath, directory);
768          m_versionExceptionHash.remove(fullPath);
769          if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
770       }
771    }
772
773    if (item == directoryTree->currentItem()) {
774       if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
775       updateFileTableChecks();
776       versionTable->clear();
777       versionTable->setRowCount(0);
778       versionTable->setColumnCount(0);
779    }
780    if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
781 }
782
783 /*
784  * When a directory item check state is changed, this function iterates through
785  * all subdirectories and sets all to the passed state, which is either partially
786  * checked or unchecked.
787  */
788 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
789 {
790    int childCount;
791    childCount = item->childCount();
792    for (int i=0; i<childCount; i++) {
793       QTreeWidgetItem *child = item->child(i);
794       child->setData(1, Qt::UserRole, QVariant(state));
795       child->setCheckState(0, state);
796       setCheckofChildren(child, state);
797    }
798 }
799
800 /*
801  * When a File Table Item is "changed" check to see if the state of the checkable
802  * item has changed which is stored in m_fileCheckStateList
803  * If changed store in a hash m_fileExceptionHash that whether this file should be
804  * restored or not.
805  * Called as a slot, connected after populated (after directory current changed called)
806  */
807 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
808 {
809    /* get the previous and current check states */
810    int row = fileTable->row(item);
811    Qt::CheckState prevState;
812    /* prevent a segfault */
813    prevState = m_fileCheckStateList[row];
814    Qt::CheckState curState = item->checkState();
815
816    /* deterimine the default state from the state of the directory */
817    QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
818    Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
819    Qt::CheckState defState = Qt::PartiallyChecked;
820    if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
821
822    /* determine if it is already in the m_fileExceptionHash */
823    QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
824    QString file = item->text();
825    QString fullPath = directory + file;
826    Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
827    int verJobNum = m_versionExceptionHash.value(fullPath, 0);
828
829    if (mainWin->m_rtFileTabICDebug) {
830       QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
831          .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
832       Pmsg1(000, "%s", msg.toUtf8().data()); }
833
834    /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
835    if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
836       /* it can behave as defaulted so current of unchecked is fine */
837       if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
838       fileExceptionRemove(fullPath, directory);
839       m_versionExceptionHash.remove(fullPath);
840    } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
841       if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
842       fileExceptionInsert(fullPath, directory, Qt::Unchecked);
843    } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
844       /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
845       if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
846       fileExceptionRemove(fullPath, directory);
847    } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
848       /* Check dir, check version, attempt uncheck in file
849        * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
850       if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
851       fileExceptionRemove(fullPath, directory);
852       m_versionExceptionHash.remove(fullPath);
853    } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
854       /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
855       if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
856    } else if (prevState != curState) {
857       if (mainWin->m_rtFileTabICDebug) Pmsg2(000, "  THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
858       /* A user did not set the check state to Partially checked, ignore if so */
859       if (curState != Qt::PartiallyChecked) {
860          if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
861             if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "  got here\n");
862          } else {
863             if (mainWin->m_rtFileTabICDebug) Pmsg2(000, "  Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
864             fileExceptionInsert(fullPath, directory, curState);
865          }
866       } else {
867          if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
868          /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
869          m_versionExceptionHash.remove(fullPath);
870       }
871    }
872
873    updateFileTableChecks();
874    updateVersionTableChecks();
875 }
876
877 /*
878  * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
879  */
880 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
881 {
882    m_fileExceptionHash.insert(fullPath, state);
883    m_fileExceptionMulti.insert(direcotry, fullPath);
884    directoryIconStateInsert(fullPath, state);
885 }
886
887 /*
888  * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
889  */
890 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
891 {
892    m_fileExceptionHash.remove(fullPath);
893    /* pull the list of values in the multi */
894    QStringList fullPathList = m_fileExceptionMulti.values(directory);
895    /* get the index of the fullpath to remove */
896    int index = fullPathList.indexOf(fullPath);
897    if (index != -1) {
898       /* remove the desired item in the list */
899       fullPathList.removeAt(index);
900       /* remove the entire list from the multi */
901       m_fileExceptionMulti.remove(directory);
902       /* readd the remaining */
903       foreach (QString fp, fullPathList) {
904          m_fileExceptionMulti.insert(directory, fp);
905       }
906    }
907    directoryIconStateRemove();
908 }
909
910 /*
911  * Overloaded function to be called from the slot and from other places to set the state
912  * of the check marks in the version table
913  */
914 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
915 {
916    /* get the previous and current check states */
917    int row = versionTable->row(item);
918    QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
919    Qt::CheckState prevState = m_versionCheckStateList[row];
920    Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
921    m_versionCheckStateList[row] = curState;
922
923    /* deterimine the default state from the state of the file */
924    QTableWidgetItem *fileTableItem = fileTable->currentItem();
925    Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
926
927    /* determine the default state */
928    Qt::CheckState defState;
929    if (row == 0) {
930       defState = Qt::PartiallyChecked;
931       if (fileState == Qt::Unchecked)
932          defState = Qt::Unchecked;
933    }
934    else
935       defState = Qt::Unchecked;
936
937    /* determine if it is already in the versionExceptionHash */
938    QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
939    Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
940    QString file = fileTableItem->text();
941    QString fullPath = directory + file;
942    int thisJobNum = colZeroItem->text().toInt();
943    int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
944
945    if (mainWin->m_rtVerTabICDebug) {
946       QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
947          .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
948          .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
949       Pmsg1(000, "%s", msg.toUtf8().data()); }
950    /* if changed from partially checked to checked, make it unchecked */
951    if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
952       if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
953       fileTableItem->setCheckState(Qt::Checked);
954    } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
955       //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
956       if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
957       fileExceptionRemove(fullPath, directory);
958    } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
959       //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
960       if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
961       m_versionExceptionHash.remove(fullPath);
962       fileExceptionRemove(fullPath, directory);
963    } else if ((curState == Qt::Checked) && (row == 0)) {
964       if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
965       m_versionExceptionHash.remove(fullPath);
966    } else if (prevState != curState) {
967       if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "  THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
968       if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
969          if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
970          m_versionExceptionHash.insert(fullPath, thisJobNum);
971          if (fileState != Qt::Checked) {
972             if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
973             fileExceptionInsert(fullPath, directory, curState);
974          }
975       } else {
976          if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
977       }
978    } else {
979      if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
980    }
981
982    updateFileTableChecks();
983    updateVersionTableChecks();
984 }
985
986 /*
987  * Simple function to set the check state in the file table by disconnecting the
988  * signal/slot the setting then reconnecting the signal/slot
989  */
990 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
991 {
992    disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
993            this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
994    item->setCheckState(state);
995    if (color) item->setBackground(Qt::yellow);
996    else item->setBackground(Qt::white);
997    connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
998            this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
999 }
1000
1001 /*
1002  * Simple function to set the check state in the version table by disconnecting the
1003  * signal/slot the setting then reconnecting the signal/slot
1004  */
1005 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1006 {
1007    disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1008            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1009    item->setCheckState(state);
1010    connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1011            this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1012 }
1013
1014 /*
1015  * Simple function to set the check state in the directory tree by disconnecting the
1016  * signal/slot the setting then reconnecting the signal/slot
1017  */
1018 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1019 {
1020    disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1021            this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1022    item->setCheckState(0, state);
1023    connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1024            this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1025 }
1026
1027 /*
1028  * Simplify the updating of the check state in the File table by iterating through
1029  * each item in the file table to determine it's appropriate state.
1030  * !! Will probably want to concoct a way to do this without iterating for the possibility
1031  * of the very large directories.
1032  */
1033 void restoreTree::updateFileTableChecks()
1034 {
1035    /* deterimine the default state from the state of the directory */
1036    QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1037    Qt::CheckState dirState = dirTreeItem->checkState(0);
1038
1039    QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1040
1041    /* Update the items in the version table */
1042    int rcnt = fileTable->rowCount();
1043    for (int row=0; row<rcnt; row++) {
1044       QTableWidgetItem* item = fileTable->item(row, 0);
1045
1046       Qt::CheckState curState = item->checkState();
1047       Qt::CheckState newState = Qt::PartiallyChecked;
1048       if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1049
1050       /* determine if it is already in the m_fileExceptionHash */
1051       QString file = item->text();
1052       QString fullPath = dirName + file;
1053       Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1054       int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1055
1056       if (hashState != 3) newState = hashState;
1057
1058       if (mainWin->m_rtUpdateFTDebug) {
1059          QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1060             .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1061          Pmsg1(000, "%s", msg.toUtf8().data());
1062       }
1063
1064       bool docolor = false;
1065       if (hashJobNum != 0) docolor = true;
1066       bool isyellow = item->background().color() == QColor(Qt::yellow);
1067       if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1068          fileTableDisconnectedSet(item, newState, docolor);
1069       m_fileCheckStateList[row] = newState;
1070    }
1071 }
1072
1073 /*
1074  * Simplify the updating of the check state in the Version table by iterating through
1075  * each item in the file table to determine it's appropriate state.
1076  */
1077 void restoreTree::updateVersionTableChecks()
1078 {
1079    /* deterimine the default state from the state of the directory */
1080    QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1081    Qt::CheckState dirState = dirTreeItem->checkState(0);
1082    QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1083
1084    /* deterimine the default state from the state of the file */
1085    QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1086    Qt::CheckState fileState = fileTableItem->checkState();
1087    QString file = fileTableItem->text();
1088    QString fullPath = dirName + file;
1089    int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1090
1091    /* Update the items in the version table */
1092    int cnt = versionTable->rowCount();
1093    for (int row=0; row<cnt; row++) {
1094       QTableWidgetItem* item = versionTable->item(row, 0);
1095
1096       Qt::CheckState curState = item->checkState();
1097       Qt::CheckState newState = Qt::Unchecked;
1098
1099       if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1100          newState = Qt::PartiallyChecked;
1101       /* determine if it is already in the versionExceptionHash */
1102       if (hashJobNum) {
1103          int thisJobNum = item->text().toInt();
1104          if (thisJobNum == hashJobNum)
1105             newState = Qt::Checked;
1106       }
1107       if (mainWin->m_rtChecksDebug) {
1108          QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1109             .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1110          Pmsg1(000, "%s", msg.toUtf8().data());
1111       }
1112       if (newState != curState)
1113          versionTableDisconnectedSet(item, newState);
1114       m_versionCheckStateList[row] = newState;
1115    }
1116 }
1117
1118 /*
1119  * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1120  */
1121 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1122 {
1123    int index;
1124    bool done = false;
1125    QString fullPath = fullPath_in;
1126    QString direct, path;
1127    while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1128       direct = path = fullPath;
1129       path.replace(index+1, fullPath.length()-index-1, "");
1130       direct.replace(0, index+1, "");
1131       if (false) {
1132          QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1133                     .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1134          Pmsg0(000, msg.toUtf8().data());
1135       }
1136       fullPath = path;
1137       subPaths.append(fullPath);
1138    }
1139 }
1140
1141 /*
1142  * A Function to set the icon state and insert a record into
1143  * m_directoryIconStateHash when an exception is added by the user
1144  */
1145 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1146 {
1147    QStringList paths;
1148    fullPathtoSubPaths(paths, fullPath);
1149    /* an exception that causes the item in the file table to be "Checked" has occured */
1150    if (excpState == Qt::Checked) {
1151       bool foundAsUnChecked = false;
1152       QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1153       if (firstItem) {
1154          if (firstItem->checkState(0) == Qt::Unchecked)
1155             foundAsUnChecked = true;
1156       }
1157       if (foundAsUnChecked) {
1158           /* as long as directory item is Unchecked, set icon state to "green check" */
1159          bool done = false;
1160          QListIterator<QString> siter(paths);
1161          while (siter.hasNext() && !done) {
1162             QString path = siter.next();
1163             QTreeWidgetItem *item = m_dirPaths.value(path);
1164             if (item) {
1165                if (item->checkState(0) != Qt::Unchecked)
1166                   done = true;
1167                else {
1168                   directorySetIcon(1, FolderGreenChecked, path, item);
1169                   if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1170                }
1171             }
1172          }
1173       } else {
1174          /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1175          if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1176          bool done = false;
1177          QListIterator<QString> siter(paths);
1178          while (siter.hasNext() && !done) {
1179             QString path = siter.next();
1180             QTreeWidgetItem *item = m_dirPaths.value(path);
1181             if (item) {  /* if the directory item is checked, set icon state to unchecked "green check" */
1182                if (item->checkState(0) == Qt::Checked)
1183                   done = true;
1184                directorySetIcon(1, FolderGreenChecked, path, item);
1185                if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1186             }
1187          }
1188       }
1189    }
1190    /* an exception that causes the item in the file table to be "Unchecked" has occured */
1191    if (excpState == Qt::Unchecked) {
1192       bool done = false;
1193       QListIterator<QString> siter(paths);
1194       while (siter.hasNext() && !done) {
1195          QString path = siter.next();
1196          QTreeWidgetItem *item = m_dirPaths.value(path);
1197          if (item) {  /* if the directory item is checked, set icon state to unchecked "white check" */
1198             if (item->checkState(0) == Qt::Checked)
1199                done = true;
1200             directorySetIcon(1, FolderWhiteChecked, path, item);
1201             if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1202          }
1203       }
1204    }
1205 }
1206
1207 /*
1208  * A function to set the icon state back to "folder" and to remove a record from
1209  * m_directoryIconStateHash when an exception is removed by a user.
1210  */
1211 void restoreTree::directoryIconStateRemove()
1212 {
1213    QHash<QString, int> shouldBeIconStateHash;
1214    /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1215    /* Use iterator tera to iterate through m_fileExceptionHash */
1216    QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1217    while (tera.hasNext()) {
1218       tera.next();
1219       if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1220
1221       QString keyPath = tera.key();
1222       Qt::CheckState state = tera.value();
1223
1224       QStringList paths;
1225       fullPathtoSubPaths(paths, keyPath);
1226       /* if the state of the item in m_fileExceptionHash is checked 
1227        * each of the subpaths should be "Checked Green" */
1228       if (state == Qt::Checked) {
1229
1230          bool foundAsUnChecked = false;
1231          QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1232          if (firstItem) {
1233             if (firstItem->checkState(0) == Qt::Unchecked)
1234                foundAsUnChecked = true;
1235          }
1236          if (foundAsUnChecked) {
1237             /* The right most directory is Unchecked, iterate leftwards
1238              * as long as directory item is Unchecked, set icon state to "green check" */
1239             bool done = false;
1240             QListIterator<QString> siter(paths);
1241             while (siter.hasNext() && !done) {
1242                QString path = siter.next();
1243                QTreeWidgetItem *item = m_dirPaths.value(path);
1244                if (item) {
1245                   if (item->checkState(0) != Qt::Unchecked)
1246                      done = true;
1247                   else {
1248                      shouldBeIconStateHash.insert(path, FolderGreenChecked);
1249                      if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1250                   }
1251                }
1252             }
1253          }
1254          else {
1255             /* The right most directory is Unchecked, iterate leftwards
1256              * until directory item is Checked, set icon state to "green check" */
1257             bool done = false;
1258             QListIterator<QString> siter(paths);
1259             while (siter.hasNext() && !done) {
1260                QString path = siter.next();
1261                QTreeWidgetItem *item = m_dirPaths.value(path);
1262                if (item) {
1263                   if (item->checkState(0) == Qt::Checked)
1264                      done = true;
1265                   shouldBeIconStateHash.insert(path, FolderGreenChecked);
1266                }
1267             }
1268          }
1269       }
1270       /* if the state of the item in m_fileExceptionHash is UNChecked
1271        * each of the subpaths should be "Checked white" until the tree item
1272        * which represents that path is Qt::Checked */
1273       if (state == Qt::Unchecked) {
1274          bool done = false;
1275          QListIterator<QString> siter(paths);
1276          while (siter.hasNext() && !done) {
1277             QString path = siter.next();
1278             QTreeWidgetItem *item = m_dirPaths.value(path);
1279             if (item) {
1280                if (item->checkState(0) == Qt::Checked)
1281                   done = true;
1282                shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1283             }
1284          }
1285       }
1286    }
1287    /* now iterate through m_directoryIconStateHash which are the items that are checked
1288     * and remove all of those that are not in shouldBeIconStateHash */
1289    QHashIterator<QString, int> iter(m_directoryIconStateHash);
1290    while (iter.hasNext()) {
1291       iter.next();
1292       if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1293
1294       QString keyPath = iter.key();
1295       if (shouldBeIconStateHash.value(keyPath)) {
1296          if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1297          //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1298          int newval = shouldBeIconStateHash.value(keyPath);
1299          newval = ~newval;
1300          newval = newval & FolderBothChecked;
1301          QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1302          if (item)
1303             directorySetIcon(0, newval, keyPath, item);
1304       } else {
1305          if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1306          QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1307          if (item)
1308             directorySetIcon(0, FolderBothChecked, keyPath, item);
1309             //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1310             //m_directoryIconStateHash.remove(keyPath);
1311       }
1312    }
1313 }
1314
1315 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1316    int newval;
1317    /* we are adding a check type white or green */
1318    if (operation > 0) {
1319       /* get the old val and "bitwise OR" with the change */
1320       newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1321       if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1322       m_directoryIconStateHash.insert(path, newval);
1323    } else {
1324    /* we are removing a check type white or green */
1325       newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1326       if (newval == 0) {
1327          if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1328          m_directoryIconStateHash.remove(path);
1329       }
1330       else {
1331          if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1332          m_directoryIconStateHash.insert(path, newval);
1333       }
1334    }
1335    if (newval == FolderUnchecked)
1336       item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1337    else if (newval == FolderGreenChecked)
1338       item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1339    else if (newval == FolderWhiteChecked)
1340       item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1341    else if (newval == FolderBothChecked)
1342       item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1343 }
1344
1345 /*
1346  * Test Button
1347  */
1348 void restoreTree::restoreButtonPushed()
1349 {
1350    /* Set progress bars and repaint */
1351    prLabel1->setVisible(true);
1352    prLabel1->setText("Task 1 of 3");
1353    prLabel2->setVisible(true);
1354    prLabel2->setText("Processing Checked directories");
1355    prBar1->setVisible(true);
1356    prBar1->setRange(0, 3);
1357    prBar1->setValue(0);
1358    prBar2->setVisible(true);
1359    prBar2->setRange(0, 0);
1360    repaint();
1361    QMultiHash<int, QString> versionFilesMulti;
1362    int vFMCounter = 0;
1363    QHash <QString, bool> fullPathDone;
1364    QHash <QString, int> fileIndexHash;
1365    if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1366       Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1367    /* Use a tree widget item iterator to count directories for the progress bar */
1368    QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1369    int ditcount = 0;
1370    while (*diterc) {
1371       ditcount += 1;
1372       ++diterc;
1373    } /* while (*diterc) */
1374    prBar2->setRange(0, ditcount);
1375    prBar2->setValue(0);
1376    ditcount = 0;
1377    /* Use a tree widget item iterator filtering for Checked Items */
1378    QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1379    while (*diter) {
1380       QString directory = (*diter)->data(0, Qt::UserRole).toString();
1381       if (mainWin->m_rtRestore1Debug)
1382       Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1383       /* With a checked directory, query for the files in the directory */
1384
1385       QString cmd =
1386          "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1387          " FROM"
1388          " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1389            " FROM File"
1390              " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1391              " INNER JOIN Path ON (Path.PathId=File.PathId)"
1392              " INNER JOIN Job ON (Job.JobId=File.JobId)"
1393            " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1394            "  AND Job.Jobid IN (" + m_jobQuery + ")"
1395            " GROUP BY Filename.Name"
1396          ") t1, File "
1397            " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1398            " INNER JOIN Path ON (Path.PathId=File.PathId)"
1399            " INNER JOIN Job ON (Job.JobId=File.JobId)"
1400          " WHERE"
1401            " Path.Path='" + directory + "'"
1402            " AND Filename.Name=t1.Filename"
1403            " AND Job.Jobid=t1.JobId"
1404          " ORDER BY Filename";
1405
1406       if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1407       QStringList results;
1408       if (m_console->sql_cmd(cmd, results)) {
1409          QStringList fieldlist;
1410    
1411          int row = 0;
1412          /* Iterate through the record returned from the query */
1413          foreach (QString resultline, results) {
1414             /* Iterate through fields in the record */
1415             int column = 0;
1416             QString fullPath = "";
1417             Qt::CheckState fileExcpState = (Qt::CheckState)4;
1418             fieldlist = resultline.split("\t");
1419             int version = 0;
1420             int fileIndex = 0;
1421             foreach (QString field, fieldlist) {
1422                if (column == 0) {
1423                   fullPath = directory + field;
1424                }
1425                if (column == 1) {
1426                   version = field.toInt();
1427                }
1428                if (column == 2) {
1429                   fileIndex = field.toInt();
1430                }
1431                column++;
1432             }
1433             fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1434             
1435             int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1436             if (fileExcpState != Qt::Unchecked) {
1437                QString debugtext;
1438                if (excpVersion != 0) {
1439                   debugtext = QString("*E* version=%1").arg(excpVersion);
1440                   version = excpVersion;
1441                   fileIndex = queryFileIndex(fullPath, excpVersion);
1442                } else
1443                   debugtext = QString("___ version=%1").arg(version);
1444                if (mainWin->m_rtRestore1Debug)
1445                   Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1446                fullPathDone.insert(fullPath, 1);
1447                fileIndexHash.insert(fullPath, fileIndex);
1448                versionFilesMulti.insert(version, fullPath);
1449                vFMCounter += 1;
1450             }
1451             row++;
1452          }
1453       }
1454       ditcount += 1;
1455       prBar2->setValue(ditcount);
1456       ++diter;
1457    } /* while (*diter) */
1458    prBar1->setValue(1);
1459    prLabel1->setText("Task 2 of 3");
1460    prLabel2->setText("Processing Exceptions");
1461    prBar2->setRange(0, 0);
1462    repaint();
1463
1464    /* There may be some exceptions not accounted for yet with fullPathDone */
1465    QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1466    while (ftera.hasNext()) {
1467       ftera.next();
1468       QString fullPath = ftera.key();
1469       Qt::CheckState state = ftera.value();
1470       if (state != 0) {
1471          /* now we don't want the ones already done */
1472          if (fullPathDone.value(fullPath, 0) == 0) {
1473             int version = m_versionExceptionHash.value(fullPath, 0);
1474             int fileIndex = 0;
1475             QString debugtext = "";
1476             if (version != 0) {
1477                fileIndex = queryFileIndex(fullPath, version);
1478                debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1479             } else {
1480                version = mostRecentVersionfromFullPath(fullPath);
1481                if (version) {
1482                   fileIndex = queryFileIndex(fullPath, version);
1483                   debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1484                } else
1485                   debugtext = QString("Error det vers").arg(version);
1486             }
1487             if (mainWin->m_rtRestore1Debug)
1488                Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1489             versionFilesMulti.insert(version, fullPath);
1490             vFMCounter += 1;
1491             fileIndexHash.insert(fullPath, fileIndex);
1492          } /* if fullPathDone.value(fullPath, 0) == 0 */
1493       } /* if state != 0 */
1494    } /* while ftera.hasNext */
1495    /* The progress bars for the next step */
1496    prBar1->setValue(2);
1497    prLabel1->setText("Task 3 of 3");
1498    prLabel2->setText("Filling Database Table");
1499    prBar2->setRange(0, vFMCounter);
1500    vFMCounter = 0;
1501    prBar2->setValue(vFMCounter);
1502    repaint();
1503
1504    /* now for the final spit out of the versions and lists of files for each version */
1505    QHash<int, int> doneKeys;
1506    QHashIterator<int, QString> vFMiter(versionFilesMulti);
1507    QString tempTable = "";
1508    QList<int> jobList;
1509    while (vFMiter.hasNext()) {
1510       vFMiter.next();
1511       int fversion = vFMiter.key();
1512       /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1513       if (doneKeys.value(fversion, 0) == 0) {
1514          if (tempTable == "") {
1515             QSettings settings("www.bacula.org", "bat");
1516             settings.beginGroup("Restore");
1517             int counter = settings.value("Counter", 1).toInt();
1518             settings.setValue("Counter", counter+1);
1519             settings.endGroup();
1520             tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1521             QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1522             if (mainWin->m_sqlDebug)
1523                Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1524             QStringList results;
1525             if (!m_console->sql_cmd(sqlcmd, results))
1526                Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1527          }
1528
1529          if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1530          QStringList fullPathList = versionFilesMulti.values(fversion);
1531          /* create the command to perform the restore */
1532          foreach(QString ffullPath, fullPathList) {
1533             int fileIndex = fileIndexHash.value(ffullPath);
1534             if (mainWin->m_rtRestore2Debug) Pmsg2(000, "  file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1535             QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1536             if (mainWin->m_rtRestore3Debug)
1537                Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1538             QStringList results;
1539             if (!m_console->sql_cmd(sqlcmd, results))
1540                Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1541             prBar2->setValue(++vFMCounter);
1542          } /* foreach fullPathList */
1543          doneKeys.insert(fversion,1);
1544          jobList.append(fversion);
1545       } /*  if (doneKeys.value(fversion, 0) == 0) */
1546    } /* while (vFMiter.hasNext()) */
1547    if (tempTable != "") {
1548       /* a table was made, lets run the job */
1549       QString jobOption = " jobid=\"";
1550       bool first = true;
1551       /* create a list of jobs comma separated */
1552       foreach (int job, jobList) {
1553          if (first) first = false;
1554          else jobOption += ",";
1555          jobOption += QString("%1").arg(job);
1556       }
1557       jobOption += "\"";
1558       QString cmd = QString("restore");
1559       cmd += jobOption +
1560              " file=\"?" + tempTable + "\" done";
1561       if (mainWin->m_commandDebug)
1562          Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1563       consoleCommand(cmd);
1564    }
1565    /* turn off the progress widgets */
1566    prBar1->setVisible(false);
1567    prBar2->setVisible(false);
1568    prLabel1->setVisible(false);
1569    prLabel2->setVisible(false);
1570 }
1571
1572 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1573 {
1574    int qversion = 0;
1575    QString directory, fileName;
1576    int index = m_slashregex.lastIndexIn(fullPath, -2);
1577    if (index != -1) {
1578       directory = fileName = fullPath;
1579       directory.replace(index+1, fullPath.length()-index-1, "");
1580       fileName.replace(0, index+1, "");
1581       if (false) {
1582          QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1583                     .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1584          Pmsg0(000, msg.toUtf8().data());
1585       }
1586       /* so now we need the latest version from the database */
1587       QString cmd =
1588          "SELECT MAX(Job.JobId)"
1589          " FROM File "
1590          " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1591          " INNER JOIN Path ON (Path.PathId=File.PathId)"
1592          " INNER JOIN Job ON (File.JobId=Job.JobId)"
1593          " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1594          " AND Job.Jobid IN (" + m_jobQuery + ")"
1595          " AND Filename.Name='" + fileName + "'"
1596          " GROUP BY Filename.Name";
1597  
1598       if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1599       QStringList results;
1600       if (m_console->sql_cmd(cmd, results)) {
1601          QStringList fieldlist;
1602          int row = 0;
1603          /* Iterate through the record returned from the query */
1604          foreach (QString resultline, results) {
1605             /* Iterate through fields in the record */
1606             int column = 0;
1607             fieldlist = resultline.split("\t");
1608             foreach (QString field, fieldlist) {
1609                if (column == 0) {
1610                   qversion = field.toInt();
1611                }
1612                column++;
1613             }
1614             row++;
1615          }
1616       }
1617    } /* if (index != -1) */
1618    return qversion;
1619 }
1620
1621
1622 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1623 {
1624    int qfileIndex = 0;
1625    QString directory, fileName;
1626    int index = m_slashregex.lastIndexIn(fullPath, -2);
1627    if (index != -1) {
1628       directory = fileName = fullPath;
1629       directory.replace(index+1, fullPath.length()-index-1, "");
1630       fileName.replace(0, index+1, "");
1631       if (false) {
1632          QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1633                     .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1634          Pmsg0(000, msg.toUtf8().data());
1635       }
1636       /* so now we need the latest version from the database */
1637       QString cmd =
1638          "SELECT"
1639           " File.FileIndex"
1640          " FROM File"
1641           " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1642           " INNER JOIN Path ON (Path.PathId=File.PathId)"
1643           " INNER JOIN Job ON (File.JobId=Job.JobId)"
1644          " WHERE"
1645           " Path.Path='" + directory + "'"
1646           " AND Filename.Name='" + fileName + "'"
1647           " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1648          " GROUP BY File.FileIndex";
1649  
1650       if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1651       QStringList results;
1652       if (m_console->sql_cmd(cmd, results)) {
1653          QStringList fieldlist;
1654          int row = 0;
1655          /* Iterate through the record returned from the query */
1656          foreach (QString resultline, results) {
1657             /* Iterate through fields in the record */
1658             int column = 0;
1659             fieldlist = resultline.split("\t");
1660             foreach (QString field, fieldlist) {
1661                if (column == 0) {
1662                   qfileIndex = field.toInt();
1663                }
1664                column++;
1665             }
1666             row++;
1667          }
1668       }
1669    } /* if (index != -1) */
1670    return qfileIndex;
1671 }