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