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