2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
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
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.
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
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
34 * Kern Sibbald, February MMVII
39 #include "restoretree.h"
42 restoreTree::restoreTree()
45 m_name = tr("Version Browser");
47 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
57 QGridLayout *gridLayout = new QGridLayout(this);
58 gridLayout->setSpacing(6);
59 gridLayout->setMargin(9);
60 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
62 m_splitter = new QSplitter(Qt::Vertical, this);
63 QScrollArea *area = new QScrollArea();
64 area->setObjectName(QString::fromUtf8("area"));
65 area->setWidget(widget);
66 area->setWidgetResizable(true);
67 m_splitter->addWidget(splitter);
68 m_splitter->addWidget(area);
70 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
72 /* progress widgets */
73 prBar1->setVisible(false);
74 prBar2->setVisible(false);
75 prLabel1->setVisible(false);
76 prLabel2->setVisible(false);
78 /* Set Defaults for check and spin for limits */
79 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
80 limitSpinBox->setValue(mainWin->m_recordLimitVal);
81 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
82 daysSpinBox->setValue(mainWin->m_daysLimitVal);
84 m_nullFileNameId = -1;
87 restoreTree::~restoreTree()
93 * Called from the constructor to set up the page widgets and connections.
95 void restoreTree::setupPage()
97 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
98 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
99 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
100 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
101 connect(clientCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
102 connect(fileSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
103 connect(limitCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
104 connect(daysCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
105 connect(daysSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
106 connect(limitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
107 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
108 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
109 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
110 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
111 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
112 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
113 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
114 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
115 connect(jobTable, SIGNAL(cellClicked(int, int)),
116 this, SLOT(jobTableCellClicked(int, int)));
118 QStringList titles = QStringList() << tr("Directories");
119 directoryTree->setHeaderLabels(titles);
120 clientCombo->addItems(m_console->client_list);
121 fileSetCombo->addItem(tr("Any"));
122 fileSetCombo->addItems(m_console->fileset_list);
123 jobCombo->addItem(tr("Any"));
124 jobCombo->addItems(m_console->job_list);
126 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
129 void restoreTree::updateRefresh()
131 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
132 m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
133 || (m_prevClientCombo != clientCombo->currentText())
134 || (m_prevFileSetCombo != fileSetCombo->currentText()
135 || (m_prevLimitSpinBox != limitSpinBox->value())
136 || (m_prevDaysSpinBox != daysSpinBox->value())
137 || (m_prevLimitCheckState != limitCheckBox->checkState())
138 || (m_prevDaysCheckState != daysCheckBox->checkState())
140 if (m_dropdownChanged) {
141 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
142 refreshLabel->setText(tr("Refresh From Re-Select"));
144 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
145 refreshLabel->setText(tr("Refresh From JobChecks"));
150 * When refresh button is pushed, perform a query getting the directories and
151 * use parseDirectory and addDirectory to populate the directory tree with items.
153 void restoreTree::populateDirectoryTree()
157 directoryTree->clear();
159 fileTable->setRowCount(0);
160 fileTable->setColumnCount(0);
161 versionTable->clear();
162 versionTable->setRowCount(0);
163 versionTable->setColumnCount(0);
164 m_fileExceptionHash.clear();
165 m_fileExceptionMulti.clear();
166 m_versionExceptionHash.clear();
167 m_directoryIconStateHash.clear();
170 int taskcount = 3, ontask = 1;
171 if (m_dropdownChanged) taskcount += 1;
173 /* Set progress bars and repaint */
174 prBar1->setVisible(true);
175 prBar1->setRange(0,taskcount);
177 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
178 prLabel1->setVisible(true);
179 prBar2->setVisible(true);
180 prBar2->setRange(0,0);
181 prLabel2->setText(tr("Querying Database"));
182 prLabel2->setVisible(true);
185 if (m_dropdownChanged) {
186 m_prevJobCombo = jobCombo->currentText();
187 m_prevClientCombo = clientCombo->currentText();
188 m_prevFileSetCombo = fileSetCombo->currentText();
189 m_prevLimitSpinBox = limitSpinBox->value();
190 m_prevDaysSpinBox = daysSpinBox->value();
191 m_prevLimitCheckState = limitCheckBox->checkState();
192 m_prevDaysCheckState = daysCheckBox->checkState();
194 prBar1->setValue(ontask++);
195 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
197 prBar2->setRange(0,0);
198 prLabel2->setText(tr("Querying Jobs"));
202 setJobsCheckedList();
203 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
205 if (m_checkedJobs != "") {
206 /* First get the filenameid of where the nae is null. These will be the directories
207 * This could be done in a subquery but postgres's query analyzer won't do the right
208 * thing like I want */
209 if (m_nullFileNameId == -1) {
210 QString cmd = "SELECT FilenameId FROM Filename WHERE name=''";
211 if (mainWin->m_sqlDebug)
212 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
214 if (m_console->sql_cmd(cmd, qres)) {
216 QStringList fieldlist = qres[0].split("\t");
217 QString field = fieldlist[0];
219 int val = field.toInt(&ok, 10);
220 if (ok) m_nullFileNameId = val;
224 /* now create the query to get the list of paths */
226 "SELECT DISTINCT Path.Path AS Path, File.PathId AS PathId"
228 " INNER JOIN Path ON (File.PathId=Path.PathId)";
229 if (m_nullFileNameId != -1)
230 cmd += " WHERE File.FilenameId=" + QString("%1").arg(m_nullFileNameId);
232 cmd += " WHERE File.FilenameId IN (SELECT FilenameId FROM Filename WHERE Name='')";
233 cmd += " AND File.Jobid IN (" + m_checkedJobs + ")"
235 if (mainWin->m_sqlDebug)
236 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
237 prBar1->setValue(ontask++);
238 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
240 prBar2->setRange(0,0);
241 prLabel2->setText(tr("Querying for Directories"));
244 m_directoryPathIdHash.clear();
245 bool querydone = false;
246 if (m_console->sql_cmd(cmd, results)) {
249 prLabel2->setText(tr("Processing Directories"));
250 prBar2->setRange(0,results.count());
253 if (mainWin->m_miscDebug)
254 Pmsg1(000, "Done with query %i results\n", results.count());
255 QStringList fieldlist;
256 foreach(QString resultline, results) {
257 /* Update progress bar periodically */
258 if ((++m_debugCnt && 0x3FF) == 0) {
259 prBar2->setValue(m_debugCnt);
261 fieldlist = resultline.split("\t");
264 /* Iterate through fields in the record */
265 foreach (field, fieldlist) {
266 if (fieldcnt == 0 ) {
267 parseDirectory(field);
268 } else if (fieldcnt == 1) {
270 int pathid = field.toInt(&ok, 10);
272 m_directoryPathIdHash.insert(fieldlist[0], pathid);
279 QMessageBox::warning(this, "Bat",
280 tr("No jobs were selected in the job query !!!.\n"
281 "Press OK to continue"),
284 prBar1->setVisible(false);
285 prBar2->setVisible(false);
286 prLabel1->setVisible(false);
287 prLabel2->setVisible(false);
291 * Function to set m_checkedJobs from the jobs that are checked in the table
294 void restoreTree::setJobsCheckedList()
296 m_JobsCheckedList = "";
298 /* Update the items in the version table */
299 int cnt = jobTable->rowCount();
300 for (int row=0; row<cnt; row++) {
301 QTableWidgetItem* jobItem = jobTable->item(row, 0);
302 if (jobItem->checkState() == Qt::Checked) {
304 m_JobsCheckedList += ",";
305 m_JobsCheckedList += jobItem->text();
307 jobItem->setBackground(Qt::green);
309 if (jobItem->flags())
310 jobItem->setBackground(Qt::gray);
312 jobItem->setBackground(Qt::darkYellow);
315 m_checkedJobs = m_JobsCheckedList;
319 * Function to parse a directory into all possible subdirectories, then add to
322 void restoreTree::parseDirectory(QString &dir_in)
324 /* m_debugTrap is to only print debugs for a few occurennces of calling parseDirectory
325 * instead of printing out what could potentially a whole bunch */
328 /* Truncate everything after the last / */
329 if (dir_in.right(1) != "/") {
330 dir_in.truncate(dir_in.lastIndexOf("/") + 1);
332 if ((mainWin->m_miscDebug) && (m_debugTrap))
333 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
335 /* split and add if not in yet */
336 QString direct, path;
339 QStringList pathAfter, dirAfter;
340 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
341 * if not added into tree, then try /etc/ and somedir/ if not added, then try
342 * / and etc/ . That should succeed, then add the ones that failed in reverse */
343 while (((index = dir_in.lastIndexOf("/", -2)) != -1) && (!done)) {
344 direct = path = dir_in;
345 path.replace(index+1, dir_in.length()-index-1,"");
346 direct.replace(0, index+1, "");
347 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
348 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
349 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
350 Pmsg0(000, msg.toUtf8().data());
352 if (addDirectory(path, direct)) done = true;
354 if ((mainWin->m_miscDebug) && (m_debugTrap))
355 Pmsg0(000, "Saving for later\n");
356 pathAfter.prepend(path);
357 dirAfter.prepend(direct);
362 for (int k=0; k<pathAfter.count(); k++) {
363 if (addDirectory(pathAfter[k], dirAfter[k])) {
364 if ((mainWin->m_miscDebug) && (m_debugTrap))
365 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
367 if ((mainWin->m_miscDebug) && (m_debugTrap))
368 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
375 * Function called from fill directory when a directory is found to see if this
376 * directory exists in the directory pane and then add it to the directory pane
378 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
380 QString newdir = newdirr;
381 QString fullPath = m_cwd + newdirr;
382 bool ok = true, added = false;
384 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
385 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
388 Pmsg0(000, msg.toUtf8().data());
392 /* add unix '/' directory first */
393 if (m_dirPaths.empty() && !isWin32Path(fullPath)) {
395 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
397 item->setText(0, text.toUtf8().data());
398 item->setData(0, Qt::UserRole, QVariant(text));
399 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
400 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
401 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
402 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
404 m_dirPaths.insert(text, item);
406 /* no need to check for windows drive if unix */
407 if (isWin32Path(m_cwd)) {
408 if (!m_dirPaths.contains(m_cwd)) {
409 /* this is a windows drive add the base widget */
410 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
411 item->setText(0, m_cwd);
412 item->setData(0, Qt::UserRole, QVariant(fullPath));
413 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
414 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
415 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
416 Pmsg0(000, "Added Base \"letter\":/\n");
418 m_dirPaths.insert(m_cwd, item);
423 /* is it already existent ?? */
424 if (!m_dirPaths.contains(fullPath)) {
425 QTreeWidgetItem *item = NULL;
426 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
428 /* new directories to add */
429 item = new QTreeWidgetItem(parent);
430 item->setText(0, newdir.toUtf8().data());
431 item->setData(0, Qt::UserRole, QVariant(fullPath));
432 item->setCheckState(0, Qt::Unchecked);
433 /* Store the current state of the check status in column 1, which at
434 * this point has no text*/
435 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
438 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
439 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
442 Pmsg0(000, msg.toUtf8().data());
445 /* insert into hash */
447 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
448 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
450 m_dirPaths.insert(fullPath, item);
458 * Virtual function which is called when this page is visible on the stack
460 void restoreTree::currentStackItem()
469 * Populate the tree when refresh button pushed.
471 void restoreTree::refreshButtonPushed()
473 populateDirectoryTree();
477 * Set the values of non-job combo boxes to the job defaults
479 void restoreTree::jobComboChanged(int)
481 if (jobCombo->currentText() == tr("Any")) {
482 fileSetCombo->setCurrentIndex(fileSetCombo->findText(tr("Any"), Qt::MatchExactly));
485 job_defaults job_defs;
488 job_defs.job_name = jobCombo->currentText();
489 if (m_console->get_job_defaults(job_defs)) {
490 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
491 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
496 * Function to populate the file list table
498 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
504 /* Also clear the version table here */
505 versionTable->clear();
506 versionFileLabel->setText("");
507 versionTable->setRowCount(0);
508 versionTable->setColumnCount(0);
510 QStringList headerlist = (QStringList() << tr("File Name") << tr("Filename Id"));
511 fileTable->setColumnCount(headerlist.size());
512 fileTable->setHorizontalHeaderLabels(headerlist);
513 fileTable->setRowCount(0);
515 m_fileCheckStateList.clear();
516 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
517 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
518 QBrush blackBrush(Qt::black);
519 QString directory = item->data(0, Qt::UserRole).toString();
520 directoryLabel->setText(tr("Present Working Directory: %1").arg(directory));
521 int pathid = m_directoryPathIdHash.value(directory, -1);
524 "SELECT DISTINCT Filename.Name AS FileName, Filename.FilenameId AS FilenameId"
526 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
527 " WHERE File.PathId=" + QString("%1").arg(pathid) +
528 " AND File.Jobid IN (" + m_checkedJobs + ")"
529 " AND Filename.Name!=''"
530 " ORDER BY FileName";
532 if (mainWin->m_sqlDebug) {
533 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
536 if (m_console->sql_cmd(cmd, results)) {
538 QTableWidgetItem* tableItem;
540 QStringList fieldlist;
541 fileTable->setRowCount(results.size());
544 /* Iterate through the record returned from the query */
545 foreach (QString resultline, results) {
546 /* Iterate through fields in the record */
548 fieldlist = resultline.split("\t");
549 foreach (field, fieldlist) {
550 field = field.trimmed(); /* strip leading & trailing spaces */
551 tableItem = new QTableWidgetItem(field, 1);
552 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
553 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
554 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
555 tableItem->setForeground(blackBrush);
556 /* Just in case a column ever gets added */
558 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
559 tableItem->setFlags(flag);
560 tableItem->setData(Qt::UserRole, QVariant(directory));
561 fileTable->setItem(row, column, tableItem);
562 m_fileCheckStateList.append(Qt::Unchecked);
563 tableItem->setCheckState(Qt::Unchecked);
564 } else if (column == 1) {
565 Qt::ItemFlags flag = Qt::ItemIsEnabled;
566 tableItem->setFlags(flag);
568 int filenameid = field.toInt(&ok, 10);
569 if (!ok) filenameid = -1;
570 tableItem->setData(Qt::UserRole, QVariant(filenameid));
571 fileTable->setItem(row, column, tableItem);
577 fileTable->setRowCount(row);
579 fileTable->resizeColumnsToContents();
580 fileTable->resizeRowsToContents();
581 fileTable->verticalHeader()->hide();
582 fileTable->hideColumn(1);
583 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
584 updateFileTableChecks();
585 } else if (mainWin->m_sqlDebug)
586 Pmsg1(000, "did not perform query, pathid=%i not found\n", pathid);
587 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
588 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
592 * Function to populate the version table
594 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *currentFileTableItem, QTableWidgetItem *)
596 if (currentFileTableItem == NULL)
599 int currentRow = fileTable->row(currentFileTableItem);
600 QTableWidgetItem *fileTableItem = fileTable->item(currentRow, 0);
601 QTableWidgetItem *fileNameIdTableItem = fileTable->item(currentRow, 1);
602 int fileNameId = fileNameIdTableItem->data(Qt::UserRole).toInt();
604 m_versionCheckStateList.clear();
605 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
606 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
608 QString file = fileTableItem->text();
609 versionFileLabel->setText(file);
610 QString directory = fileTableItem->data(Qt::UserRole).toString();
612 QBrush blackBrush(Qt::black);
614 QStringList headerlist = (QStringList()
615 << tr("Job Id") << tr("Type") << tr("End Time") << tr("Hash") << tr("FileId"));
616 versionTable->clear();
617 versionTable->setColumnCount(headerlist.size());
618 versionTable->setHorizontalHeaderLabels(headerlist);
619 versionTable->setRowCount(0);
621 int pathid = m_directoryPathIdHash.value(directory, -1);
622 if ((pathid != -1) && (fileNameId != -1)) {
624 "SELECT Job.JobId AS JobId,Job.Level AS Type,Job.EndTime AS EndTime,File.MD5 AS MD5,File.FileId AS FileId"
626 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
627 " INNER JOIN Path ON (Path.PathId=File.PathId)"
628 " INNER JOIN Job ON (File.JobId=Job.JobId)"
629 " WHERE Path.PathId=" + QString("%1").arg(pathid) +
630 //" AND Filename.Name='" + file + "'"
631 " AND Filename.FilenameId=" + QString("%1").arg(fileNameId) +
632 " AND Job.Jobid IN (" + m_checkedJobs + ")"
633 " ORDER BY Job.EndTime DESC";
635 if (mainWin->m_sqlDebug)
636 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
638 if (m_console->sql_cmd(cmd, results)) {
640 QTableWidgetItem* tableItem;
642 QStringList fieldlist;
643 versionTable->setRowCount(results.size());
646 /* Iterate through the record returned from the query */
647 foreach (QString resultline, results) {
648 fieldlist = resultline.split("\t");
650 /* remove directory */
651 if (fieldlist[0].trimmed() != "") {
652 /* Iterate through fields in the record */
653 foreach (field, fieldlist) {
654 field = field.trimmed(); /* strip leading & trailing spaces */
655 tableItem = new QTableWidgetItem(field, 1);
656 tableItem->setFlags(0);
657 tableItem->setForeground(blackBrush);
658 tableItem->setData(Qt::UserRole, QVariant(directory));
659 versionTable->setItem(row, column, tableItem);
662 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
663 tableItem->setFlags(flag);
664 m_versionCheckStateList.append(Qt::Unchecked);
665 tableItem->setCheckState(Qt::Unchecked);
673 versionTable->resizeColumnsToContents();
674 versionTable->resizeRowsToContents();
675 versionTable->verticalHeader()->hide();
676 updateVersionTableChecks();
678 if (mainWin->m_sqlDebug)
679 Pmsg2(000, "not querying : pathid=%i fileNameId=%i\n", pathid, fileNameId);
681 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
682 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
686 * Save user settings associated with this page
688 void restoreTree::writeSettings()
690 QSettings settings(m_console->m_dir->name(), "bat");
691 settings.beginGroup(m_groupText);
692 settings.setValue(m_splitText, m_splitter->saveState());
697 * Read and restore user settings associated with this page
699 void restoreTree::readSettings()
701 m_groupText = tr("RestoreTreePage");
702 m_splitText = "splitterSizes_1";
703 QSettings settings(m_console->m_dir->name(), "bat");
704 settings.beginGroup(m_groupText);
705 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
710 * This is a funcion to accomplish the one thing I struggled to figure out what
711 * was taking so long. It add the icons, but after the tree is made. Seemed to
712 * work fast after changing from png to png file for graphic.
714 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
716 int childCount = item->childCount();
717 for (int i=0; i<childCount; i++) {
718 QTreeWidgetItem *child = item->child(i);
719 if (child->icon(0).isNull())
720 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
725 * Show what jobs meet the criteria and are being used to
726 * populate the directory tree and file and version tables.
728 void restoreTree::populateJobTable()
730 QBrush blackBrush(Qt::black);
732 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
733 QStringList headerlist = (QStringList()
734 << tr("Job Id") << tr("End Time") << tr("Level")
735 << tr("Name") << tr("Purged") << tr("TU") << tr("TD"));
736 m_toggleUpIndex = headerlist.indexOf(tr("TU"));
737 m_toggleDownIndex = headerlist.indexOf(tr("TD"));
738 int purgedIndex = headerlist.indexOf(tr("Purged"));
740 jobTable->setColumnCount(headerlist.size());
741 jobTable->setHorizontalHeaderLabels(headerlist);
743 "SELECT Job.Jobid AS Id,Job.EndTime AS EndTime,Job.Level AS Level,"
744 "Job.Name AS JobName,Job.purgedfiles AS Purged"
746 /* INNER JOIN FileSet eliminates all restore jobs */
747 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
748 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
750 " Client.Name='" + clientCombo->currentText() + "'";
751 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != tr("Any"))) {
752 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
754 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != tr("Any"))) {
755 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
757 /* If Limit check box For limit by days is checked */
758 if (daysCheckBox->checkState() == Qt::Checked) {
759 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
760 QString since = stamp.toString(Qt::ISODate);
761 jobQuery += " AND Job.Starttime>'" + since + "'";
763 //jobQuery += " AND Job.purgedfiles=0";
764 jobQuery += " ORDER BY Job.EndTime DESC";
765 /* If Limit check box for limit records returned is checked */
766 if (limitCheckBox->checkState() == Qt::Checked) {
768 limit.setNum(limitSpinBox->value());
769 jobQuery += " LIMIT " + limit;
771 if (mainWin->m_sqlDebug)
772 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
775 if (m_console->sql_cmd(jobQuery, results)) {
777 QTableWidgetItem* tableItem;
779 QStringList fieldlist;
780 jobTable->setRowCount(results.size());
783 /* Iterate through the record returned from the query */
784 foreach (QString resultline, results) {
785 fieldlist = resultline.split("\t");
787 /* remove directory */
788 if (fieldlist[0].trimmed() != "") {
789 /* Iterate through fields in the record */
790 foreach (field, fieldlist) {
791 field = field.trimmed(); /* strip leading & trailing spaces */
793 tableItem = new QTableWidgetItem(field, 1);
794 tableItem->setFlags(0);
795 tableItem->setForeground(blackBrush);
796 jobTable->setItem(row, column, tableItem);
799 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
800 if (!((ok) && (purged == 1))) {
801 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
802 tableItem->setFlags(flag);
803 tableItem->setCheckState(Qt::Checked);
804 tableItem->setBackground(Qt::green);
806 tableItem->setFlags(0);
807 tableItem->setCheckState(Qt::Unchecked);
813 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
814 tableItem->setFlags(0);
815 tableItem->setForeground(blackBrush);
816 jobTable->setItem(row, column, tableItem);
818 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
819 tableItem->setFlags(0);
820 tableItem->setForeground(blackBrush);
821 jobTable->setItem(row, column, tableItem);
826 jobTable->resizeColumnsToContents();
827 jobTable->resizeRowsToContents();
828 jobTable->verticalHeader()->hide();
829 jobTable->hideColumn(purgedIndex);
832 void restoreTree::jobTableCellClicked(int row, int column)
834 if (column == m_toggleUpIndex){
836 for (cnt=0; cnt<row+1; cnt++) {
837 QTableWidgetItem *item = jobTable->item(cnt, 0);
839 Qt::CheckState state = item->checkState();
840 if (state == Qt::Checked)
841 item->setCheckState(Qt::Unchecked);
842 else if (state == Qt::Unchecked)
843 item->setCheckState(Qt::Checked);
847 if (column == m_toggleDownIndex){
848 int cnt, max = jobTable->rowCount();
849 for (cnt=row; cnt<max; cnt++) {
850 QTableWidgetItem *item = jobTable->item(cnt, 0);
852 Qt::CheckState state = item->checkState();
853 if (state == Qt::Checked)
854 item->setCheckState(Qt::Unchecked);
855 else if (state == Qt::Unchecked)
856 item->setCheckState(Qt::Checked);
863 * When a directory item is "changed" check the state of the checkable item
864 * to see if it is different than what it was which is stored in Qt::UserRole
865 * of the 2nd column, column 1, of the tree widget.
867 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
869 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
870 Qt::CheckState curState = item->checkState(0);
871 QTreeWidgetItem* parent = item->parent();
872 Qt::CheckState parState;
873 if (parent) parState = parent->checkState(0);
874 else parState = (Qt::CheckState)3;
875 if (mainWin->m_rtDirICDebug) {
876 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
877 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
878 Pmsg1(000, "%s", msg.toUtf8().data()); }
879 /* I only care when the check state changes */
880 if (prevState == curState) {
881 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
885 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
886 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
887 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
888 curState = Qt::PartiallyChecked;
890 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
891 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
892 directoryTreeDisconnectedSet(item, Qt::Unchecked);
893 curState = Qt::Unchecked;
895 if (mainWin->m_rtDirICDebug) {
896 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
897 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
898 Pmsg1(000, "%s", msg.toUtf8().data()); }
900 item->setData(1, Qt::UserRole, QVariant(curState));
901 Qt::CheckState childState = curState;
902 if (childState == Qt::Checked)
903 childState = Qt::PartiallyChecked;
904 setCheckofChildren(item, childState);
906 /* Remove items from the exception lists. The multi exception list is my index
907 * of what exceptions can be removed when the directory is known*/
908 QString directory = item->data(0, Qt::UserRole).toString();
909 QStringList fullPathList = m_fileExceptionMulti.values(directory);
910 int fullPathListCount = fullPathList.count();
911 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
912 foreach (QString fullPath, fullPathList) {
913 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
914 * which will match no Qt::xxx values */
915 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
916 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
917 if (hashState == Qt::Unchecked) {
918 fileExceptionRemove(fullPath, directory);
919 m_versionExceptionHash.remove(fullPath);
920 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
922 if (hashState == Qt::Checked) {
923 fileExceptionRemove(fullPath, directory);
924 m_versionExceptionHash.remove(fullPath);
925 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
929 if (item == directoryTree->currentItem()) {
930 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
931 updateFileTableChecks();
932 versionTable->clear();
933 versionTable->setRowCount(0);
934 versionTable->setColumnCount(0);
936 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
940 * When a directory item check state is changed, this function iterates through
941 * all subdirectories and sets all to the passed state, which is either partially
942 * checked or unchecked.
944 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
947 childCount = item->childCount();
948 for (int i=0; i<childCount; i++) {
949 QTreeWidgetItem *child = item->child(i);
950 child->setData(1, Qt::UserRole, QVariant(state));
951 child->setCheckState(0, state);
952 setCheckofChildren(child, state);
957 * When a File Table Item is "changed" check to see if the state of the checkable
958 * item has changed which is stored in m_fileCheckStateList
959 * If changed store in a hash m_fileExceptionHash that whether this file should be
961 * Called as a slot, connected after populated (after directory current changed called)
963 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
965 /* get the previous and current check states */
966 int row = fileTable->row(item);
967 Qt::CheckState prevState;
968 /* prevent a segfault */
969 prevState = m_fileCheckStateList[row];
970 Qt::CheckState curState = item->checkState();
972 /* deterimine the default state from the state of the directory */
973 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
974 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
975 Qt::CheckState defState = Qt::PartiallyChecked;
976 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
978 /* determine if it is already in the m_fileExceptionHash */
979 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
980 QString file = item->text();
981 QString fullPath = directory + file;
982 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
983 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
985 if (mainWin->m_rtFileTabICDebug) {
986 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
987 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
988 Pmsg1(000, "%s", msg.toUtf8().data()); }
990 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
991 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
992 /* it can behave as defaulted so current of unchecked is fine */
993 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
994 fileExceptionRemove(fullPath, directory);
995 m_versionExceptionHash.remove(fullPath);
996 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
997 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
998 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
999 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
1000 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
1001 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
1002 fileExceptionRemove(fullPath, directory);
1003 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
1004 /* Check dir, check version, attempt uncheck in file
1005 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
1006 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
1007 fileExceptionRemove(fullPath, directory);
1008 m_versionExceptionHash.remove(fullPath);
1009 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
1010 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
1011 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
1012 } else if (prevState != curState) {
1013 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
1014 /* A user did not set the check state to Partially checked, ignore if so */
1015 if (curState != Qt::PartiallyChecked) {
1016 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
1017 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
1019 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1020 fileExceptionInsert(fullPath, directory, curState);
1023 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
1024 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
1025 m_versionExceptionHash.remove(fullPath);
1029 updateFileTableChecks();
1030 updateVersionTableChecks();
1034 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
1036 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
1038 m_fileExceptionHash.insert(fullPath, state);
1039 m_fileExceptionMulti.insert(direcotry, fullPath);
1040 directoryIconStateInsert(fullPath, state);
1044 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
1046 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
1048 m_fileExceptionHash.remove(fullPath);
1049 /* pull the list of values in the multi */
1050 QStringList fullPathList = m_fileExceptionMulti.values(directory);
1051 /* get the index of the fullpath to remove */
1052 int index = fullPathList.indexOf(fullPath);
1054 /* remove the desired item in the list */
1055 fullPathList.removeAt(index);
1056 /* remove the entire list from the multi */
1057 m_fileExceptionMulti.remove(directory);
1058 /* readd the remaining */
1059 foreach (QString fp, fullPathList) {
1060 m_fileExceptionMulti.insert(directory, fp);
1063 directoryIconStateRemove();
1067 * Overloaded function to be called from the slot and from other places to set the state
1068 * of the check marks in the version table
1070 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
1072 /* get the previous and current check states */
1073 int row = versionTable->row(item);
1074 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
1075 Qt::CheckState prevState = m_versionCheckStateList[row];
1076 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
1077 m_versionCheckStateList[row] = curState;
1079 /* deterimine the default state from the state of the file */
1080 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1081 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1083 /* determine the default state */
1084 Qt::CheckState defState;
1086 defState = Qt::PartiallyChecked;
1087 if (fileState == Qt::Unchecked)
1088 defState = Qt::Unchecked;
1091 defState = Qt::Unchecked;
1093 /* determine if it is already in the versionExceptionHash */
1094 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1095 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1096 QString file = fileTableItem->text();
1097 QString fullPath = directory + file;
1098 int thisJobNum = colZeroItem->text().toInt();
1099 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1101 if (mainWin->m_rtVerTabICDebug) {
1102 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1103 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1104 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1105 Pmsg1(000, "%s", msg.toUtf8().data()); }
1106 /* if changed from partially checked to checked, make it unchecked */
1107 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1108 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1109 fileTableItem->setCheckState(Qt::Checked);
1110 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1111 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1112 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1113 fileExceptionRemove(fullPath, directory);
1114 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1115 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1116 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1117 m_versionExceptionHash.remove(fullPath);
1118 fileExceptionRemove(fullPath, directory);
1119 } else if ((curState == Qt::Checked) && (row == 0)) {
1120 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1121 m_versionExceptionHash.remove(fullPath);
1122 } else if (prevState != curState) {
1123 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1124 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked && row != 0)) {
1125 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1126 m_versionExceptionHash.insert(fullPath, thisJobNum);
1127 if (fileState != Qt::Checked) {
1128 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1129 fileExceptionInsert(fullPath, directory, curState);
1132 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1135 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1138 updateFileTableChecks();
1139 updateVersionTableChecks();
1143 * Simple function to set the check state in the file table by disconnecting the
1144 * signal/slot the setting then reconnecting the signal/slot
1146 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1148 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1149 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1150 item->setCheckState(state);
1151 if (color) item->setBackground(Qt::yellow);
1152 else item->setBackground(Qt::white);
1153 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1154 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1158 * Simple function to set the check state in the version table by disconnecting the
1159 * signal/slot the setting then reconnecting the signal/slot
1161 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1163 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1164 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1165 item->setCheckState(state);
1166 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1167 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1171 * Simple function to set the check state in the directory tree by disconnecting the
1172 * signal/slot the setting then reconnecting the signal/slot
1174 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1176 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1177 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1178 item->setCheckState(0, state);
1179 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1180 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1184 * Simplify the updating of the check state in the File table by iterating through
1185 * each item in the file table to determine it's appropriate state.
1186 * !! Will probably want to concoct a way to do this without iterating for the possibility
1187 * of the very large directories.
1189 void restoreTree::updateFileTableChecks()
1191 /* deterimine the default state from the state of the directory */
1192 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1193 Qt::CheckState dirState = dirTreeItem->checkState(0);
1195 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1197 /* Update the items in the version table */
1198 int rcnt = fileTable->rowCount();
1199 for (int row=0; row<rcnt; row++) {
1200 QTableWidgetItem* item = fileTable->item(row, 0);
1202 Qt::CheckState curState = item->checkState();
1203 Qt::CheckState newState = Qt::PartiallyChecked;
1204 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1206 /* determine if it is already in the m_fileExceptionHash */
1207 QString file = item->text();
1208 QString fullPath = dirName + file;
1209 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1210 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1212 if (hashState != 3) newState = hashState;
1214 if (mainWin->m_rtUpdateFTDebug) {
1215 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1216 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1217 Pmsg1(000, "%s", msg.toUtf8().data());
1220 bool docolor = false;
1221 if (hashJobNum != 0) docolor = true;
1222 bool isyellow = item->background().color() == QColor(Qt::yellow);
1223 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1224 fileTableDisconnectedSet(item, newState, docolor);
1225 m_fileCheckStateList[row] = newState;
1230 * Simplify the updating of the check state in the Version table by iterating through
1231 * each item in the file table to determine it's appropriate state.
1233 void restoreTree::updateVersionTableChecks()
1235 /* deterimine the default state from the state of the directory */
1236 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1237 Qt::CheckState dirState = dirTreeItem->checkState(0);
1238 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1240 /* deterimine the default state from the state of the file */
1241 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1242 Qt::CheckState fileState = fileTableItem->checkState();
1243 QString file = fileTableItem->text();
1244 QString fullPath = dirName + file;
1245 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1247 /* Update the items in the version table */
1248 int cnt = versionTable->rowCount();
1249 for (int row=0; row<cnt; row++) {
1250 QTableWidgetItem* item = versionTable->item(row, 0);
1252 Qt::CheckState curState = item->checkState();
1253 Qt::CheckState newState = Qt::Unchecked;
1255 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1256 newState = Qt::PartiallyChecked;
1257 /* determine if it is already in the versionExceptionHash */
1259 int thisJobNum = item->text().toInt();
1260 if (thisJobNum == hashJobNum)
1261 newState = Qt::Checked;
1263 if (mainWin->m_rtChecksDebug) {
1264 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1265 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1266 Pmsg1(000, "%s", msg.toUtf8().data());
1268 if (newState != curState)
1269 versionTableDisconnectedSet(item, newState);
1270 m_versionCheckStateList[row] = newState;
1275 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1277 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1281 QString fullPath = fullPath_in;
1282 QString direct, path;
1283 while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
1284 direct = path = fullPath;
1285 path.replace(index+1, fullPath.length()-index-1, "");
1286 direct.replace(0, index+1, "");
1288 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1289 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1290 Pmsg0(000, msg.toUtf8().data());
1293 subPaths.append(fullPath);
1298 * A Function to set the icon state and insert a record into
1299 * m_directoryIconStateHash when an exception is added by the user
1301 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1304 fullPathtoSubPaths(paths, fullPath);
1305 /* an exception that causes the item in the file table to be "Checked" has occured */
1306 if (excpState == Qt::Checked) {
1307 bool foundAsUnChecked = false;
1308 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1310 if (firstItem->checkState(0) == Qt::Unchecked)
1311 foundAsUnChecked = true;
1313 if (foundAsUnChecked) {
1314 /* as long as directory item is Unchecked, set icon state to "green check" */
1316 QListIterator<QString> siter(paths);
1317 while (siter.hasNext() && !done) {
1318 QString path = siter.next();
1319 QTreeWidgetItem *item = m_dirPaths.value(path);
1321 if (item->checkState(0) != Qt::Unchecked)
1324 directorySetIcon(1, FolderGreenChecked, path, item);
1325 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1330 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1331 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1333 QListIterator<QString> siter(paths);
1334 while (siter.hasNext() && !done) {
1335 QString path = siter.next();
1336 QTreeWidgetItem *item = m_dirPaths.value(path);
1337 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1338 if (item->checkState(0) == Qt::Checked)
1340 directorySetIcon(1, FolderGreenChecked, path, item);
1341 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1346 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1347 if (excpState == Qt::Unchecked) {
1349 QListIterator<QString> siter(paths);
1350 while (siter.hasNext() && !done) {
1351 QString path = siter.next();
1352 QTreeWidgetItem *item = m_dirPaths.value(path);
1353 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1354 if (item->checkState(0) == Qt::Checked)
1356 directorySetIcon(1, FolderWhiteChecked, path, item);
1357 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1364 * A function to set the icon state back to "folder" and to remove a record from
1365 * m_directoryIconStateHash when an exception is removed by a user.
1367 void restoreTree::directoryIconStateRemove()
1369 QHash<QString, int> shouldBeIconStateHash;
1370 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1371 /* Use iterator tera to iterate through m_fileExceptionHash */
1372 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1373 while (tera.hasNext()) {
1375 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1377 QString keyPath = tera.key();
1378 Qt::CheckState state = tera.value();
1381 fullPathtoSubPaths(paths, keyPath);
1382 /* if the state of the item in m_fileExceptionHash is checked
1383 * each of the subpaths should be "Checked Green" */
1384 if (state == Qt::Checked) {
1386 bool foundAsUnChecked = false;
1387 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1389 if (firstItem->checkState(0) == Qt::Unchecked)
1390 foundAsUnChecked = true;
1392 if (foundAsUnChecked) {
1393 /* The right most directory is Unchecked, iterate leftwards
1394 * as long as directory item is Unchecked, set icon state to "green check" */
1396 QListIterator<QString> siter(paths);
1397 while (siter.hasNext() && !done) {
1398 QString path = siter.next();
1399 QTreeWidgetItem *item = m_dirPaths.value(path);
1401 if (item->checkState(0) != Qt::Unchecked)
1404 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1405 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1411 /* The right most directory is Unchecked, iterate leftwards
1412 * until directory item is Checked, set icon state to "green check" */
1414 QListIterator<QString> siter(paths);
1415 while (siter.hasNext() && !done) {
1416 QString path = siter.next();
1417 QTreeWidgetItem *item = m_dirPaths.value(path);
1419 if (item->checkState(0) == Qt::Checked)
1421 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1426 /* if the state of the item in m_fileExceptionHash is UNChecked
1427 * each of the subpaths should be "Checked white" until the tree item
1428 * which represents that path is Qt::Checked */
1429 if (state == Qt::Unchecked) {
1431 QListIterator<QString> siter(paths);
1432 while (siter.hasNext() && !done) {
1433 QString path = siter.next();
1434 QTreeWidgetItem *item = m_dirPaths.value(path);
1436 if (item->checkState(0) == Qt::Checked)
1438 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1443 /* now iterate through m_directoryIconStateHash which are the items that are checked
1444 * and remove all of those that are not in shouldBeIconStateHash */
1445 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1446 while (iter.hasNext()) {
1448 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1450 QString keyPath = iter.key();
1451 if (shouldBeIconStateHash.value(keyPath)) {
1452 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1453 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1454 int newval = shouldBeIconStateHash.value(keyPath);
1456 newval = newval & FolderBothChecked;
1457 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1459 directorySetIcon(0, newval, keyPath, item);
1461 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1462 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1464 directorySetIcon(0, FolderBothChecked, keyPath, item);
1465 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1466 //m_directoryIconStateHash.remove(keyPath);
1471 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1473 /* we are adding a check type white or green */
1474 if (operation > 0) {
1475 /* get the old val and "bitwise OR" with the change */
1476 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1477 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1478 m_directoryIconStateHash.insert(path, newval);
1480 /* we are removing a check type white or green */
1481 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1483 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1484 m_directoryIconStateHash.remove(path);
1487 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1488 m_directoryIconStateHash.insert(path, newval);
1491 if (newval == FolderUnchecked)
1492 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1493 else if (newval == FolderGreenChecked)
1494 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1495 else if (newval == FolderWhiteChecked)
1496 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1497 else if (newval == FolderBothChecked)
1498 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1504 void restoreTree::restoreButtonPushed()
1506 /* Set progress bars and repaint */
1507 prLabel1->setVisible(true);
1508 prLabel1->setText(tr("Task 1 of 3"));
1509 prLabel2->setVisible(true);
1510 prLabel2->setText(tr("Processing Checked directories"));
1511 prBar1->setVisible(true);
1512 prBar1->setRange(0, 3);
1513 prBar1->setValue(0);
1514 prBar2->setVisible(true);
1515 prBar2->setRange(0, 0);
1517 QMultiHash<int, QString> versionFilesMulti;
1519 QHash <QString, bool> fullPathDone;
1520 QHash <QString, int> fileIndexHash;
1521 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1522 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1523 /* Use a tree widget item iterator to count directories for the progress bar */
1524 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1529 } /* while (*diterc) */
1530 prBar2->setRange(0, ditcount);
1531 prBar2->setValue(0);
1533 /* Use a tree widget item iterator filtering for Checked Items */
1534 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1536 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1537 int pathid = m_directoryPathIdHash.value(directory, -1);
1539 if (mainWin->m_rtRestore1Debug)
1540 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1541 /* With a checked directory, query for the files in the directory */
1544 "SELECT Filename.Name AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1546 " ( SELECT File.FilenameId AS FilenameId, MAX(Job.JobId) AS JobId"
1548 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1549 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1550 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1551 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1552 " GROUP BY File.FilenameId"
1554 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1555 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1556 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1557 " AND File.FilenameId=t1.FilenameId"
1558 " AND Job.Jobid=t1.JobId"
1559 " ORDER BY Filename";
1561 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1562 QStringList results;
1563 if (m_console->sql_cmd(cmd, results)) {
1564 QStringList fieldlist;
1567 /* Iterate through the record returned from the query */
1568 foreach (QString resultline, results) {
1569 /* Iterate through fields in the record */
1571 QString fullPath = "";
1572 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1573 fieldlist = resultline.split("\t");
1576 foreach (QString field, fieldlist) {
1578 fullPath = directory + field;
1581 version = field.toInt();
1584 fileIndex = field.toInt();
1588 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1590 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1591 if (fileExcpState != Qt::Unchecked) {
1593 if (excpVersion != 0) {
1594 debugtext = QString("*E* version=%1").arg(excpVersion);
1595 version = excpVersion;
1596 fileIndex = queryFileIndex(fullPath, excpVersion);
1598 debugtext = QString("___ version=%1").arg(version);
1599 if (mainWin->m_rtRestore1Debug)
1600 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1601 fullPathDone.insert(fullPath, 1);
1602 fileIndexHash.insert(fullPath, fileIndex);
1603 versionFilesMulti.insert(version, fullPath);
1611 prBar2->setValue(ditcount);
1613 } /* while (*diter) */
1614 prBar1->setValue(1);
1615 prLabel1->setText( tr("Task 2 of 3"));
1616 prLabel2->setText(tr("Processing Exceptions"));
1617 prBar2->setRange(0, 0);
1620 /* There may be some exceptions not accounted for yet with fullPathDone */
1621 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1622 while (ftera.hasNext()) {
1624 QString fullPath = ftera.key();
1625 Qt::CheckState state = ftera.value();
1627 /* now we don't want the ones already done */
1628 if (fullPathDone.value(fullPath, 0) == 0) {
1629 int version = m_versionExceptionHash.value(fullPath, 0);
1631 QString debugtext = "";
1633 fileIndex = queryFileIndex(fullPath, version);
1634 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1636 version = mostRecentVersionfromFullPath(fullPath);
1638 fileIndex = queryFileIndex(fullPath, version);
1639 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1641 debugtext = QString("Error det vers").arg(version);
1643 if (mainWin->m_rtRestore1Debug)
1644 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1645 versionFilesMulti.insert(version, fullPath);
1647 fileIndexHash.insert(fullPath, fileIndex);
1648 } /* if fullPathDone.value(fullPath, 0) == 0 */
1649 } /* if state != 0 */
1650 } /* while ftera.hasNext */
1651 /* The progress bars for the next step */
1652 prBar1->setValue(2);
1653 prLabel1->setText(tr("Task 3 of 3"));
1654 prLabel2->setText(tr("Filling Database Table"));
1655 prBar2->setRange(0, vFMCounter);
1657 prBar2->setValue(vFMCounter);
1660 /* now for the final spit out of the versions and lists of files for each version */
1661 QHash<int, int> doneKeys;
1662 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1663 QString tempTable = "";
1665 while (vFMiter.hasNext()) {
1667 int fversion = vFMiter.key();
1668 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1669 if (doneKeys.value(fversion, 0) == 0) {
1670 if (tempTable == "") {
1671 QSettings settings("www.bacula.org", "bat");
1672 settings.beginGroup("Restore");
1673 int counter = settings.value("Counter", 1).toInt();
1674 settings.setValue("Counter", counter+1);
1675 settings.endGroup();
1676 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1677 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1678 if (mainWin->m_sqlDebug)
1679 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1680 QStringList results;
1681 if (!m_console->sql_cmd(sqlcmd, results))
1682 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1685 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1686 QStringList fullPathList = versionFilesMulti.values(fversion);
1687 /* create the command to perform the restore */
1688 foreach(QString ffullPath, fullPathList) {
1689 int fileIndex = fileIndexHash.value(ffullPath);
1690 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1691 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1692 if (mainWin->m_rtRestore3Debug)
1693 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1694 QStringList results;
1695 if (!m_console->sql_cmd(sqlcmd, results))
1696 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1697 prBar2->setValue(++vFMCounter);
1698 } /* foreach fullPathList */
1699 doneKeys.insert(fversion,1);
1700 jobList.append(fversion);
1701 } /* if (doneKeys.value(fversion, 0) == 0) */
1702 } /* while (vFMiter.hasNext()) */
1703 if (tempTable != "") {
1704 /* a table was made, lets run the job */
1705 QString jobOption = " jobid=\"";
1707 /* create a list of jobs comma separated */
1708 foreach (int job, jobList) {
1709 if (first) first = false;
1710 else jobOption += ",";
1711 jobOption += QString("%1").arg(job);
1714 QString cmd = QString("restore");
1716 " client=\"" + m_prevClientCombo + "\"" +
1717 " file=\"?" + tempTable + "\" done";
1718 if (mainWin->m_commandDebug)
1719 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1720 consoleCommand(cmd);
1722 /* turn off the progress widgets */
1723 prBar1->setVisible(false);
1724 prBar2->setVisible(false);
1725 prLabel1->setVisible(false);
1726 prLabel2->setVisible(false);
1729 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1732 QString directory, fileName;
1733 int index = fullPath.lastIndexOf("/", -2);
1735 directory = fileName = fullPath;
1736 directory.replace(index+1, fullPath.length()-index-1, "");
1737 fileName.replace(0, index+1, "");
1739 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1740 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1741 Pmsg0(000, msg.toUtf8().data());
1743 int pathid = m_directoryPathIdHash.value(directory, -1);
1745 /* so now we need the latest version from the database */
1747 "SELECT MAX(Job.JobId)"
1749 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1750 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1751 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1752 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1753 " AND Filename.Name='" + fileName + "'"
1754 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1755 " GROUP BY Filename.Name";
1757 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1758 QStringList results;
1759 if (m_console->sql_cmd(cmd, results)) {
1760 QStringList fieldlist;
1762 /* Iterate through the record returned from the query */
1763 foreach (QString resultline, results) {
1764 /* Iterate through fields in the record */
1766 fieldlist = resultline.split("\t");
1767 foreach (QString field, fieldlist) {
1769 qversion = field.toInt();
1777 } /* if (index != -1) */
1782 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1785 QString directory, fileName;
1786 int index = fullPath.lastIndexOf("/", -2);
1788 directory = fileName = fullPath;
1789 directory.replace(index+1, fullPath.length()-index-1, "");
1790 fileName.replace(0, index+1, "");
1792 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1793 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1794 Pmsg0(000, msg.toUtf8().data());
1796 int pathid = m_directoryPathIdHash.value(directory, -1);
1798 /* so now we need the latest version from the database */
1803 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1804 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1805 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1806 " AND Filename.Name='" + fileName + "'"
1807 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1808 " GROUP BY File.FileIndex";
1810 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1811 QStringList results;
1812 if (m_console->sql_cmd(cmd, results)) {
1813 QStringList fieldlist;
1815 /* Iterate through the record returned from the query */
1816 foreach (QString resultline, results) {
1817 /* Iterate through fields in the record */
1819 fieldlist = resultline.split("\t");
1820 foreach (QString field, fieldlist) {
1822 qfileIndex = field.toInt();
1830 } /* if (index != -1) */