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