2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2010 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 three of the GNU Affero 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 Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
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.
33 * Kern Sibbald, February MMVII
38 #include "restoretree.h"
41 restoreTree::restoreTree() : Pages()
44 m_name = tr("Version Browser");
46 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
47 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
54 QGridLayout *gridLayout = new QGridLayout(this);
55 gridLayout->setSpacing(6);
56 gridLayout->setMargin(9);
57 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
59 m_splitter = new QSplitter(Qt::Vertical, this);
60 QScrollArea *area = new QScrollArea();
61 area->setObjectName(QString::fromUtf8("area"));
62 area->setWidget(widget);
63 area->setWidgetResizable(true);
64 m_splitter->addWidget(area);
65 m_splitter->addWidget(splitter);
66 splitter->setChildrenCollapsible(false);
68 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
70 /* progress widgets */
71 prBar1->setVisible(false);
72 prBar2->setVisible(false);
73 prLabel1->setVisible(false);
74 prLabel2->setVisible(false);
76 /* Set Defaults for check and spin for limits */
77 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
78 limitSpinBox->setValue(mainWin->m_recordLimitVal);
79 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
80 daysSpinBox->setValue(mainWin->m_daysLimitVal);
82 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()
159 directoryTree->clear();
161 fileTable->setRowCount(0);
162 fileTable->setColumnCount(0);
163 versionTable->clear();
164 versionTable->setRowCount(0);
165 versionTable->setColumnCount(0);
166 m_fileExceptionHash.clear();
167 m_fileExceptionMulti.clear();
168 m_versionExceptionHash.clear();
169 m_directoryIconStateHash.clear();
172 int taskcount = 3, ontask = 1;
173 if (m_dropdownChanged) taskcount += 1;
175 /* Set progress bars and repaint */
176 prBar1->setVisible(true);
177 prBar1->setRange(0,taskcount);
179 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
180 prLabel1->setVisible(true);
181 prBar2->setVisible(true);
182 prBar2->setRange(0,0);
183 prLabel2->setText(tr("Querying Database"));
184 prLabel2->setVisible(true);
187 if (m_dropdownChanged) {
188 m_prevJobCombo = jobCombo->currentText();
189 m_prevClientCombo = clientCombo->currentText();
190 m_prevFileSetCombo = fileSetCombo->currentText();
191 m_prevLimitSpinBox = limitSpinBox->value();
192 m_prevDaysSpinBox = daysSpinBox->value();
193 m_prevLimitCheckState = limitCheckBox->checkState();
194 m_prevDaysCheckState = daysCheckBox->checkState();
196 prBar1->setValue(ontask++);
197 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
199 prBar2->setRange(0,0);
200 prLabel2->setText(tr("Querying Jobs"));
204 setJobsCheckedList();
205 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
207 if (m_checkedJobs != "") {
208 /* First get the filenameid of where the nae is null. These will be the directories
209 * This could be done in a subquery but postgres's query analyzer won't do the right
210 * thing like I want */
211 if (m_nullFileNameId == -1) {
212 QString cmd = "SELECT FilenameId FROM Filename WHERE name=''";
213 if (mainWin->m_sqlDebug)
214 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
216 if (m_console->sql_cmd(cmd, qres)) {
218 QStringList fieldlist = qres[0].split("\t");
219 QString field = fieldlist[0];
221 int val = field.toInt(&ok, 10);
222 if (ok) m_nullFileNameId = val;
226 /* now create the query to get the list of paths */
228 "SELECT DISTINCT Path.Path AS Path, File.PathId AS PathId"
230 " INNER JOIN Path ON (File.PathId=Path.PathId)";
231 if (m_nullFileNameId != -1)
232 cmd += " WHERE File.FilenameId=" + QString("%1").arg(m_nullFileNameId);
234 cmd += " WHERE File.FilenameId IN (SELECT FilenameId FROM Filename WHERE Name='')";
235 cmd += " AND File.Jobid IN (" + m_checkedJobs + ")";
236 if (mainWin->m_sqlDebug)
237 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
238 prBar1->setValue(ontask++);
239 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
241 prBar2->setRange(0,0);
242 prLabel2->setText(tr("Querying for Directories"));
245 m_directoryPathIdHash.clear();
246 bool querydone = false;
247 if (m_console->sql_cmd(cmd, results)) {
250 prLabel2->setText(tr("Processing Directories"));
251 prBar2->setRange(0,results.count());
254 if (mainWin->m_miscDebug)
255 Pmsg1(000, "Done with query %i results\n", results.count());
256 QStringList fieldlist;
257 foreach(const QString &resultline, results) {
258 /* Update progress bar periodically */
259 if ((++m_debugCnt && 0x3FF) == 0) {
260 prBar2->setValue(m_debugCnt);
262 fieldlist = resultline.split("\t");
264 /* Iterate through fields in the record */
265 foreach (const QString &field, fieldlist) {
266 if (fieldcnt == 0 ) {
267 parseDirectory(field);
268 } else if (fieldcnt == 1) {
270 int pathid = field.toInt(&ok, 10);
272 m_directoryPathIdHash.insert(fieldlist[0], pathid);
281 QMessageBox::warning(this, "Bat",
282 tr("No jobs were selected in the job query !!!.\n"
283 "Press OK to continue"),
286 prBar1->setVisible(false);
287 prBar2->setVisible(false);
288 prLabel1->setVisible(false);
289 prLabel2->setVisible(false);
293 * Function to set m_checkedJobs from the jobs that are checked in the table
296 void restoreTree::setJobsCheckedList()
298 m_JobsCheckedList = "";
300 /* Update the items in the version table */
301 int cnt = jobTable->rowCount();
302 for (int row=0; row<cnt; row++) {
303 QTableWidgetItem* jobItem = jobTable->item(row, 0);
304 if (jobItem->checkState() == Qt::Checked) {
306 m_JobsCheckedList += ",";
307 m_JobsCheckedList += jobItem->text();
309 jobItem->setBackground(Qt::green);
311 if (jobItem->flags())
312 jobItem->setBackground(Qt::gray);
314 jobItem->setBackground(Qt::darkYellow);
317 m_checkedJobs = m_JobsCheckedList;
321 * Function to parse a directory into all possible subdirectories, then add to
324 void restoreTree::parseDirectory(const QString &dir_in)
326 // bail out if already processed
327 if (m_dirPaths.contains(dir_in))
329 // search for parent...
330 int pos=dir_in.lastIndexOf("/",-2);
334 QString parent=dir_in.left(pos+1);
335 QString subdir=dir_in.mid(pos+1);
337 QTreeWidgetItem *item = NULL;
338 QTreeWidgetItem *parentItem = m_dirPaths.value(parent);
341 // recurse to build parent...
342 parseDirectory(parent);
343 parentItem = m_dirPaths.value(parent);
346 /* new directories to add */
347 item = new QTreeWidgetItem(parentItem);
348 item->setText(0, subdir);
349 item->setData(0, Qt::UserRole, QVariant(dir_in));
350 item->setCheckState(0, Qt::Unchecked);
351 /* Store the current state of the check status in column 1, which at
352 * this point has no text*/
353 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
354 m_dirPaths.insert(dir_in,item);
358 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
359 item->setText(0, dir_in);
360 item->setData(0, Qt::UserRole, QVariant(dir_in));
361 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
362 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
363 m_dirPaths.insert(dir_in,item);
368 * Virtual function which is called when this page is visible on the stack
370 void restoreTree::currentStackItem()
379 * Populate the tree when refresh button pushed.
381 void restoreTree::refreshButtonPushed()
383 populateDirectoryTree();
387 * Set the values of non-job combo boxes to the job defaults
389 void restoreTree::jobComboChanged(int)
391 if (jobCombo->currentText() == tr("Any")) {
392 fileSetCombo->setCurrentIndex(fileSetCombo->findText(tr("Any"), Qt::MatchExactly));
395 job_defaults job_defs;
398 job_defs.job_name = jobCombo->currentText();
399 if (m_console->get_job_defaults(job_defs)) {
400 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
401 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
406 * Function to populate the file list table
408 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
414 /* Also clear the version table here */
415 versionTable->clear();
416 versionFileLabel->setText("");
417 versionTable->setRowCount(0);
418 versionTable->setColumnCount(0);
420 QStringList headerlist = (QStringList() << tr("File Name") << tr("Filename Id"));
421 fileTable->setColumnCount(headerlist.size());
422 fileTable->setHorizontalHeaderLabels(headerlist);
423 fileTable->setRowCount(0);
425 m_fileCheckStateList.clear();
426 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
427 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
428 QBrush blackBrush(Qt::black);
429 QString directory = item->data(0, Qt::UserRole).toString();
430 directoryLabel->setText(tr("Present Working Directory: %1").arg(directory));
431 int pathid = m_directoryPathIdHash.value(directory, -1);
434 "SELECT DISTINCT Filename.Name AS FileName, Filename.FilenameId AS FilenameId"
436 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
437 " WHERE File.PathId=" + QString("%1").arg(pathid) +
438 " AND File.Jobid IN (" + m_checkedJobs + ")"
439 " AND Filename.Name!=''"
440 " ORDER BY FileName";
441 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
444 if (m_console->sql_cmd(cmd, results)) {
446 QTableWidgetItem* tableItem;
448 QStringList fieldlist;
449 fileTable->setRowCount(results.size());
452 /* Iterate through the record returned from the query */
453 foreach (QString resultline, results) {
454 /* Iterate through fields in the record */
456 fieldlist = resultline.split("\t");
457 foreach (field, fieldlist) {
458 field = field.trimmed(); /* strip leading & trailing spaces */
459 tableItem = new QTableWidgetItem(field, 1);
460 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
461 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
462 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
463 tableItem->setForeground(blackBrush);
464 /* Just in case a column ever gets added */
465 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
467 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
468 tableItem->setFlags(flag);
469 tableItem->setData(Qt::UserRole, QVariant(directory));
470 fileTable->setItem(row, column, tableItem);
471 m_fileCheckStateList.append(Qt::Unchecked);
472 tableItem->setCheckState(Qt::Unchecked);
473 } else if (column == 1) {
474 Qt::ItemFlags flag = Qt::ItemIsEnabled;
475 tableItem->setFlags(flag);
477 int filenameid = field.toInt(&ok, 10);
478 if (!ok) filenameid = -1;
479 tableItem->setData(Qt::UserRole, QVariant(filenameid));
480 fileTable->setItem(row, column, tableItem);
486 fileTable->setRowCount(row);
488 fileTable->resizeColumnsToContents();
489 fileTable->resizeRowsToContents();
490 fileTable->verticalHeader()->hide();
491 fileTable->hideColumn(1);
492 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
493 updateFileTableChecks();
494 } else if (mainWin->m_sqlDebug)
495 Pmsg1(000, "did not perform query, pathid=%i not found\n", pathid);
496 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
497 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
501 * Function to populate the version table
503 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *currentFileTableItem, QTableWidgetItem *)
505 if (currentFileTableItem == NULL)
508 int currentRow = fileTable->row(currentFileTableItem);
509 QTableWidgetItem *fileTableItem = fileTable->item(currentRow, 0);
510 QTableWidgetItem *fileNameIdTableItem = fileTable->item(currentRow, 1);
511 int fileNameId = fileNameIdTableItem->data(Qt::UserRole).toInt();
513 m_versionCheckStateList.clear();
514 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
515 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
517 QString file = fileTableItem->text();
518 versionFileLabel->setText(file);
519 QString directory = fileTableItem->data(Qt::UserRole).toString();
521 QBrush blackBrush(Qt::black);
523 QStringList headerlist = (QStringList()
524 << tr("Job Id") << tr("Type") << tr("End Time") << tr("Hash") << tr("FileId") << tr("Job Type") << tr("First Volume"));
525 versionTable->clear();
526 versionTable->setColumnCount(headerlist.size());
527 versionTable->setHorizontalHeaderLabels(headerlist);
528 versionTable->setRowCount(0);
530 int pathid = m_directoryPathIdHash.value(directory, -1);
531 if ((pathid != -1) && (fileNameId != -1)) {
533 "SELECT Job.JobId AS JobId, Job.Level AS Type,"
534 " Job.EndTime AS EndTime, File.MD5 AS MD5,"
535 " File.FileId AS FileId, Job.Type AS JobType,"
536 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume"
538 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
539 " INNER JOIN Path ON (Path.PathId=File.PathId)"
540 " INNER JOIN Job ON (File.JobId=Job.JobId)"
541 " WHERE Path.PathId=" + QString("%1").arg(pathid) +
542 //" AND Filename.Name='" + file + "'"
543 " AND Filename.FilenameId=" + QString("%1").arg(fileNameId) +
544 " AND Job.Jobid IN (" + m_checkedJobs + ")"
545 " ORDER BY Job.EndTime DESC";
547 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
549 if (m_console->sql_cmd(cmd, results)) {
551 QTableWidgetItem* tableItem;
553 QStringList fieldlist;
554 versionTable->setRowCount(results.size());
557 /* Iterate through the record returned from the query */
558 foreach (QString resultline, results) {
559 fieldlist = resultline.split("\t");
561 /* remove directory */
562 if (fieldlist[0].trimmed() != "") {
563 /* Iterate through fields in the record */
564 foreach (field, fieldlist) {
565 field = field.trimmed(); /* strip leading & trailing spaces */
567 QByteArray jtype(field.trimmed().toAscii());
569 field = job_type_to_str(jtype[0]);
572 tableItem = new QTableWidgetItem(field, 1);
573 tableItem->setFlags(0);
574 tableItem->setForeground(blackBrush);
575 tableItem->setData(Qt::UserRole, QVariant(directory));
576 versionTable->setItem(row, column, tableItem);
577 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
579 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
580 tableItem->setFlags(flag);
581 m_versionCheckStateList.append(Qt::Unchecked);
582 tableItem->setCheckState(Qt::Unchecked);
590 versionTable->resizeColumnsToContents();
591 versionTable->resizeRowsToContents();
592 versionTable->verticalHeader()->hide();
593 updateVersionTableChecks();
595 if (mainWin->m_sqlDebug)
596 Pmsg2(000, "not querying : pathid=%i fileNameId=%i\n", pathid, fileNameId);
598 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
599 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
603 * Save user settings associated with this page
605 void restoreTree::writeSettings()
607 QSettings settings(m_console->m_dir->name(), "bat");
608 settings.beginGroup(m_groupText);
609 settings.setValue(m_splitText1, m_splitter->saveState());
610 settings.setValue(m_splitText2, splitter->saveState());
615 * Read and restore user settings associated with this page
617 void restoreTree::readSettings()
619 m_groupText = tr("RestoreTreePage");
620 m_splitText1 = "splitterSizes1_3";
621 m_splitText2 = "splitterSizes2_3";
622 QSettings settings(m_console->m_dir->name(), "bat");
623 settings.beginGroup(m_groupText);
624 if (settings.contains(m_splitText1)) { m_splitter->restoreState(settings.value(m_splitText1).toByteArray()); }
625 if (settings.contains(m_splitText2)) { splitter->restoreState(settings.value(m_splitText2).toByteArray()); }
630 * This is a funcion to accomplish the one thing I struggled to figure out what
631 * was taking so long. It add the icons, but after the tree is made. Seemed to
632 * work fast after changing from png to png file for graphic.
634 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
636 int childCount = item->childCount();
637 for (int i=0; i<childCount; i++) {
638 QTreeWidgetItem *child = item->child(i);
639 if (child->icon(0).isNull())
640 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
645 * Show what jobs meet the criteria and are being used to
646 * populate the directory tree and file and version tables.
648 void restoreTree::populateJobTable()
650 QBrush blackBrush(Qt::black);
652 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
653 QStringList headerlist = (QStringList()
654 << tr("Job Id") << tr("End Time") << tr("Level") << tr("Type")
655 << tr("Name") << tr("Purged") << tr("TU") << tr("TD"));
656 m_toggleUpIndex = headerlist.indexOf(tr("TU"));
657 m_toggleDownIndex = headerlist.indexOf(tr("TD"));
658 int purgedIndex = headerlist.indexOf(tr("Purged"));
659 int typeIndex = headerlist.indexOf(tr("Type"));
661 jobTable->setColumnCount(headerlist.size());
662 jobTable->setHorizontalHeaderLabels(headerlist);
664 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime,"
665 " Job.Level AS Level, Job.Type AS Type,"
666 " Job.Name AS JobName, Job.purgedfiles AS Purged"
668 /* INNER JOIN FileSet eliminates all restore jobs */
669 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
670 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
672 " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
673 " Client.Name='" + clientCombo->currentText() + "'";
674 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != tr("Any"))) {
675 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
677 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != tr("Any"))) {
678 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
680 /* If Limit check box For limit by days is checked */
681 if (daysCheckBox->checkState() == Qt::Checked) {
682 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
683 QString since = stamp.toString(Qt::ISODate);
684 jobQuery += " AND Job.Starttime>'" + since + "'";
686 //jobQuery += " AND Job.purgedfiles=0";
687 jobQuery += " ORDER BY Job.EndTime DESC";
688 /* If Limit check box for limit records returned is checked */
689 if (limitCheckBox->checkState() == Qt::Checked) {
691 limit.setNum(limitSpinBox->value());
692 jobQuery += " LIMIT " + limit;
694 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
698 if (m_console->sql_cmd(jobQuery, results)) {
700 QTableWidgetItem* tableItem;
702 QStringList fieldlist;
703 jobTable->setRowCount(results.size());
706 /* Iterate through the record returned from the query */
707 foreach (QString resultline, results) {
708 fieldlist = resultline.split("\t");
710 /* remove directory */
711 if (fieldlist[0].trimmed() != "") {
712 /* Iterate through fields in the record */
713 foreach (field, fieldlist) {
714 field = field.trimmed(); /* strip leading & trailing spaces */
716 if (column == typeIndex) {
717 QByteArray jtype(field.trimmed().toAscii());
719 field = job_type_to_str(jtype[0]);
722 tableItem = new QTableWidgetItem(field, 1);
723 tableItem->setFlags(0);
724 tableItem->setForeground(blackBrush);
725 jobTable->setItem(row, column, tableItem);
726 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
729 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
730 if (!((ok) && (purged == 1))) {
731 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
732 tableItem->setFlags(flag);
733 tableItem->setCheckState(Qt::Checked);
734 tableItem->setBackground(Qt::green);
736 tableItem->setFlags(0);
737 tableItem->setCheckState(Qt::Unchecked);
743 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
744 tableItem->setFlags(0);
745 tableItem->setForeground(blackBrush);
746 jobTable->setItem(row, column, tableItem);
748 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
749 tableItem->setFlags(0);
750 tableItem->setForeground(blackBrush);
751 jobTable->setItem(row, column, tableItem);
756 jobTable->resizeColumnsToContents();
757 jobTable->resizeRowsToContents();
758 jobTable->verticalHeader()->hide();
759 jobTable->hideColumn(purgedIndex);
762 void restoreTree::jobTableCellClicked(int row, int column)
764 if (column == m_toggleUpIndex){
766 for (cnt=0; cnt<row+1; cnt++) {
767 QTableWidgetItem *item = jobTable->item(cnt, 0);
769 Qt::CheckState state = item->checkState();
770 if (state == Qt::Checked)
771 item->setCheckState(Qt::Unchecked);
772 else if (state == Qt::Unchecked)
773 item->setCheckState(Qt::Checked);
777 if (column == m_toggleDownIndex){
778 int cnt, max = jobTable->rowCount();
779 for (cnt=row; cnt<max; cnt++) {
780 QTableWidgetItem *item = jobTable->item(cnt, 0);
782 Qt::CheckState state = item->checkState();
783 if (state == Qt::Checked)
784 item->setCheckState(Qt::Unchecked);
785 else if (state == Qt::Unchecked)
786 item->setCheckState(Qt::Checked);
793 * When a directory item is "changed" check the state of the checkable item
794 * to see if it is different than what it was which is stored in Qt::UserRole
795 * of the 2nd column, column 1, of the tree widget.
797 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
799 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
800 Qt::CheckState curState = item->checkState(0);
801 QTreeWidgetItem* parent = item->parent();
802 Qt::CheckState parState;
803 if (parent) parState = parent->checkState(0);
804 else parState = (Qt::CheckState)3;
805 if (mainWin->m_rtDirICDebug) {
806 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
807 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
808 Pmsg1(000, "%s", msg.toUtf8().data()); }
809 /* I only care when the check state changes */
810 if (prevState == curState) {
811 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
815 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
816 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
817 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
818 curState = Qt::PartiallyChecked;
820 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
821 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
822 directoryTreeDisconnectedSet(item, Qt::Unchecked);
823 curState = Qt::Unchecked;
825 if (mainWin->m_rtDirICDebug) {
826 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
827 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
828 Pmsg1(000, "%s", msg.toUtf8().data()); }
830 item->setData(1, Qt::UserRole, QVariant(curState));
831 Qt::CheckState childState = curState;
832 if (childState == Qt::Checked)
833 childState = Qt::PartiallyChecked;
834 setCheckofChildren(item, childState);
836 /* Remove items from the exception lists. The multi exception list is my index
837 * of what exceptions can be removed when the directory is known*/
838 QString directory = item->data(0, Qt::UserRole).toString();
839 QStringList fullPathList = m_fileExceptionMulti.values(directory);
840 int fullPathListCount = fullPathList.count();
841 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
842 foreach (QString fullPath, fullPathList) {
843 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
844 * which will match no Qt::xxx values */
845 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
846 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
847 if (hashState == Qt::Unchecked) {
848 fileExceptionRemove(fullPath, directory);
849 m_versionExceptionHash.remove(fullPath);
850 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
852 if (hashState == Qt::Checked) {
853 fileExceptionRemove(fullPath, directory);
854 m_versionExceptionHash.remove(fullPath);
855 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
859 if (item == directoryTree->currentItem()) {
860 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
861 updateFileTableChecks();
862 versionTable->clear();
863 versionTable->setRowCount(0);
864 versionTable->setColumnCount(0);
866 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
870 * When a directory item check state is changed, this function iterates through
871 * all subdirectories and sets all to the passed state, which is either partially
872 * checked or unchecked.
874 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
877 childCount = item->childCount();
878 for (int i=0; i<childCount; i++) {
879 QTreeWidgetItem *child = item->child(i);
880 child->setData(1, Qt::UserRole, QVariant(state));
881 child->setCheckState(0, state);
882 setCheckofChildren(child, state);
887 * When a File Table Item is "changed" check to see if the state of the checkable
888 * item has changed which is stored in m_fileCheckStateList
889 * If changed store in a hash m_fileExceptionHash that whether this file should be
891 * Called as a slot, connected after populated (after directory current changed called)
893 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
895 /* get the previous and current check states */
896 int row = fileTable->row(item);
897 Qt::CheckState prevState;
898 /* prevent a segfault */
899 prevState = m_fileCheckStateList[row];
900 Qt::CheckState curState = item->checkState();
902 /* deterimine the default state from the state of the directory */
903 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
904 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
905 Qt::CheckState defState = Qt::PartiallyChecked;
906 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
908 /* determine if it is already in the m_fileExceptionHash */
909 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
910 QString file = item->text();
911 QString fullPath = directory + file;
912 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
913 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
915 if (mainWin->m_rtFileTabICDebug) {
916 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
917 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
918 Pmsg1(000, "%s", msg.toUtf8().data()); }
920 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
921 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
922 /* it can behave as defaulted so current of unchecked is fine */
923 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
924 fileExceptionRemove(fullPath, directory);
925 m_versionExceptionHash.remove(fullPath);
926 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
927 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
928 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
929 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
930 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
931 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
932 fileExceptionRemove(fullPath, directory);
933 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
934 /* Check dir, check version, attempt uncheck in file
935 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
936 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
937 fileExceptionRemove(fullPath, directory);
938 m_versionExceptionHash.remove(fullPath);
939 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
940 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
941 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
942 } else if (prevState != curState) {
943 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
944 /* A user did not set the check state to Partially checked, ignore if so */
945 if (curState != Qt::PartiallyChecked) {
946 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
947 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
949 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
950 fileExceptionInsert(fullPath, directory, curState);
953 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
954 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
955 m_versionExceptionHash.remove(fullPath);
959 updateFileTableChecks();
960 updateVersionTableChecks();
964 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
966 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
968 m_fileExceptionHash.insert(fullPath, state);
969 m_fileExceptionMulti.insert(direcotry, fullPath);
970 directoryIconStateInsert(fullPath, state);
974 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
976 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
978 m_fileExceptionHash.remove(fullPath);
979 /* pull the list of values in the multi */
980 QStringList fullPathList = m_fileExceptionMulti.values(directory);
981 /* get the index of the fullpath to remove */
982 int index = fullPathList.indexOf(fullPath);
984 /* remove the desired item in the list */
985 fullPathList.removeAt(index);
986 /* remove the entire list from the multi */
987 m_fileExceptionMulti.remove(directory);
988 /* readd the remaining */
989 foreach (QString fp, fullPathList) {
990 m_fileExceptionMulti.insert(directory, fp);
993 directoryIconStateRemove();
997 * Overloaded function to be called from the slot and from other places to set the state
998 * of the check marks in the version table
1000 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
1002 /* get the previous and current check states */
1003 int row = versionTable->row(item);
1004 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
1005 Qt::CheckState prevState = m_versionCheckStateList[row];
1006 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
1007 m_versionCheckStateList[row] = curState;
1009 /* deterimine the default state from the state of the file */
1010 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1011 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1013 /* determine the default state */
1014 Qt::CheckState defState;
1015 if (mainWin->m_sqlDebug) Pmsg1(000, "row=%d\n", row);
1017 defState = Qt::PartiallyChecked;
1018 if (fileState == Qt::Unchecked)
1019 defState = Qt::Unchecked;
1021 defState = Qt::Unchecked;
1024 /* determine if it is already in the versionExceptionHash */
1025 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1026 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1027 QString file = fileTableItem->text();
1028 QString fullPath = directory + file;
1029 int thisJobNum = colZeroItem->text().toInt();
1030 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1032 if (mainWin->m_rtVerTabICDebug) {
1033 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1034 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1035 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1036 Pmsg1(000, "%s", msg.toUtf8().data()); }
1037 /* if changed from partially checked to checked, make it unchecked */
1038 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1039 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1040 fileTableItem->setCheckState(Qt::Checked);
1041 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1042 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1043 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1044 fileExceptionRemove(fullPath, directory);
1045 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1046 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1047 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1048 m_versionExceptionHash.remove(fullPath);
1049 fileExceptionRemove(fullPath, directory);
1050 } else if ((curState == Qt::Checked) && (row == 0)) {
1051 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1052 m_versionExceptionHash.remove(fullPath);
1053 } else if (prevState != curState) {
1054 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1055 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked)) {
1056 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1057 m_versionExceptionHash.insert(fullPath, thisJobNum);
1058 if (fileState != Qt::Checked) {
1059 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1060 fileExceptionInsert(fullPath, directory, curState);
1063 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1066 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1069 updateFileTableChecks();
1070 updateVersionTableChecks();
1074 * Simple function to set the check state in the file table by disconnecting the
1075 * signal/slot the setting then reconnecting the signal/slot
1077 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1079 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1080 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1081 item->setCheckState(state);
1082 if (color) item->setBackground(Qt::yellow);
1083 else item->setBackground(Qt::white);
1084 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1085 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1089 * Simple function to set the check state in the version table by disconnecting the
1090 * signal/slot the setting then reconnecting the signal/slot
1092 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1094 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1095 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1096 item->setCheckState(state);
1097 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1098 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1102 * Simple function to set the check state in the directory tree by disconnecting the
1103 * signal/slot the setting then reconnecting the signal/slot
1105 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1107 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1108 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1109 item->setCheckState(0, state);
1110 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1111 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1115 * Simplify the updating of the check state in the File table by iterating through
1116 * each item in the file table to determine it's appropriate state.
1117 * !! Will probably want to concoct a way to do this without iterating for the possibility
1118 * of the very large directories.
1120 void restoreTree::updateFileTableChecks()
1122 /* deterimine the default state from the state of the directory */
1123 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1124 Qt::CheckState dirState = dirTreeItem->checkState(0);
1126 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1128 /* Update the items in the version table */
1129 int rcnt = fileTable->rowCount();
1130 for (int row=0; row<rcnt; row++) {
1131 QTableWidgetItem* item = fileTable->item(row, 0);
1132 if (!item) { return; }
1134 Qt::CheckState curState = item->checkState();
1135 Qt::CheckState newState = Qt::PartiallyChecked;
1136 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1138 /* determine if it is already in the m_fileExceptionHash */
1139 QString file = item->text();
1140 QString fullPath = dirName + file;
1141 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1142 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1144 if (hashState != 3) newState = hashState;
1146 if (mainWin->m_rtUpdateFTDebug) {
1147 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1148 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1149 Pmsg1(000, "%s", msg.toUtf8().data());
1152 bool docolor = false;
1153 if (hashJobNum != 0) docolor = true;
1154 bool isyellow = item->background().color() == QColor(Qt::yellow);
1155 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1156 fileTableDisconnectedSet(item, newState, docolor);
1157 m_fileCheckStateList[row] = newState;
1162 * Simplify the updating of the check state in the Version table by iterating through
1163 * each item in the file table to determine it's appropriate state.
1165 void restoreTree::updateVersionTableChecks()
1167 /* deterimine the default state from the state of the directory */
1168 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1169 Qt::CheckState dirState = dirTreeItem->checkState(0);
1170 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1172 /* deterimine the default state from the state of the file */
1173 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1174 if (!fileTableItem) { return; }
1175 Qt::CheckState fileState = fileTableItem->checkState();
1176 QString file = fileTableItem->text();
1177 QString fullPath = dirName + file;
1178 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1180 /* Update the items in the version table */
1181 int cnt = versionTable->rowCount();
1182 for (int row=0; row<cnt; row++) {
1183 QTableWidgetItem* item = versionTable->item(row, 0);
1184 if (!item) { break; }
1186 Qt::CheckState curState = item->checkState();
1187 Qt::CheckState newState = Qt::Unchecked;
1189 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1190 newState = Qt::PartiallyChecked;
1191 /* determine if it is already in the versionExceptionHash */
1193 int thisJobNum = item->text().toInt();
1194 if (thisJobNum == hashJobNum)
1195 newState = Qt::Checked;
1197 if (mainWin->m_rtChecksDebug) {
1198 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1199 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1200 Pmsg1(000, "%s", msg.toUtf8().data());
1202 if (newState != curState)
1203 versionTableDisconnectedSet(item, newState);
1204 m_versionCheckStateList[row] = newState;
1209 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1211 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1215 QString fullPath = fullPath_in;
1216 QString direct, path;
1217 while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
1218 direct = path = fullPath;
1219 path.replace(index+1, fullPath.length()-index-1, "");
1220 direct.replace(0, index+1, "");
1222 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1223 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1224 Pmsg0(000, msg.toUtf8().data());
1227 subPaths.append(fullPath);
1232 * A Function to set the icon state and insert a record into
1233 * m_directoryIconStateHash when an exception is added by the user
1235 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1238 fullPathtoSubPaths(paths, fullPath);
1239 /* an exception that causes the item in the file table to be "Checked" has occured */
1240 if (excpState == Qt::Checked) {
1241 bool foundAsUnChecked = false;
1242 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1244 if (firstItem->checkState(0) == Qt::Unchecked)
1245 foundAsUnChecked = true;
1247 if (foundAsUnChecked) {
1248 /* as long as directory item is Unchecked, set icon state to "green check" */
1250 QListIterator<QString> siter(paths);
1251 while (siter.hasNext() && !done) {
1252 QString path = siter.next();
1253 QTreeWidgetItem *item = m_dirPaths.value(path);
1255 if (item->checkState(0) != Qt::Unchecked)
1258 directorySetIcon(1, FolderGreenChecked, path, item);
1259 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1264 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1265 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1267 QListIterator<QString> siter(paths);
1268 while (siter.hasNext() && !done) {
1269 QString path = siter.next();
1270 QTreeWidgetItem *item = m_dirPaths.value(path);
1271 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1272 if (item->checkState(0) == Qt::Checked)
1274 directorySetIcon(1, FolderGreenChecked, path, item);
1275 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1280 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1281 if (excpState == Qt::Unchecked) {
1283 QListIterator<QString> siter(paths);
1284 while (siter.hasNext() && !done) {
1285 QString path = siter.next();
1286 QTreeWidgetItem *item = m_dirPaths.value(path);
1287 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1288 if (item->checkState(0) == Qt::Checked)
1290 directorySetIcon(1, FolderWhiteChecked, path, item);
1291 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1298 * A function to set the icon state back to "folder" and to remove a record from
1299 * m_directoryIconStateHash when an exception is removed by a user.
1301 void restoreTree::directoryIconStateRemove()
1303 QHash<QString, int> shouldBeIconStateHash;
1304 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1305 /* Use iterator tera to iterate through m_fileExceptionHash */
1306 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1307 while (tera.hasNext()) {
1309 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1311 QString keyPath = tera.key();
1312 Qt::CheckState state = tera.value();
1315 fullPathtoSubPaths(paths, keyPath);
1316 /* if the state of the item in m_fileExceptionHash is checked
1317 * each of the subpaths should be "Checked Green" */
1318 if (state == Qt::Checked) {
1320 bool foundAsUnChecked = false;
1321 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1323 if (firstItem->checkState(0) == Qt::Unchecked)
1324 foundAsUnChecked = true;
1326 if (foundAsUnChecked) {
1327 /* The right most directory is Unchecked, iterate leftwards
1328 * as long as directory item is Unchecked, set icon state to "green check" */
1330 QListIterator<QString> siter(paths);
1331 while (siter.hasNext() && !done) {
1332 QString path = siter.next();
1333 QTreeWidgetItem *item = m_dirPaths.value(path);
1335 if (item->checkState(0) != Qt::Unchecked)
1338 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1339 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1345 /* The right most directory is Unchecked, iterate leftwards
1346 * until directory item is Checked, set icon state to "green check" */
1348 QListIterator<QString> siter(paths);
1349 while (siter.hasNext() && !done) {
1350 QString path = siter.next();
1351 QTreeWidgetItem *item = m_dirPaths.value(path);
1353 if (item->checkState(0) == Qt::Checked)
1355 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1360 /* if the state of the item in m_fileExceptionHash is UNChecked
1361 * each of the subpaths should be "Checked white" until the tree item
1362 * which represents that path is Qt::Checked */
1363 if (state == Qt::Unchecked) {
1365 QListIterator<QString> siter(paths);
1366 while (siter.hasNext() && !done) {
1367 QString path = siter.next();
1368 QTreeWidgetItem *item = m_dirPaths.value(path);
1370 if (item->checkState(0) == Qt::Checked)
1372 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1377 /* now iterate through m_directoryIconStateHash which are the items that are checked
1378 * and remove all of those that are not in shouldBeIconStateHash */
1379 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1380 while (iter.hasNext()) {
1382 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1384 QString keyPath = iter.key();
1385 if (shouldBeIconStateHash.value(keyPath)) {
1386 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1387 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1388 int newval = shouldBeIconStateHash.value(keyPath);
1390 newval = newval & FolderBothChecked;
1391 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1393 directorySetIcon(0, newval, keyPath, item);
1395 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1396 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1398 directorySetIcon(0, FolderBothChecked, keyPath, item);
1399 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1400 //m_directoryIconStateHash.remove(keyPath);
1405 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1407 /* we are adding a check type white or green */
1408 if (operation > 0) {
1409 /* get the old val and "bitwise OR" with the change */
1410 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1411 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1412 m_directoryIconStateHash.insert(path, newval);
1414 /* we are removing a check type white or green */
1415 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1417 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1418 m_directoryIconStateHash.remove(path);
1421 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1422 m_directoryIconStateHash.insert(path, newval);
1425 if (newval == FolderUnchecked)
1426 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1427 else if (newval == FolderGreenChecked)
1428 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1429 else if (newval == FolderWhiteChecked)
1430 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1431 else if (newval == FolderBothChecked)
1432 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1438 void restoreTree::restoreButtonPushed()
1440 /* Set progress bars and repaint */
1441 prLabel1->setVisible(true);
1442 prLabel1->setText(tr("Task 1 of 3"));
1443 prLabel2->setVisible(true);
1444 prLabel2->setText(tr("Processing Checked directories"));
1445 prBar1->setVisible(true);
1446 prBar1->setRange(0, 3);
1447 prBar1->setValue(0);
1448 prBar2->setVisible(true);
1449 prBar2->setRange(0, 0);
1451 QMultiHash<int, QString> versionFilesMulti;
1453 QHash <QString, bool> fullPathDone;
1454 QHash <QString, int> fileIndexHash;
1455 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1456 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1457 /* Use a tree widget item iterator to count directories for the progress bar */
1458 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1463 } /* while (*diterc) */
1464 prBar2->setRange(0, ditcount);
1465 prBar2->setValue(0);
1467 /* Use a tree widget item iterator filtering for Checked Items */
1468 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1470 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1471 int pathid = m_directoryPathIdHash.value(directory, -1);
1473 if (mainWin->m_rtRestore1Debug)
1474 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1475 /* With a checked directory, query for the files in the directory */
1478 "SELECT Filename.Name AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1480 " ( SELECT File.FilenameId AS FilenameId, MAX(Job.JobId) AS JobId"
1482 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1483 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1484 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1485 " GROUP BY File.FilenameId"
1487 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1488 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1489 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1490 " AND File.FilenameId=t1.FilenameId"
1491 " AND Job.Jobid=t1.JobId"
1492 " ORDER BY Filename";
1494 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1495 QStringList results;
1496 if (m_console->sql_cmd(cmd, results)) {
1497 QStringList fieldlist;
1500 /* Iterate through the record returned from the query */
1501 foreach (QString resultline, results) {
1502 /* Iterate through fields in the record */
1504 QString fullPath = "";
1505 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1506 fieldlist = resultline.split("\t");
1509 foreach (QString field, fieldlist) {
1511 fullPath = directory + field;
1514 version = field.toInt();
1517 fileIndex = field.toInt();
1521 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1523 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1524 if (fileExcpState != Qt::Unchecked) {
1526 if (excpVersion != 0) {
1527 debugtext = QString("*E* version=%1").arg(excpVersion);
1528 version = excpVersion;
1529 fileIndex = queryFileIndex(fullPath, excpVersion);
1531 debugtext = QString("___ version=%1").arg(version);
1532 if (mainWin->m_rtRestore1Debug)
1533 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1534 fullPathDone.insert(fullPath, 1);
1535 fileIndexHash.insert(fullPath, fileIndex);
1536 versionFilesMulti.insert(version, fullPath);
1544 prBar2->setValue(ditcount);
1546 } /* while (*diter) */
1547 prBar1->setValue(1);
1548 prLabel1->setText( tr("Task 2 of 3"));
1549 prLabel2->setText(tr("Processing Exceptions"));
1550 prBar2->setRange(0, 0);
1553 /* There may be some exceptions not accounted for yet with fullPathDone */
1554 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1555 while (ftera.hasNext()) {
1557 QString fullPath = ftera.key();
1558 Qt::CheckState state = ftera.value();
1560 /* now we don't want the ones already done */
1561 if (fullPathDone.value(fullPath, 0) == 0) {
1562 int version = m_versionExceptionHash.value(fullPath, 0);
1564 QString debugtext = "";
1566 fileIndex = queryFileIndex(fullPath, version);
1567 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1569 version = mostRecentVersionfromFullPath(fullPath);
1571 fileIndex = queryFileIndex(fullPath, version);
1572 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1574 debugtext = QString("Error det vers").arg(version);
1576 if (mainWin->m_rtRestore1Debug)
1577 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1578 versionFilesMulti.insert(version, fullPath);
1580 fileIndexHash.insert(fullPath, fileIndex);
1581 } /* if fullPathDone.value(fullPath, 0) == 0 */
1582 } /* if state != 0 */
1583 } /* while ftera.hasNext */
1584 /* The progress bars for the next step */
1585 prBar1->setValue(2);
1586 prLabel1->setText(tr("Task 3 of 3"));
1587 prLabel2->setText(tr("Filling Database Table"));
1588 prBar2->setRange(0, vFMCounter);
1590 prBar2->setValue(vFMCounter);
1593 /* now for the final spit out of the versions and lists of files for each version */
1594 QHash<int, int> doneKeys;
1595 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1596 QString tempTable = "";
1598 while (vFMiter.hasNext()) {
1600 int fversion = vFMiter.key();
1601 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1602 if (doneKeys.value(fversion, 0) == 0) {
1603 if (tempTable == "") {
1604 QSettings settings("www.bacula.org", "bat");
1605 settings.beginGroup("Restore");
1606 int counter = settings.value("Counter", 1).toInt();
1607 settings.setValue("Counter", counter+1);
1608 settings.endGroup();
1609 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1610 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1611 if (mainWin->m_sqlDebug)
1612 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1613 QStringList results;
1614 if (!m_console->sql_cmd(sqlcmd, results))
1615 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1618 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1619 QStringList fullPathList = versionFilesMulti.values(fversion);
1620 /* create the command to perform the restore */
1621 foreach(QString ffullPath, fullPathList) {
1622 int fileIndex = fileIndexHash.value(ffullPath);
1623 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1624 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1625 if (mainWin->m_rtRestore3Debug)
1626 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1627 QStringList results;
1628 if (!m_console->sql_cmd(sqlcmd, results))
1629 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1630 prBar2->setValue(++vFMCounter);
1631 } /* foreach fullPathList */
1632 doneKeys.insert(fversion,1);
1633 jobList.append(fversion);
1634 } /* if (doneKeys.value(fversion, 0) == 0) */
1635 } /* while (vFMiter.hasNext()) */
1636 if (tempTable != "") {
1637 /* a table was made, lets run the job */
1638 QString jobOption = " jobid=\"";
1640 /* create a list of jobs comma separated */
1641 foreach (int job, jobList) {
1642 if (first) first = false;
1643 else jobOption += ",";
1644 jobOption += QString("%1").arg(job);
1647 QString cmd = QString("restore");
1649 " client=\"" + m_prevClientCombo + "\"" +
1650 " file=\"?" + tempTable + "\" done";
1651 if (mainWin->m_commandDebug)
1652 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1653 consoleCommand(cmd);
1655 /* turn off the progress widgets */
1656 prBar1->setVisible(false);
1657 prBar2->setVisible(false);
1658 prLabel1->setVisible(false);
1659 prLabel2->setVisible(false);
1662 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1665 QString directory, fileName;
1666 int index = fullPath.lastIndexOf("/", -2);
1668 directory = fileName = fullPath;
1669 directory.replace(index+1, fullPath.length()-index-1, "");
1670 fileName.replace(0, index+1, "");
1672 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1673 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1674 Pmsg0(000, msg.toUtf8().data());
1676 int pathid = m_directoryPathIdHash.value(directory, -1);
1678 /* so now we need the latest version from the database */
1680 "SELECT MAX(Job.JobId)"
1682 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1683 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1684 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1685 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1686 " AND Filename.Name='" + fileName + "'"
1687 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1688 " GROUP BY Filename.Name";
1690 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1691 QStringList results;
1692 if (m_console->sql_cmd(cmd, results)) {
1693 QStringList fieldlist;
1695 /* Iterate through the record returned from the query */
1696 foreach (QString resultline, results) {
1697 /* Iterate through fields in the record */
1699 fieldlist = resultline.split("\t");
1700 foreach (QString field, fieldlist) {
1702 qversion = field.toInt();
1710 } /* if (index != -1) */
1715 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1718 QString directory, fileName;
1719 int index = fullPath.lastIndexOf("/", -2);
1720 if (mainWin->m_sqlDebug) Pmsg1(000, "Index=%d\n", index);
1722 directory = fileName = fullPath;
1723 directory.replace(index+1, fullPath.length()-index-1, "");
1724 fileName.replace(0, index+1, "");
1726 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1727 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1728 Pmsg0(000, msg.toUtf8().data());
1730 int pathid = m_directoryPathIdHash.value(directory, -1);
1732 /* so now we need the latest version from the database */
1737 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1738 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1739 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1740 " AND Filename.Name='" + fileName + "'"
1741 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1742 " GROUP BY File.FileIndex";
1743 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1744 QStringList results;
1745 if (m_console->sql_cmd(cmd, results)) {
1746 QStringList fieldlist;
1748 /* Iterate through the record returned from the query */
1749 foreach (QString resultline, results) {
1750 /* Iterate through fields in the record */
1752 fieldlist = resultline.split("\t");
1753 foreach (QString field, fieldlist) {
1755 qfileIndex = field.toInt();
1763 } /* if (index != -1) */
1764 if (mainWin->m_sqlDebug) Pmsg1(000, "qfileIndex=%d\n", qfileIndex);
1769 void restoreTree::PgSeltreeWidgetClicked()
1771 if (!isOnceDocked()) {