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