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