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