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 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.
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()
463 if (!m_console->preventInUseConnect())
471 * Populate the tree when refresh button pushed.
473 void restoreTree::refreshButtonPushed()
475 populateDirectoryTree();
479 * Set the values of non-job combo boxes to the job defaults
481 void restoreTree::jobComboChanged(int)
483 if (jobCombo->currentText() == tr("Any")) {
484 fileSetCombo->setCurrentIndex(fileSetCombo->findText(tr("Any"), Qt::MatchExactly));
487 job_defaults job_defs;
490 job_defs.job_name = jobCombo->currentText();
491 if (m_console->get_job_defaults(job_defs)) {
492 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
493 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
498 * Function to populate the file list table
500 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
506 /* Also clear the version table here */
507 versionTable->clear();
508 versionFileLabel->setText("");
509 versionTable->setRowCount(0);
510 versionTable->setColumnCount(0);
512 QStringList headerlist = (QStringList() << tr("File Name") << tr("Filename Id"));
513 fileTable->setColumnCount(headerlist.size());
514 fileTable->setHorizontalHeaderLabels(headerlist);
515 fileTable->setRowCount(0);
517 m_fileCheckStateList.clear();
518 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
519 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
520 QBrush blackBrush(Qt::black);
521 QString directory = item->data(0, Qt::UserRole).toString();
522 directoryLabel->setText(tr("Present Working Directory: %1").arg(directory));
523 int pathid = m_directoryPathIdHash.value(directory, -1);
526 "SELECT DISTINCT Filename.Name AS FileName, Filename.FilenameId AS FilenameId"
528 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
529 " WHERE File.PathId=" + QString("%1").arg(pathid) +
530 " AND File.Jobid IN (" + m_checkedJobs + ")"
531 " AND Filename.Name!=''"
532 " ORDER BY FileName";
534 if (mainWin->m_sqlDebug) {
535 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
538 if (m_console->sql_cmd(cmd, results)) {
540 QTableWidgetItem* tableItem;
542 QStringList fieldlist;
543 fileTable->setRowCount(results.size());
546 /* Iterate through the record returned from the query */
547 foreach (QString resultline, results) {
548 /* Iterate through fields in the record */
550 fieldlist = resultline.split("\t");
551 foreach (field, fieldlist) {
552 field = field.trimmed(); /* strip leading & trailing spaces */
553 tableItem = new QTableWidgetItem(field, 1);
554 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
555 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
556 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
557 tableItem->setForeground(blackBrush);
558 /* Just in case a column ever gets added */
560 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
561 tableItem->setFlags(flag);
562 tableItem->setData(Qt::UserRole, QVariant(directory));
563 fileTable->setItem(row, column, tableItem);
564 m_fileCheckStateList.append(Qt::Unchecked);
565 tableItem->setCheckState(Qt::Unchecked);
566 } else if (column == 1) {
567 Qt::ItemFlags flag = Qt::ItemIsEnabled;
568 tableItem->setFlags(flag);
570 int filenameid = field.toInt(&ok, 10);
571 if (!ok) filenameid = -1;
572 tableItem->setData(Qt::UserRole, QVariant(filenameid));
573 fileTable->setItem(row, column, tableItem);
579 fileTable->setRowCount(row);
581 fileTable->resizeColumnsToContents();
582 fileTable->resizeRowsToContents();
583 fileTable->verticalHeader()->hide();
584 fileTable->hideColumn(1);
585 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
586 updateFileTableChecks();
587 } else if (mainWin->m_sqlDebug)
588 Pmsg1(000, "did not perform query, pathid=%i not found\n", pathid);
589 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
590 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
594 * Function to populate the version table
596 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *currentFileTableItem, QTableWidgetItem *)
598 if (currentFileTableItem == NULL)
601 int currentRow = fileTable->row(currentFileTableItem);
602 QTableWidgetItem *fileTableItem = fileTable->item(currentRow, 0);
603 QTableWidgetItem *fileNameIdTableItem = fileTable->item(currentRow, 1);
604 int fileNameId = fileNameIdTableItem->data(Qt::UserRole).toInt();
606 m_versionCheckStateList.clear();
607 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
608 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
610 QString file = fileTableItem->text();
611 versionFileLabel->setText(file);
612 QString directory = fileTableItem->data(Qt::UserRole).toString();
614 QBrush blackBrush(Qt::black);
616 QStringList headerlist = (QStringList()
617 << tr("Job Id") << tr("Type") << tr("End Time") << tr("Hash") << tr("FileId"));
618 versionTable->clear();
619 versionTable->setColumnCount(headerlist.size());
620 versionTable->setHorizontalHeaderLabels(headerlist);
621 versionTable->setRowCount(0);
623 int pathid = m_directoryPathIdHash.value(directory, -1);
624 if ((pathid != -1) && (fileNameId != -1)) {
626 "SELECT Job.JobId AS JobId,Job.Level AS Type,Job.EndTime AS EndTime,File.MD5 AS MD5,File.FileId AS FileId"
628 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
629 " INNER JOIN Path ON (Path.PathId=File.PathId)"
630 " INNER JOIN Job ON (File.JobId=Job.JobId)"
631 " WHERE Path.PathId=" + QString("%1").arg(pathid) +
632 //" AND Filename.Name='" + file + "'"
633 " AND Filename.FilenameId=" + QString("%1").arg(fileNameId) +
634 " AND Job.Jobid IN (" + m_checkedJobs + ")"
635 " ORDER BY Job.EndTime DESC";
637 if (mainWin->m_sqlDebug)
638 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
640 if (m_console->sql_cmd(cmd, results)) {
642 QTableWidgetItem* tableItem;
644 QStringList fieldlist;
645 versionTable->setRowCount(results.size());
648 /* Iterate through the record returned from the query */
649 foreach (QString resultline, results) {
650 fieldlist = resultline.split("\t");
652 /* remove directory */
653 if (fieldlist[0].trimmed() != "") {
654 /* Iterate through fields in the record */
655 foreach (field, fieldlist) {
656 field = field.trimmed(); /* strip leading & trailing spaces */
657 tableItem = new QTableWidgetItem(field, 1);
658 tableItem->setFlags(0);
659 tableItem->setForeground(blackBrush);
660 tableItem->setData(Qt::UserRole, QVariant(directory));
661 versionTable->setItem(row, column, tableItem);
664 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
665 tableItem->setFlags(flag);
666 m_versionCheckStateList.append(Qt::Unchecked);
667 tableItem->setCheckState(Qt::Unchecked);
675 versionTable->resizeColumnsToContents();
676 versionTable->resizeRowsToContents();
677 versionTable->verticalHeader()->hide();
678 updateVersionTableChecks();
680 if (mainWin->m_sqlDebug)
681 Pmsg2(000, "not querying : pathid=%i fileNameId=%i\n", pathid, fileNameId);
683 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
684 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
688 * Save user settings associated with this page
690 void restoreTree::writeSettings()
692 QSettings settings(m_console->m_dir->name(), "bat");
693 settings.beginGroup(m_groupText);
694 settings.setValue(m_splitText, m_splitter->saveState());
699 * Read and restore user settings associated with this page
701 void restoreTree::readSettings()
703 m_groupText = tr("RestoreTreePage");
704 m_splitText = "splitterSizes_1";
705 QSettings settings(m_console->m_dir->name(), "bat");
706 settings.beginGroup(m_groupText);
707 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
712 * This is a funcion to accomplish the one thing I struggled to figure out what
713 * was taking so long. It add the icons, but after the tree is made. Seemed to
714 * work fast after changing from png to png file for graphic.
716 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
718 int childCount = item->childCount();
719 for (int i=0; i<childCount; i++) {
720 QTreeWidgetItem *child = item->child(i);
721 if (child->icon(0).isNull())
722 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
727 * Show what jobs meet the criteria and are being used to
728 * populate the directory tree and file and version tables.
730 void restoreTree::populateJobTable()
732 QBrush blackBrush(Qt::black);
734 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
735 QStringList headerlist = (QStringList()
736 << tr("Job Id") << tr("End Time") << tr("Level")
737 << tr("Name") << tr("Purged") << tr("TU") << tr("TD"));
738 m_toggleUpIndex = headerlist.indexOf(tr("TU"));
739 m_toggleDownIndex = headerlist.indexOf(tr("TD"));
740 int purgedIndex = headerlist.indexOf(tr("Purged"));
742 jobTable->setColumnCount(headerlist.size());
743 jobTable->setHorizontalHeaderLabels(headerlist);
745 "SELECT Job.Jobid AS Id,Job.EndTime AS EndTime,Job.Level AS Level,"
746 "Job.Name AS JobName,Job.purgedfiles AS Purged"
748 /* INNER JOIN FileSet eliminates all restore jobs */
749 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
750 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
752 " Client.Name='" + clientCombo->currentText() + "'";
753 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != tr("Any"))) {
754 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
756 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != tr("Any"))) {
757 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
759 /* If Limit check box For limit by days is checked */
760 if (daysCheckBox->checkState() == Qt::Checked) {
761 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
762 QString since = stamp.toString(Qt::ISODate);
763 jobQuery += " AND Job.Starttime>'" + since + "'";
765 //jobQuery += " AND Job.purgedfiles=0";
766 jobQuery += " ORDER BY Job.EndTime DESC";
767 /* If Limit check box for limit records returned is checked */
768 if (limitCheckBox->checkState() == Qt::Checked) {
770 limit.setNum(limitSpinBox->value());
771 jobQuery += " LIMIT " + limit;
773 if (mainWin->m_sqlDebug)
774 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
777 if (m_console->sql_cmd(jobQuery, results)) {
779 QTableWidgetItem* tableItem;
781 QStringList fieldlist;
782 jobTable->setRowCount(results.size());
785 /* Iterate through the record returned from the query */
786 foreach (QString resultline, results) {
787 fieldlist = resultline.split("\t");
789 /* remove directory */
790 if (fieldlist[0].trimmed() != "") {
791 /* Iterate through fields in the record */
792 foreach (field, fieldlist) {
793 field = field.trimmed(); /* strip leading & trailing spaces */
795 tableItem = new QTableWidgetItem(field, 1);
796 tableItem->setFlags(0);
797 tableItem->setForeground(blackBrush);
798 jobTable->setItem(row, column, tableItem);
801 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
802 if (!((ok) && (purged == 1))) {
803 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
804 tableItem->setFlags(flag);
805 tableItem->setCheckState(Qt::Checked);
806 tableItem->setBackground(Qt::green);
808 tableItem->setFlags(0);
809 tableItem->setCheckState(Qt::Unchecked);
815 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
816 tableItem->setFlags(0);
817 tableItem->setForeground(blackBrush);
818 jobTable->setItem(row, column, tableItem);
820 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
821 tableItem->setFlags(0);
822 tableItem->setForeground(blackBrush);
823 jobTable->setItem(row, column, tableItem);
828 jobTable->resizeColumnsToContents();
829 jobTable->resizeRowsToContents();
830 jobTable->verticalHeader()->hide();
831 jobTable->hideColumn(purgedIndex);
834 void restoreTree::jobTableCellClicked(int row, int column)
836 if (column == m_toggleUpIndex){
838 for (cnt=0; cnt<row+1; cnt++) {
839 QTableWidgetItem *item = jobTable->item(cnt, 0);
841 Qt::CheckState state = item->checkState();
842 if (state == Qt::Checked)
843 item->setCheckState(Qt::Unchecked);
844 else if (state == Qt::Unchecked)
845 item->setCheckState(Qt::Checked);
849 if (column == m_toggleDownIndex){
850 int cnt, max = jobTable->rowCount();
851 for (cnt=row; cnt<max; cnt++) {
852 QTableWidgetItem *item = jobTable->item(cnt, 0);
854 Qt::CheckState state = item->checkState();
855 if (state == Qt::Checked)
856 item->setCheckState(Qt::Unchecked);
857 else if (state == Qt::Unchecked)
858 item->setCheckState(Qt::Checked);
865 * When a directory item is "changed" check the state of the checkable item
866 * to see if it is different than what it was which is stored in Qt::UserRole
867 * of the 2nd column, column 1, of the tree widget.
869 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
871 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
872 Qt::CheckState curState = item->checkState(0);
873 QTreeWidgetItem* parent = item->parent();
874 Qt::CheckState parState;
875 if (parent) parState = parent->checkState(0);
876 else parState = (Qt::CheckState)3;
877 if (mainWin->m_rtDirICDebug) {
878 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
879 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
880 Pmsg1(000, "%s", msg.toUtf8().data()); }
881 /* I only care when the check state changes */
882 if (prevState == curState) {
883 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
887 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
888 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
889 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
890 curState = Qt::PartiallyChecked;
892 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
893 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
894 directoryTreeDisconnectedSet(item, Qt::Unchecked);
895 curState = Qt::Unchecked;
897 if (mainWin->m_rtDirICDebug) {
898 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
899 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
900 Pmsg1(000, "%s", msg.toUtf8().data()); }
902 item->setData(1, Qt::UserRole, QVariant(curState));
903 Qt::CheckState childState = curState;
904 if (childState == Qt::Checked)
905 childState = Qt::PartiallyChecked;
906 setCheckofChildren(item, childState);
908 /* Remove items from the exception lists. The multi exception list is my index
909 * of what exceptions can be removed when the directory is known*/
910 QString directory = item->data(0, Qt::UserRole).toString();
911 QStringList fullPathList = m_fileExceptionMulti.values(directory);
912 int fullPathListCount = fullPathList.count();
913 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
914 foreach (QString fullPath, fullPathList) {
915 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
916 * which will match no Qt::xxx values */
917 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
918 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
919 if (hashState == Qt::Unchecked) {
920 fileExceptionRemove(fullPath, directory);
921 m_versionExceptionHash.remove(fullPath);
922 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
924 if (hashState == Qt::Checked) {
925 fileExceptionRemove(fullPath, directory);
926 m_versionExceptionHash.remove(fullPath);
927 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
931 if (item == directoryTree->currentItem()) {
932 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
933 updateFileTableChecks();
934 versionTable->clear();
935 versionTable->setRowCount(0);
936 versionTable->setColumnCount(0);
938 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
942 * When a directory item check state is changed, this function iterates through
943 * all subdirectories and sets all to the passed state, which is either partially
944 * checked or unchecked.
946 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
949 childCount = item->childCount();
950 for (int i=0; i<childCount; i++) {
951 QTreeWidgetItem *child = item->child(i);
952 child->setData(1, Qt::UserRole, QVariant(state));
953 child->setCheckState(0, state);
954 setCheckofChildren(child, state);
959 * When a File Table Item is "changed" check to see if the state of the checkable
960 * item has changed which is stored in m_fileCheckStateList
961 * If changed store in a hash m_fileExceptionHash that whether this file should be
963 * Called as a slot, connected after populated (after directory current changed called)
965 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
967 /* get the previous and current check states */
968 int row = fileTable->row(item);
969 Qt::CheckState prevState;
970 /* prevent a segfault */
971 prevState = m_fileCheckStateList[row];
972 Qt::CheckState curState = item->checkState();
974 /* deterimine the default state from the state of the directory */
975 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
976 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
977 Qt::CheckState defState = Qt::PartiallyChecked;
978 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
980 /* determine if it is already in the m_fileExceptionHash */
981 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
982 QString file = item->text();
983 QString fullPath = directory + file;
984 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
985 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
987 if (mainWin->m_rtFileTabICDebug) {
988 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
989 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
990 Pmsg1(000, "%s", msg.toUtf8().data()); }
992 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
993 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
994 /* it can behave as defaulted so current of unchecked is fine */
995 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
996 fileExceptionRemove(fullPath, directory);
997 m_versionExceptionHash.remove(fullPath);
998 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
999 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
1000 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
1001 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
1002 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
1003 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
1004 fileExceptionRemove(fullPath, directory);
1005 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
1006 /* Check dir, check version, attempt uncheck in file
1007 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
1008 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
1009 fileExceptionRemove(fullPath, directory);
1010 m_versionExceptionHash.remove(fullPath);
1011 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
1012 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
1013 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
1014 } else if (prevState != curState) {
1015 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
1016 /* A user did not set the check state to Partially checked, ignore if so */
1017 if (curState != Qt::PartiallyChecked) {
1018 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
1019 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
1021 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1022 fileExceptionInsert(fullPath, directory, curState);
1025 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
1026 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
1027 m_versionExceptionHash.remove(fullPath);
1031 updateFileTableChecks();
1032 updateVersionTableChecks();
1036 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
1038 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
1040 m_fileExceptionHash.insert(fullPath, state);
1041 m_fileExceptionMulti.insert(direcotry, fullPath);
1042 directoryIconStateInsert(fullPath, state);
1046 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
1048 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
1050 m_fileExceptionHash.remove(fullPath);
1051 /* pull the list of values in the multi */
1052 QStringList fullPathList = m_fileExceptionMulti.values(directory);
1053 /* get the index of the fullpath to remove */
1054 int index = fullPathList.indexOf(fullPath);
1056 /* remove the desired item in the list */
1057 fullPathList.removeAt(index);
1058 /* remove the entire list from the multi */
1059 m_fileExceptionMulti.remove(directory);
1060 /* readd the remaining */
1061 foreach (QString fp, fullPathList) {
1062 m_fileExceptionMulti.insert(directory, fp);
1065 directoryIconStateRemove();
1069 * Overloaded function to be called from the slot and from other places to set the state
1070 * of the check marks in the version table
1072 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
1074 /* get the previous and current check states */
1075 int row = versionTable->row(item);
1076 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
1077 Qt::CheckState prevState = m_versionCheckStateList[row];
1078 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
1079 m_versionCheckStateList[row] = curState;
1081 /* deterimine the default state from the state of the file */
1082 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1083 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1085 /* determine the default state */
1086 Qt::CheckState defState;
1088 defState = Qt::PartiallyChecked;
1089 if (fileState == Qt::Unchecked)
1090 defState = Qt::Unchecked;
1093 defState = Qt::Unchecked;
1095 /* determine if it is already in the versionExceptionHash */
1096 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1097 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1098 QString file = fileTableItem->text();
1099 QString fullPath = directory + file;
1100 int thisJobNum = colZeroItem->text().toInt();
1101 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1103 if (mainWin->m_rtVerTabICDebug) {
1104 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1105 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1106 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1107 Pmsg1(000, "%s", msg.toUtf8().data()); }
1108 /* if changed from partially checked to checked, make it unchecked */
1109 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1110 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1111 fileTableItem->setCheckState(Qt::Checked);
1112 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1113 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1114 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1115 fileExceptionRemove(fullPath, directory);
1116 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1117 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1118 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1119 m_versionExceptionHash.remove(fullPath);
1120 fileExceptionRemove(fullPath, directory);
1121 } else if ((curState == Qt::Checked) && (row == 0)) {
1122 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1123 m_versionExceptionHash.remove(fullPath);
1124 } else if (prevState != curState) {
1125 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1126 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked && row != 0)) {
1127 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1128 m_versionExceptionHash.insert(fullPath, thisJobNum);
1129 if (fileState != Qt::Checked) {
1130 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1131 fileExceptionInsert(fullPath, directory, curState);
1134 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1137 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1140 updateFileTableChecks();
1141 updateVersionTableChecks();
1145 * Simple function to set the check state in the file table by disconnecting the
1146 * signal/slot the setting then reconnecting the signal/slot
1148 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1150 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1151 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1152 item->setCheckState(state);
1153 if (color) item->setBackground(Qt::yellow);
1154 else item->setBackground(Qt::white);
1155 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1156 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1160 * Simple function to set the check state in the version table by disconnecting the
1161 * signal/slot the setting then reconnecting the signal/slot
1163 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1165 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1166 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1167 item->setCheckState(state);
1168 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1169 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1173 * Simple function to set the check state in the directory tree by disconnecting the
1174 * signal/slot the setting then reconnecting the signal/slot
1176 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1178 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1179 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1180 item->setCheckState(0, state);
1181 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1182 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1186 * Simplify the updating of the check state in the File table by iterating through
1187 * each item in the file table to determine it's appropriate state.
1188 * !! Will probably want to concoct a way to do this without iterating for the possibility
1189 * of the very large directories.
1191 void restoreTree::updateFileTableChecks()
1193 /* deterimine the default state from the state of the directory */
1194 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1195 Qt::CheckState dirState = dirTreeItem->checkState(0);
1197 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1199 /* Update the items in the version table */
1200 int rcnt = fileTable->rowCount();
1201 for (int row=0; row<rcnt; row++) {
1202 QTableWidgetItem* item = fileTable->item(row, 0);
1204 Qt::CheckState curState = item->checkState();
1205 Qt::CheckState newState = Qt::PartiallyChecked;
1206 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1208 /* determine if it is already in the m_fileExceptionHash */
1209 QString file = item->text();
1210 QString fullPath = dirName + file;
1211 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1212 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1214 if (hashState != 3) newState = hashState;
1216 if (mainWin->m_rtUpdateFTDebug) {
1217 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1218 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1219 Pmsg1(000, "%s", msg.toUtf8().data());
1222 bool docolor = false;
1223 if (hashJobNum != 0) docolor = true;
1224 bool isyellow = item->background().color() == QColor(Qt::yellow);
1225 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1226 fileTableDisconnectedSet(item, newState, docolor);
1227 m_fileCheckStateList[row] = newState;
1232 * Simplify the updating of the check state in the Version table by iterating through
1233 * each item in the file table to determine it's appropriate state.
1235 void restoreTree::updateVersionTableChecks()
1237 /* deterimine the default state from the state of the directory */
1238 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1239 Qt::CheckState dirState = dirTreeItem->checkState(0);
1240 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1242 /* deterimine the default state from the state of the file */
1243 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1244 Qt::CheckState fileState = fileTableItem->checkState();
1245 QString file = fileTableItem->text();
1246 QString fullPath = dirName + file;
1247 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1249 /* Update the items in the version table */
1250 int cnt = versionTable->rowCount();
1251 for (int row=0; row<cnt; row++) {
1252 QTableWidgetItem* item = versionTable->item(row, 0);
1254 Qt::CheckState curState = item->checkState();
1255 Qt::CheckState newState = Qt::Unchecked;
1257 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1258 newState = Qt::PartiallyChecked;
1259 /* determine if it is already in the versionExceptionHash */
1261 int thisJobNum = item->text().toInt();
1262 if (thisJobNum == hashJobNum)
1263 newState = Qt::Checked;
1265 if (mainWin->m_rtChecksDebug) {
1266 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1267 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1268 Pmsg1(000, "%s", msg.toUtf8().data());
1270 if (newState != curState)
1271 versionTableDisconnectedSet(item, newState);
1272 m_versionCheckStateList[row] = newState;
1277 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1279 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1283 QString fullPath = fullPath_in;
1284 QString direct, path;
1285 while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
1286 direct = path = fullPath;
1287 path.replace(index+1, fullPath.length()-index-1, "");
1288 direct.replace(0, index+1, "");
1290 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1291 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1292 Pmsg0(000, msg.toUtf8().data());
1295 subPaths.append(fullPath);
1300 * A Function to set the icon state and insert a record into
1301 * m_directoryIconStateHash when an exception is added by the user
1303 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1306 fullPathtoSubPaths(paths, fullPath);
1307 /* an exception that causes the item in the file table to be "Checked" has occured */
1308 if (excpState == Qt::Checked) {
1309 bool foundAsUnChecked = false;
1310 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1312 if (firstItem->checkState(0) == Qt::Unchecked)
1313 foundAsUnChecked = true;
1315 if (foundAsUnChecked) {
1316 /* as long as directory item is Unchecked, set icon state to "green check" */
1318 QListIterator<QString> siter(paths);
1319 while (siter.hasNext() && !done) {
1320 QString path = siter.next();
1321 QTreeWidgetItem *item = m_dirPaths.value(path);
1323 if (item->checkState(0) != Qt::Unchecked)
1326 directorySetIcon(1, FolderGreenChecked, path, item);
1327 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1332 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1333 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1335 QListIterator<QString> siter(paths);
1336 while (siter.hasNext() && !done) {
1337 QString path = siter.next();
1338 QTreeWidgetItem *item = m_dirPaths.value(path);
1339 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1340 if (item->checkState(0) == Qt::Checked)
1342 directorySetIcon(1, FolderGreenChecked, path, item);
1343 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1348 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1349 if (excpState == Qt::Unchecked) {
1351 QListIterator<QString> siter(paths);
1352 while (siter.hasNext() && !done) {
1353 QString path = siter.next();
1354 QTreeWidgetItem *item = m_dirPaths.value(path);
1355 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1356 if (item->checkState(0) == Qt::Checked)
1358 directorySetIcon(1, FolderWhiteChecked, path, item);
1359 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1366 * A function to set the icon state back to "folder" and to remove a record from
1367 * m_directoryIconStateHash when an exception is removed by a user.
1369 void restoreTree::directoryIconStateRemove()
1371 QHash<QString, int> shouldBeIconStateHash;
1372 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1373 /* Use iterator tera to iterate through m_fileExceptionHash */
1374 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1375 while (tera.hasNext()) {
1377 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1379 QString keyPath = tera.key();
1380 Qt::CheckState state = tera.value();
1383 fullPathtoSubPaths(paths, keyPath);
1384 /* if the state of the item in m_fileExceptionHash is checked
1385 * each of the subpaths should be "Checked Green" */
1386 if (state == Qt::Checked) {
1388 bool foundAsUnChecked = false;
1389 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1391 if (firstItem->checkState(0) == Qt::Unchecked)
1392 foundAsUnChecked = true;
1394 if (foundAsUnChecked) {
1395 /* The right most directory is Unchecked, iterate leftwards
1396 * as long as directory item is Unchecked, set icon state to "green check" */
1398 QListIterator<QString> siter(paths);
1399 while (siter.hasNext() && !done) {
1400 QString path = siter.next();
1401 QTreeWidgetItem *item = m_dirPaths.value(path);
1403 if (item->checkState(0) != Qt::Unchecked)
1406 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1407 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1413 /* The right most directory is Unchecked, iterate leftwards
1414 * until directory item is Checked, set icon state to "green check" */
1416 QListIterator<QString> siter(paths);
1417 while (siter.hasNext() && !done) {
1418 QString path = siter.next();
1419 QTreeWidgetItem *item = m_dirPaths.value(path);
1421 if (item->checkState(0) == Qt::Checked)
1423 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1428 /* if the state of the item in m_fileExceptionHash is UNChecked
1429 * each of the subpaths should be "Checked white" until the tree item
1430 * which represents that path is Qt::Checked */
1431 if (state == Qt::Unchecked) {
1433 QListIterator<QString> siter(paths);
1434 while (siter.hasNext() && !done) {
1435 QString path = siter.next();
1436 QTreeWidgetItem *item = m_dirPaths.value(path);
1438 if (item->checkState(0) == Qt::Checked)
1440 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1445 /* now iterate through m_directoryIconStateHash which are the items that are checked
1446 * and remove all of those that are not in shouldBeIconStateHash */
1447 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1448 while (iter.hasNext()) {
1450 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1452 QString keyPath = iter.key();
1453 if (shouldBeIconStateHash.value(keyPath)) {
1454 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1455 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1456 int newval = shouldBeIconStateHash.value(keyPath);
1458 newval = newval & FolderBothChecked;
1459 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1461 directorySetIcon(0, newval, keyPath, item);
1463 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1464 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1466 directorySetIcon(0, FolderBothChecked, keyPath, item);
1467 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1468 //m_directoryIconStateHash.remove(keyPath);
1473 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1475 /* we are adding a check type white or green */
1476 if (operation > 0) {
1477 /* get the old val and "bitwise OR" with the change */
1478 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1479 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1480 m_directoryIconStateHash.insert(path, newval);
1482 /* we are removing a check type white or green */
1483 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1485 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1486 m_directoryIconStateHash.remove(path);
1489 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1490 m_directoryIconStateHash.insert(path, newval);
1493 if (newval == FolderUnchecked)
1494 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1495 else if (newval == FolderGreenChecked)
1496 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1497 else if (newval == FolderWhiteChecked)
1498 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1499 else if (newval == FolderBothChecked)
1500 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1506 void restoreTree::restoreButtonPushed()
1508 /* Set progress bars and repaint */
1509 prLabel1->setVisible(true);
1510 prLabel1->setText(tr("Task 1 of 3"));
1511 prLabel2->setVisible(true);
1512 prLabel2->setText(tr("Processing Checked directories"));
1513 prBar1->setVisible(true);
1514 prBar1->setRange(0, 3);
1515 prBar1->setValue(0);
1516 prBar2->setVisible(true);
1517 prBar2->setRange(0, 0);
1519 QMultiHash<int, QString> versionFilesMulti;
1521 QHash <QString, bool> fullPathDone;
1522 QHash <QString, int> fileIndexHash;
1523 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1524 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1525 /* Use a tree widget item iterator to count directories for the progress bar */
1526 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1531 } /* while (*diterc) */
1532 prBar2->setRange(0, ditcount);
1533 prBar2->setValue(0);
1535 /* Use a tree widget item iterator filtering for Checked Items */
1536 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1538 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1539 int pathid = m_directoryPathIdHash.value(directory, -1);
1541 if (mainWin->m_rtRestore1Debug)
1542 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1543 /* With a checked directory, query for the files in the directory */
1546 "SELECT Filename.Name AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1548 " ( SELECT File.FilenameId AS FilenameId, MAX(Job.JobId) AS JobId"
1550 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1551 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1552 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1553 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1554 " GROUP BY File.FilenameId"
1556 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1557 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1558 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1559 " AND File.FilenameId=t1.FilenameId"
1560 " AND Job.Jobid=t1.JobId"
1561 " ORDER BY Filename";
1563 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1564 QStringList results;
1565 if (m_console->sql_cmd(cmd, results)) {
1566 QStringList fieldlist;
1569 /* Iterate through the record returned from the query */
1570 foreach (QString resultline, results) {
1571 /* Iterate through fields in the record */
1573 QString fullPath = "";
1574 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1575 fieldlist = resultline.split("\t");
1578 foreach (QString field, fieldlist) {
1580 fullPath = directory + field;
1583 version = field.toInt();
1586 fileIndex = field.toInt();
1590 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1592 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1593 if (fileExcpState != Qt::Unchecked) {
1595 if (excpVersion != 0) {
1596 debugtext = QString("*E* version=%1").arg(excpVersion);
1597 version = excpVersion;
1598 fileIndex = queryFileIndex(fullPath, excpVersion);
1600 debugtext = QString("___ version=%1").arg(version);
1601 if (mainWin->m_rtRestore1Debug)
1602 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1603 fullPathDone.insert(fullPath, 1);
1604 fileIndexHash.insert(fullPath, fileIndex);
1605 versionFilesMulti.insert(version, fullPath);
1613 prBar2->setValue(ditcount);
1615 } /* while (*diter) */
1616 prBar1->setValue(1);
1617 prLabel1->setText( tr("Task 2 of 3"));
1618 prLabel2->setText(tr("Processing Exceptions"));
1619 prBar2->setRange(0, 0);
1622 /* There may be some exceptions not accounted for yet with fullPathDone */
1623 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1624 while (ftera.hasNext()) {
1626 QString fullPath = ftera.key();
1627 Qt::CheckState state = ftera.value();
1629 /* now we don't want the ones already done */
1630 if (fullPathDone.value(fullPath, 0) == 0) {
1631 int version = m_versionExceptionHash.value(fullPath, 0);
1633 QString debugtext = "";
1635 fileIndex = queryFileIndex(fullPath, version);
1636 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1638 version = mostRecentVersionfromFullPath(fullPath);
1640 fileIndex = queryFileIndex(fullPath, version);
1641 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1643 debugtext = QString("Error det vers").arg(version);
1645 if (mainWin->m_rtRestore1Debug)
1646 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1647 versionFilesMulti.insert(version, fullPath);
1649 fileIndexHash.insert(fullPath, fileIndex);
1650 } /* if fullPathDone.value(fullPath, 0) == 0 */
1651 } /* if state != 0 */
1652 } /* while ftera.hasNext */
1653 /* The progress bars for the next step */
1654 prBar1->setValue(2);
1655 prLabel1->setText(tr("Task 3 of 3"));
1656 prLabel2->setText(tr("Filling Database Table"));
1657 prBar2->setRange(0, vFMCounter);
1659 prBar2->setValue(vFMCounter);
1662 /* now for the final spit out of the versions and lists of files for each version */
1663 QHash<int, int> doneKeys;
1664 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1665 QString tempTable = "";
1667 while (vFMiter.hasNext()) {
1669 int fversion = vFMiter.key();
1670 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1671 if (doneKeys.value(fversion, 0) == 0) {
1672 if (tempTable == "") {
1673 QSettings settings("www.bacula.org", "bat");
1674 settings.beginGroup("Restore");
1675 int counter = settings.value("Counter", 1).toInt();
1676 settings.setValue("Counter", counter+1);
1677 settings.endGroup();
1678 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1679 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1680 if (mainWin->m_sqlDebug)
1681 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1682 QStringList results;
1683 if (!m_console->sql_cmd(sqlcmd, results))
1684 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1687 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1688 QStringList fullPathList = versionFilesMulti.values(fversion);
1689 /* create the command to perform the restore */
1690 foreach(QString ffullPath, fullPathList) {
1691 int fileIndex = fileIndexHash.value(ffullPath);
1692 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1693 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1694 if (mainWin->m_rtRestore3Debug)
1695 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1696 QStringList results;
1697 if (!m_console->sql_cmd(sqlcmd, results))
1698 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1699 prBar2->setValue(++vFMCounter);
1700 } /* foreach fullPathList */
1701 doneKeys.insert(fversion,1);
1702 jobList.append(fversion);
1703 } /* if (doneKeys.value(fversion, 0) == 0) */
1704 } /* while (vFMiter.hasNext()) */
1705 if (tempTable != "") {
1706 /* a table was made, lets run the job */
1707 QString jobOption = " jobid=\"";
1709 /* create a list of jobs comma separated */
1710 foreach (int job, jobList) {
1711 if (first) first = false;
1712 else jobOption += ",";
1713 jobOption += QString("%1").arg(job);
1716 QString cmd = QString("restore");
1718 " client=\"" + m_prevClientCombo + "\"" +
1719 " file=\"?" + tempTable + "\" done";
1720 if (mainWin->m_commandDebug)
1721 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1722 consoleCommand(cmd);
1724 /* turn off the progress widgets */
1725 prBar1->setVisible(false);
1726 prBar2->setVisible(false);
1727 prLabel1->setVisible(false);
1728 prLabel2->setVisible(false);
1731 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1734 QString directory, fileName;
1735 int index = fullPath.lastIndexOf("/", -2);
1737 directory = fileName = fullPath;
1738 directory.replace(index+1, fullPath.length()-index-1, "");
1739 fileName.replace(0, index+1, "");
1741 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1742 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1743 Pmsg0(000, msg.toUtf8().data());
1745 int pathid = m_directoryPathIdHash.value(directory, -1);
1747 /* so now we need the latest version from the database */
1749 "SELECT MAX(Job.JobId)"
1751 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1752 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1753 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1754 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1755 " AND Filename.Name='" + fileName + "'"
1756 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1757 " GROUP BY Filename.Name";
1759 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1760 QStringList results;
1761 if (m_console->sql_cmd(cmd, results)) {
1762 QStringList fieldlist;
1764 /* Iterate through the record returned from the query */
1765 foreach (QString resultline, results) {
1766 /* Iterate through fields in the record */
1768 fieldlist = resultline.split("\t");
1769 foreach (QString field, fieldlist) {
1771 qversion = field.toInt();
1779 } /* if (index != -1) */
1784 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1787 QString directory, fileName;
1788 int index = fullPath.lastIndexOf("/", -2);
1790 directory = fileName = fullPath;
1791 directory.replace(index+1, fullPath.length()-index-1, "");
1792 fileName.replace(0, index+1, "");
1794 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1795 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1796 Pmsg0(000, msg.toUtf8().data());
1798 int pathid = m_directoryPathIdHash.value(directory, -1);
1800 /* so now we need the latest version from the database */
1805 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1806 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1807 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1808 " AND Filename.Name='" + fileName + "'"
1809 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1810 " GROUP BY File.FileIndex";
1812 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1813 QStringList results;
1814 if (m_console->sql_cmd(cmd, results)) {
1815 QStringList fieldlist;
1817 /* Iterate through the record returned from the query */
1818 foreach (QString resultline, results) {
1819 /* Iterate through fields in the record */
1821 fieldlist = resultline.split("\t");
1822 foreach (QString field, fieldlist) {
1824 qfileIndex = field.toInt();
1832 } /* if (index != -1) */