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