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