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