2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
25 * Kern Sibbald, February MMVII
30 #include "restoretree.h"
33 restoreTree::restoreTree() : Pages()
36 m_name = tr("Version Browser");
38 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
39 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
46 QGridLayout *gridLayout = new QGridLayout(this);
47 gridLayout->setSpacing(6);
48 gridLayout->setMargin(9);
49 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
51 m_splitter = new QSplitter(Qt::Vertical, this);
52 QScrollArea *area = new QScrollArea();
53 area->setObjectName(QString::fromUtf8("area"));
54 area->setWidget(widget);
55 area->setWidgetResizable(true);
56 m_splitter->addWidget(area);
57 m_splitter->addWidget(splitter);
58 splitter->setChildrenCollapsible(false);
60 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
62 /* progress widgets */
63 prBar1->setVisible(false);
64 prBar2->setVisible(false);
65 prLabel1->setVisible(false);
66 prLabel2->setVisible(false);
68 /* Set Defaults for check and spin for limits */
69 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
70 limitSpinBox->setValue(mainWin->m_recordLimitVal);
71 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
72 daysSpinBox->setValue(mainWin->m_daysLimitVal);
74 m_nullFileNameId = -1;
79 restoreTree::~restoreTree()
85 * Called from the constructor to set up the page widgets and connections.
87 void restoreTree::setupPage()
89 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
90 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
91 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
92 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
93 connect(clientCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
94 connect(fileSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
95 connect(limitCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
96 connect(daysCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
97 connect(daysSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
98 connect(limitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
99 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
100 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
101 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
102 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
103 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
104 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
105 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
106 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
107 connect(jobTable, SIGNAL(cellClicked(int, int)),
108 this, SLOT(jobTableCellClicked(int, int)));
110 QStringList titles = QStringList() << tr("Directories");
111 directoryTree->setHeaderLabels(titles);
112 clientCombo->addItems(m_console->client_list);
113 fileSetCombo->addItem(tr("Any"));
114 fileSetCombo->addItems(m_console->fileset_list);
115 jobCombo->addItem(tr("Any"));
116 jobCombo->addItems(m_console->job_list);
118 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
121 void restoreTree::updateRefresh()
123 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
124 m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
125 || (m_prevClientCombo != clientCombo->currentText())
126 || (m_prevFileSetCombo != fileSetCombo->currentText()
127 || (m_prevLimitSpinBox != limitSpinBox->value())
128 || (m_prevDaysSpinBox != daysSpinBox->value())
129 || (m_prevLimitCheckState != limitCheckBox->checkState())
130 || (m_prevDaysCheckState != daysCheckBox->checkState())
132 if (m_dropdownChanged) {
133 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
134 refreshLabel->setText(tr("Refresh From Re-Select"));
136 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
137 refreshLabel->setText(tr("Refresh From JobChecks"));
142 * When refresh button is pushed, perform a query getting the directories and
143 * use parseDirectory and addDirectory to populate the directory tree with items.
145 void restoreTree::populateDirectoryTree()
151 directoryTree->clear();
153 fileTable->setRowCount(0);
154 fileTable->setColumnCount(0);
155 versionTable->clear();
156 versionTable->setRowCount(0);
157 versionTable->setColumnCount(0);
158 m_fileExceptionHash.clear();
159 m_fileExceptionMulti.clear();
160 m_versionExceptionHash.clear();
161 m_directoryIconStateHash.clear();
164 int taskcount = 3, ontask = 1;
165 if (m_dropdownChanged) taskcount += 1;
167 /* Set progress bars and repaint */
168 prBar1->setVisible(true);
169 prBar1->setRange(0,taskcount);
171 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
172 prLabel1->setVisible(true);
173 prBar2->setVisible(true);
174 prBar2->setRange(0,0);
175 prLabel2->setText(tr("Querying Database"));
176 prLabel2->setVisible(true);
179 if (m_dropdownChanged) {
180 m_prevJobCombo = jobCombo->currentText();
181 m_prevClientCombo = clientCombo->currentText();
182 m_prevFileSetCombo = fileSetCombo->currentText();
183 m_prevLimitSpinBox = limitSpinBox->value();
184 m_prevDaysSpinBox = daysSpinBox->value();
185 m_prevLimitCheckState = limitCheckBox->checkState();
186 m_prevDaysCheckState = daysCheckBox->checkState();
188 prBar1->setValue(ontask++);
189 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
191 prBar2->setRange(0,0);
192 prLabel2->setText(tr("Querying Jobs"));
196 setJobsCheckedList();
197 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
199 if (m_checkedJobs != "") {
200 /* First get the filenameid of where the nae is null. These will be the directories
201 * This could be done in a subquery but postgres's query analyzer won't do the right
202 * thing like I want */
203 if (m_nullFileNameId == -1) {
204 QString cmd = "SELECT FilenameId FROM Filename WHERE name=''";
205 if (mainWin->m_sqlDebug)
206 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
208 if (m_console->sql_cmd(cmd, qres)) {
210 QStringList fieldlist = qres[0].split("\t");
211 QString field = fieldlist[0];
213 int val = field.toInt(&ok, 10);
214 if (ok) m_nullFileNameId = val;
218 /* now create the query to get the list of paths */
220 "SELECT DISTINCT Path.Path AS Path, File.PathId AS PathId"
222 " INNER JOIN Path ON (File.PathId=Path.PathId)";
223 if (m_nullFileNameId != -1)
224 cmd += " WHERE File.FilenameId=" + QString("%1").arg(m_nullFileNameId);
226 cmd += " WHERE File.FilenameId IN (SELECT FilenameId FROM Filename WHERE Name='')";
227 cmd += " AND File.Jobid IN (" + m_checkedJobs + ")";
228 if (mainWin->m_sqlDebug)
229 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
230 prBar1->setValue(ontask++);
231 prLabel1->setText(tr("Task %1 of %2").arg(ontask).arg(taskcount));
233 prBar2->setRange(0,0);
234 prLabel2->setText(tr("Querying for Directories"));
237 m_directoryPathIdHash.clear();
238 bool querydone = false;
239 if (m_console->sql_cmd(cmd, results)) {
242 prLabel2->setText(tr("Processing Directories"));
243 prBar2->setRange(0,results.count());
246 if (mainWin->m_miscDebug)
247 Pmsg1(000, "Done with query %i results\n", results.count());
248 QStringList fieldlist;
249 foreach(const QString &resultline, results) {
250 /* Update progress bar periodically */
251 if ((++m_debugCnt && 0x3FF) == 0) {
252 prBar2->setValue(m_debugCnt);
254 fieldlist = resultline.split("\t");
256 /* Iterate through fields in the record */
257 foreach (const QString &field, fieldlist) {
258 if (fieldcnt == 0 ) {
259 parseDirectory(field);
260 } else if (fieldcnt == 1) {
262 int pathid = field.toInt(&ok, 10);
264 m_directoryPathIdHash.insert(fieldlist[0], pathid);
273 QMessageBox::warning(this, "Bat",
274 tr("No jobs were selected in the job query !!!.\n"
275 "Press OK to continue"),
278 prBar1->setVisible(false);
279 prBar2->setVisible(false);
280 prLabel1->setVisible(false);
281 prLabel2->setVisible(false);
285 * Function to set m_checkedJobs from the jobs that are checked in the table
288 void restoreTree::setJobsCheckedList()
290 m_JobsCheckedList = "";
292 /* Update the items in the version table */
293 int cnt = jobTable->rowCount();
294 for (int row=0; row<cnt; row++) {
295 QTableWidgetItem* jobItem = jobTable->item(row, 0);
296 if (jobItem->checkState() == Qt::Checked) {
298 m_JobsCheckedList += ",";
299 m_JobsCheckedList += jobItem->text();
301 jobItem->setBackground(Qt::green);
303 if (jobItem->flags())
304 jobItem->setBackground(Qt::gray);
306 jobItem->setBackground(Qt::darkYellow);
309 m_checkedJobs = m_JobsCheckedList;
313 * Function to parse a directory into all possible subdirectories, then add to
316 void restoreTree::parseDirectory(const QString &dir_in)
318 // bail out if already processed
319 if (m_dirPaths.contains(dir_in))
321 // search for parent...
322 int pos=dir_in.lastIndexOf("/",-2);
326 QString parent=dir_in.left(pos+1);
327 QString subdir=dir_in.mid(pos+1);
329 QTreeWidgetItem *item = NULL;
330 QTreeWidgetItem *parentItem = m_dirPaths.value(parent);
333 // recurse to build parent...
334 parseDirectory(parent);
335 parentItem = m_dirPaths.value(parent);
338 /* new directories to add */
339 item = new QTreeWidgetItem(parentItem);
340 item->setText(0, subdir);
341 item->setData(0, Qt::UserRole, QVariant(dir_in));
342 item->setCheckState(0, Qt::Unchecked);
343 /* Store the current state of the check status in column 1, which at
344 * this point has no text*/
345 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
346 m_dirPaths.insert(dir_in,item);
350 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
351 item->setText(0, dir_in);
352 item->setData(0, Qt::UserRole, QVariant(dir_in));
353 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
354 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
355 m_dirPaths.insert(dir_in,item);
360 * Virtual function which is called when this page is visible on the stack
362 void restoreTree::currentStackItem()
371 * Populate the tree when refresh button pushed.
373 void restoreTree::refreshButtonPushed()
375 populateDirectoryTree();
379 * Set the values of non-job combo boxes to the job defaults
381 void restoreTree::jobComboChanged(int)
383 if (jobCombo->currentText() == tr("Any")) {
384 fileSetCombo->setCurrentIndex(fileSetCombo->findText(tr("Any"), Qt::MatchExactly));
387 job_defaults job_defs;
390 job_defs.job_name = jobCombo->currentText();
391 if (m_console->get_job_defaults(job_defs)) {
392 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
393 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
398 * Function to populate the file list table
400 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
406 /* Also clear the version table here */
407 versionTable->clear();
408 versionFileLabel->setText("");
409 versionTable->setRowCount(0);
410 versionTable->setColumnCount(0);
412 QStringList headerlist = (QStringList() << tr("File Name") << tr("Filename Id"));
413 fileTable->setColumnCount(headerlist.size());
414 fileTable->setHorizontalHeaderLabels(headerlist);
415 fileTable->setRowCount(0);
417 m_fileCheckStateList.clear();
418 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
419 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
420 QBrush blackBrush(Qt::black);
421 QString directory = item->data(0, Qt::UserRole).toString();
422 directoryLabel->setText(tr("Present Working Directory: %1").arg(directory));
423 int pathid = m_directoryPathIdHash.value(directory, -1);
426 "SELECT DISTINCT Filename.Name AS FileName, Filename.FilenameId AS FilenameId"
428 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
429 " WHERE File.PathId=" + QString("%1").arg(pathid) +
430 " AND File.Jobid IN (" + m_checkedJobs + ")"
431 " AND Filename.Name!=''"
432 " ORDER BY FileName";
433 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
436 if (m_console->sql_cmd(cmd, results)) {
438 QTableWidgetItem* tableItem;
440 QStringList fieldlist;
441 fileTable->setRowCount(results.size());
444 /* Iterate through the record returned from the query */
445 foreach (QString resultline, results) {
446 /* Iterate through fields in the record */
448 fieldlist = resultline.split("\t");
449 foreach (field, fieldlist) {
450 field = field.trimmed(); /* strip leading & trailing spaces */
451 tableItem = new QTableWidgetItem(field, 1);
452 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
453 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
454 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
455 tableItem->setForeground(blackBrush);
456 /* Just in case a column ever gets added */
457 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
459 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
460 tableItem->setFlags(flag);
461 tableItem->setData(Qt::UserRole, QVariant(directory));
462 fileTable->setItem(row, column, tableItem);
463 m_fileCheckStateList.append(Qt::Unchecked);
464 tableItem->setCheckState(Qt::Unchecked);
465 } else if (column == 1) {
466 Qt::ItemFlags flag = Qt::ItemIsEnabled;
467 tableItem->setFlags(flag);
469 int filenameid = field.toInt(&ok, 10);
470 if (!ok) filenameid = -1;
471 tableItem->setData(Qt::UserRole, QVariant(filenameid));
472 fileTable->setItem(row, column, tableItem);
478 fileTable->setRowCount(row);
480 fileTable->resizeColumnsToContents();
481 fileTable->resizeRowsToContents();
482 fileTable->verticalHeader()->hide();
483 fileTable->hideColumn(1);
484 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
485 updateFileTableChecks();
486 } else if (mainWin->m_sqlDebug)
487 Pmsg1(000, "did not perform query, pathid=%i not found\n", pathid);
488 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
489 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
493 * Function to populate the version table
495 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *currentFileTableItem, QTableWidgetItem *)
497 if (currentFileTableItem == NULL)
500 int currentRow = fileTable->row(currentFileTableItem);
501 QTableWidgetItem *fileTableItem = fileTable->item(currentRow, 0);
502 QTableWidgetItem *fileNameIdTableItem = fileTable->item(currentRow, 1);
503 int fileNameId = fileNameIdTableItem->data(Qt::UserRole).toInt();
505 m_versionCheckStateList.clear();
506 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
507 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
509 QString file = fileTableItem->text();
510 versionFileLabel->setText(file);
511 QString directory = fileTableItem->data(Qt::UserRole).toString();
513 QBrush blackBrush(Qt::black);
515 QStringList headerlist = (QStringList()
516 << tr("Job Id") << tr("Type") << tr("End Time") << tr("Hash") << tr("FileId") << tr("Job Type") << tr("First Volume"));
517 versionTable->clear();
518 versionTable->setColumnCount(headerlist.size());
519 versionTable->setHorizontalHeaderLabels(headerlist);
520 versionTable->setRowCount(0);
522 int pathid = m_directoryPathIdHash.value(directory, -1);
523 if ((pathid != -1) && (fileNameId != -1)) {
525 "SELECT Job.JobId AS JobId, Job.Level AS Type,"
526 " Job.EndTime AS EndTime, File.MD5 AS MD5,"
527 " File.FileId AS FileId, Job.Type AS JobType,"
528 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume"
530 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
531 " INNER JOIN Path ON (Path.PathId=File.PathId)"
532 " INNER JOIN Job ON (File.JobId=Job.JobId)"
533 " WHERE Path.PathId=" + QString("%1").arg(pathid) +
534 //" AND Filename.Name='" + file + "'"
535 " AND Filename.FilenameId=" + QString("%1").arg(fileNameId) +
536 " AND Job.Jobid IN (" + m_checkedJobs + ")"
537 " ORDER BY Job.EndTime DESC";
539 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
541 if (m_console->sql_cmd(cmd, results)) {
543 QTableWidgetItem* tableItem;
545 QStringList fieldlist;
546 versionTable->setRowCount(results.size());
549 /* Iterate through the record returned from the query */
550 foreach (QString resultline, results) {
551 fieldlist = resultline.split("\t");
553 /* remove directory */
554 if (fieldlist[0].trimmed() != "") {
555 /* Iterate through fields in the record */
556 foreach (field, fieldlist) {
557 field = field.trimmed(); /* strip leading & trailing spaces */
559 QByteArray jtype(field.trimmed().toAscii());
561 field = job_type_to_str(jtype[0]);
564 tableItem = new QTableWidgetItem(field, 1);
565 tableItem->setFlags(0);
566 tableItem->setForeground(blackBrush);
567 tableItem->setData(Qt::UserRole, QVariant(directory));
568 versionTable->setItem(row, column, tableItem);
569 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
571 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
572 tableItem->setFlags(flag);
573 m_versionCheckStateList.append(Qt::Unchecked);
574 tableItem->setCheckState(Qt::Unchecked);
582 versionTable->resizeColumnsToContents();
583 versionTable->resizeRowsToContents();
584 versionTable->verticalHeader()->hide();
585 updateVersionTableChecks();
587 if (mainWin->m_sqlDebug)
588 Pmsg2(000, "not querying : pathid=%i fileNameId=%i\n", pathid, fileNameId);
590 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
591 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
595 * Save user settings associated with this page
597 void restoreTree::writeSettings()
599 QSettings settings(m_console->m_dir->name(), "bat");
600 settings.beginGroup(m_groupText);
601 settings.setValue(m_splitText1, m_splitter->saveState());
602 settings.setValue(m_splitText2, splitter->saveState());
607 * Read and restore user settings associated with this page
609 void restoreTree::readSettings()
611 m_groupText = tr("RestoreTreePage");
612 m_splitText1 = "splitterSizes1_3";
613 m_splitText2 = "splitterSizes2_3";
614 QSettings settings(m_console->m_dir->name(), "bat");
615 settings.beginGroup(m_groupText);
616 if (settings.contains(m_splitText1)) { m_splitter->restoreState(settings.value(m_splitText1).toByteArray()); }
617 if (settings.contains(m_splitText2)) { splitter->restoreState(settings.value(m_splitText2).toByteArray()); }
622 * This is a funcion to accomplish the one thing I struggled to figure out what
623 * was taking so long. It add the icons, but after the tree is made. Seemed to
624 * work fast after changing from png to png file for graphic.
626 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
628 int childCount = item->childCount();
629 for (int i=0; i<childCount; i++) {
630 QTreeWidgetItem *child = item->child(i);
631 if (child->icon(0).isNull())
632 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
637 * Show what jobs meet the criteria and are being used to
638 * populate the directory tree and file and version tables.
640 void restoreTree::populateJobTable()
642 QBrush blackBrush(Qt::black);
644 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
645 QStringList headerlist = (QStringList()
646 << tr("Job Id") << tr("End Time") << tr("Level") << tr("Type")
647 << tr("Name") << tr("Purged") << tr("TU") << tr("TD"));
648 m_toggleUpIndex = headerlist.indexOf(tr("TU"));
649 m_toggleDownIndex = headerlist.indexOf(tr("TD"));
650 int purgedIndex = headerlist.indexOf(tr("Purged"));
651 int typeIndex = headerlist.indexOf(tr("Type"));
653 jobTable->setColumnCount(headerlist.size());
654 jobTable->setHorizontalHeaderLabels(headerlist);
656 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime,"
657 " Job.Level AS Level, Job.Type AS Type,"
658 " Job.Name AS JobName, Job.purgedfiles AS Purged"
660 /* INNER JOIN FileSet eliminates all restore jobs */
661 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
662 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
664 " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
665 " Client.Name='" + clientCombo->currentText() + "'";
666 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != tr("Any"))) {
667 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
669 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != tr("Any"))) {
670 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
672 /* If Limit check box For limit by days is checked */
673 if (daysCheckBox->checkState() == Qt::Checked) {
674 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
675 QString since = stamp.toString(Qt::ISODate);
676 jobQuery += " AND Job.Starttime>'" + since + "'";
678 //jobQuery += " AND Job.purgedfiles=0";
679 jobQuery += " ORDER BY Job.EndTime DESC";
680 /* If Limit check box for limit records returned is checked */
681 if (limitCheckBox->checkState() == Qt::Checked) {
683 limit.setNum(limitSpinBox->value());
684 jobQuery += " LIMIT " + limit;
686 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
690 if (m_console->sql_cmd(jobQuery, results)) {
692 QTableWidgetItem* tableItem;
694 QStringList fieldlist;
695 jobTable->setRowCount(results.size());
698 /* Iterate through the record returned from the query */
699 foreach (QString resultline, results) {
700 fieldlist = resultline.split("\t");
702 /* remove directory */
703 if (fieldlist[0].trimmed() != "") {
704 /* Iterate through fields in the record */
705 foreach (field, fieldlist) {
706 field = field.trimmed(); /* strip leading & trailing spaces */
708 if (column == typeIndex) {
709 QByteArray jtype(field.trimmed().toAscii());
711 field = job_type_to_str(jtype[0]);
714 tableItem = new QTableWidgetItem(field, 1);
715 tableItem->setFlags(0);
716 tableItem->setForeground(blackBrush);
717 jobTable->setItem(row, column, tableItem);
718 if (mainWin->m_sqlDebug) Pmsg1(000, "Column=%d\n", column);
721 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
722 if (!((ok) && (purged == 1))) {
723 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
724 tableItem->setFlags(flag);
725 tableItem->setCheckState(Qt::Checked);
726 tableItem->setBackground(Qt::green);
728 tableItem->setFlags(0);
729 tableItem->setCheckState(Qt::Unchecked);
735 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
736 tableItem->setFlags(0);
737 tableItem->setForeground(blackBrush);
738 jobTable->setItem(row, column, tableItem);
740 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
741 tableItem->setFlags(0);
742 tableItem->setForeground(blackBrush);
743 jobTable->setItem(row, column, tableItem);
748 jobTable->resizeColumnsToContents();
749 jobTable->resizeRowsToContents();
750 jobTable->verticalHeader()->hide();
751 jobTable->hideColumn(purgedIndex);
754 void restoreTree::jobTableCellClicked(int row, int column)
756 if (column == m_toggleUpIndex){
758 for (cnt=0; cnt<row+1; cnt++) {
759 QTableWidgetItem *item = jobTable->item(cnt, 0);
761 Qt::CheckState state = item->checkState();
762 if (state == Qt::Checked)
763 item->setCheckState(Qt::Unchecked);
764 else if (state == Qt::Unchecked)
765 item->setCheckState(Qt::Checked);
769 if (column == m_toggleDownIndex){
770 int cnt, max = jobTable->rowCount();
771 for (cnt=row; cnt<max; cnt++) {
772 QTableWidgetItem *item = jobTable->item(cnt, 0);
774 Qt::CheckState state = item->checkState();
775 if (state == Qt::Checked)
776 item->setCheckState(Qt::Unchecked);
777 else if (state == Qt::Unchecked)
778 item->setCheckState(Qt::Checked);
785 * When a directory item is "changed" check the state of the checkable item
786 * to see if it is different than what it was which is stored in Qt::UserRole
787 * of the 2nd column, column 1, of the tree widget.
789 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
791 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
792 Qt::CheckState curState = item->checkState(0);
793 QTreeWidgetItem* parent = item->parent();
794 Qt::CheckState parState;
795 if (parent) parState = parent->checkState(0);
796 else parState = (Qt::CheckState)3;
797 if (mainWin->m_rtDirICDebug) {
798 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
799 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
800 Pmsg1(000, "%s", msg.toUtf8().data()); }
801 /* I only care when the check state changes */
802 if (prevState == curState) {
803 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
807 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
808 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
809 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
810 curState = Qt::PartiallyChecked;
812 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
813 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
814 directoryTreeDisconnectedSet(item, Qt::Unchecked);
815 curState = Qt::Unchecked;
817 if (mainWin->m_rtDirICDebug) {
818 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
819 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
820 Pmsg1(000, "%s", msg.toUtf8().data()); }
822 item->setData(1, Qt::UserRole, QVariant(curState));
823 Qt::CheckState childState = curState;
824 if (childState == Qt::Checked)
825 childState = Qt::PartiallyChecked;
826 setCheckofChildren(item, childState);
828 /* Remove items from the exception lists. The multi exception list is my index
829 * of what exceptions can be removed when the directory is known*/
830 QString directory = item->data(0, Qt::UserRole).toString();
831 QStringList fullPathList = m_fileExceptionMulti.values(directory);
832 int fullPathListCount = fullPathList.count();
833 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
834 foreach (QString fullPath, fullPathList) {
835 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
836 * which will match no Qt::xxx values */
837 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
838 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
839 if (hashState == Qt::Unchecked) {
840 fileExceptionRemove(fullPath, directory);
841 m_versionExceptionHash.remove(fullPath);
842 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
844 if (hashState == Qt::Checked) {
845 fileExceptionRemove(fullPath, directory);
846 m_versionExceptionHash.remove(fullPath);
847 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
851 if (item == directoryTree->currentItem()) {
852 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
853 updateFileTableChecks();
854 versionTable->clear();
855 versionTable->setRowCount(0);
856 versionTable->setColumnCount(0);
858 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
862 * When a directory item check state is changed, this function iterates through
863 * all subdirectories and sets all to the passed state, which is either partially
864 * checked or unchecked.
866 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
869 childCount = item->childCount();
870 for (int i=0; i<childCount; i++) {
871 QTreeWidgetItem *child = item->child(i);
872 child->setData(1, Qt::UserRole, QVariant(state));
873 child->setCheckState(0, state);
874 setCheckofChildren(child, state);
879 * When a File Table Item is "changed" check to see if the state of the checkable
880 * item has changed which is stored in m_fileCheckStateList
881 * If changed store in a hash m_fileExceptionHash that whether this file should be
883 * Called as a slot, connected after populated (after directory current changed called)
885 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
887 /* get the previous and current check states */
888 int row = fileTable->row(item);
889 Qt::CheckState prevState;
890 /* prevent a segfault */
891 prevState = m_fileCheckStateList[row];
892 Qt::CheckState curState = item->checkState();
894 /* deterimine the default state from the state of the directory */
895 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
896 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
897 Qt::CheckState defState = Qt::PartiallyChecked;
898 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
900 /* determine if it is already in the m_fileExceptionHash */
901 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
902 QString file = item->text();
903 QString fullPath = directory + file;
904 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
905 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
907 if (mainWin->m_rtFileTabICDebug) {
908 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
909 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
910 Pmsg1(000, "%s", msg.toUtf8().data()); }
912 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
913 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
914 /* it can behave as defaulted so current of unchecked is fine */
915 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
916 fileExceptionRemove(fullPath, directory);
917 m_versionExceptionHash.remove(fullPath);
918 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
919 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
920 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
921 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
922 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
923 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
924 fileExceptionRemove(fullPath, directory);
925 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
926 /* Check dir, check version, attempt uncheck in file
927 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
928 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
929 fileExceptionRemove(fullPath, directory);
930 m_versionExceptionHash.remove(fullPath);
931 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
932 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
933 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
934 } else if (prevState != curState) {
935 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
936 /* A user did not set the check state to Partially checked, ignore if so */
937 if (curState != Qt::PartiallyChecked) {
938 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
939 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
941 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
942 fileExceptionInsert(fullPath, directory, curState);
945 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
946 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
947 m_versionExceptionHash.remove(fullPath);
951 updateFileTableChecks();
952 updateVersionTableChecks();
956 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
958 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
960 m_fileExceptionHash.insert(fullPath, state);
961 m_fileExceptionMulti.insert(direcotry, fullPath);
962 directoryIconStateInsert(fullPath, state);
966 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
968 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
970 m_fileExceptionHash.remove(fullPath);
971 /* pull the list of values in the multi */
972 QStringList fullPathList = m_fileExceptionMulti.values(directory);
973 /* get the index of the fullpath to remove */
974 int index = fullPathList.indexOf(fullPath);
976 /* remove the desired item in the list */
977 fullPathList.removeAt(index);
978 /* remove the entire list from the multi */
979 m_fileExceptionMulti.remove(directory);
980 /* readd the remaining */
981 foreach (QString fp, fullPathList) {
982 m_fileExceptionMulti.insert(directory, fp);
985 directoryIconStateRemove();
989 * Overloaded function to be called from the slot and from other places to set the state
990 * of the check marks in the version table
992 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
994 /* get the previous and current check states */
995 int row = versionTable->row(item);
996 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
997 Qt::CheckState prevState = m_versionCheckStateList[row];
998 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
999 m_versionCheckStateList[row] = curState;
1001 /* deterimine the default state from the state of the file */
1002 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1003 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1005 /* determine the default state */
1006 Qt::CheckState defState;
1007 if (mainWin->m_sqlDebug) Pmsg1(000, "row=%d\n", row);
1009 defState = Qt::PartiallyChecked;
1010 if (fileState == Qt::Unchecked)
1011 defState = Qt::Unchecked;
1013 defState = Qt::Unchecked;
1016 /* determine if it is already in the versionExceptionHash */
1017 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1018 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1019 QString file = fileTableItem->text();
1020 QString fullPath = directory + file;
1021 int thisJobNum = colZeroItem->text().toInt();
1022 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1024 if (mainWin->m_rtVerTabICDebug) {
1025 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1026 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1027 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1028 Pmsg1(000, "%s", msg.toUtf8().data()); }
1029 /* if changed from partially checked to checked, make it unchecked */
1030 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1031 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1032 fileTableItem->setCheckState(Qt::Checked);
1033 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1034 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1035 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1036 fileExceptionRemove(fullPath, directory);
1037 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1038 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1039 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1040 m_versionExceptionHash.remove(fullPath);
1041 fileExceptionRemove(fullPath, directory);
1042 } else if ((curState == Qt::Checked) && (row == 0)) {
1043 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1044 m_versionExceptionHash.remove(fullPath);
1045 } else if (prevState != curState) {
1046 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1047 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked)) {
1048 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1049 m_versionExceptionHash.insert(fullPath, thisJobNum);
1050 if (fileState != Qt::Checked) {
1051 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1052 fileExceptionInsert(fullPath, directory, curState);
1055 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1058 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1061 updateFileTableChecks();
1062 updateVersionTableChecks();
1066 * Simple function to set the check state in the file table by disconnecting the
1067 * signal/slot the setting then reconnecting the signal/slot
1069 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1071 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1072 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1073 item->setCheckState(state);
1074 if (color) item->setBackground(Qt::yellow);
1075 else item->setBackground(Qt::white);
1076 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1077 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1081 * Simple function to set the check state in the version table by disconnecting the
1082 * signal/slot the setting then reconnecting the signal/slot
1084 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1086 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1087 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1088 item->setCheckState(state);
1089 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1090 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1094 * Simple function to set the check state in the directory tree by disconnecting the
1095 * signal/slot the setting then reconnecting the signal/slot
1097 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1099 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1100 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1101 item->setCheckState(0, state);
1102 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1103 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1107 * Simplify the updating of the check state in the File table by iterating through
1108 * each item in the file table to determine it's appropriate state.
1109 * !! Will probably want to concoct a way to do this without iterating for the possibility
1110 * of the very large directories.
1112 void restoreTree::updateFileTableChecks()
1114 /* deterimine the default state from the state of the directory */
1115 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1116 Qt::CheckState dirState = dirTreeItem->checkState(0);
1118 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1120 /* Update the items in the version table */
1121 int rcnt = fileTable->rowCount();
1122 for (int row=0; row<rcnt; row++) {
1123 QTableWidgetItem* item = fileTable->item(row, 0);
1124 if (!item) { return; }
1126 Qt::CheckState curState = item->checkState();
1127 Qt::CheckState newState = Qt::PartiallyChecked;
1128 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1130 /* determine if it is already in the m_fileExceptionHash */
1131 QString file = item->text();
1132 QString fullPath = dirName + file;
1133 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1134 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1136 if (hashState != 3) newState = hashState;
1138 if (mainWin->m_rtUpdateFTDebug) {
1139 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1140 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1141 Pmsg1(000, "%s", msg.toUtf8().data());
1144 bool docolor = false;
1145 if (hashJobNum != 0) docolor = true;
1146 bool isyellow = item->background().color() == QColor(Qt::yellow);
1147 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1148 fileTableDisconnectedSet(item, newState, docolor);
1149 m_fileCheckStateList[row] = newState;
1154 * Simplify the updating of the check state in the Version table by iterating through
1155 * each item in the file table to determine it's appropriate state.
1157 void restoreTree::updateVersionTableChecks()
1159 /* deterimine the default state from the state of the directory */
1160 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1161 Qt::CheckState dirState = dirTreeItem->checkState(0);
1162 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1164 /* deterimine the default state from the state of the file */
1165 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1166 if (!fileTableItem) { return; }
1167 Qt::CheckState fileState = fileTableItem->checkState();
1168 QString file = fileTableItem->text();
1169 QString fullPath = dirName + file;
1170 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1172 /* Update the items in the version table */
1173 int cnt = versionTable->rowCount();
1174 for (int row=0; row<cnt; row++) {
1175 QTableWidgetItem* item = versionTable->item(row, 0);
1176 if (!item) { break; }
1178 Qt::CheckState curState = item->checkState();
1179 Qt::CheckState newState = Qt::Unchecked;
1181 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1182 newState = Qt::PartiallyChecked;
1183 /* determine if it is already in the versionExceptionHash */
1185 int thisJobNum = item->text().toInt();
1186 if (thisJobNum == hashJobNum)
1187 newState = Qt::Checked;
1189 if (mainWin->m_rtChecksDebug) {
1190 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1191 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1192 Pmsg1(000, "%s", msg.toUtf8().data());
1194 if (newState != curState)
1195 versionTableDisconnectedSet(item, newState);
1196 m_versionCheckStateList[row] = newState;
1201 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1203 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1207 QString fullPath = fullPath_in;
1208 QString direct, path;
1209 while (((index = fullPath.lastIndexOf("/", -2)) != -1) && (!done)) {
1210 direct = path = fullPath;
1211 path.replace(index+1, fullPath.length()-index-1, "");
1212 direct.replace(0, index+1, "");
1214 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1215 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1216 Pmsg0(000, msg.toUtf8().data());
1219 subPaths.append(fullPath);
1224 * A Function to set the icon state and insert a record into
1225 * m_directoryIconStateHash when an exception is added by the user
1227 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1230 fullPathtoSubPaths(paths, fullPath);
1231 /* an exception that causes the item in the file table to be "Checked" has occured */
1232 if (excpState == Qt::Checked) {
1233 bool foundAsUnChecked = false;
1234 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1236 if (firstItem->checkState(0) == Qt::Unchecked)
1237 foundAsUnChecked = true;
1239 if (foundAsUnChecked) {
1240 /* as long as directory item is Unchecked, set icon state to "green check" */
1242 QListIterator<QString> siter(paths);
1243 while (siter.hasNext() && !done) {
1244 QString path = siter.next();
1245 QTreeWidgetItem *item = m_dirPaths.value(path);
1247 if (item->checkState(0) != Qt::Unchecked)
1250 directorySetIcon(1, FolderGreenChecked, path, item);
1251 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1256 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1257 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1259 QListIterator<QString> siter(paths);
1260 while (siter.hasNext() && !done) {
1261 QString path = siter.next();
1262 QTreeWidgetItem *item = m_dirPaths.value(path);
1263 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1264 if (item->checkState(0) == Qt::Checked)
1266 directorySetIcon(1, FolderGreenChecked, path, item);
1267 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1272 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1273 if (excpState == Qt::Unchecked) {
1275 QListIterator<QString> siter(paths);
1276 while (siter.hasNext() && !done) {
1277 QString path = siter.next();
1278 QTreeWidgetItem *item = m_dirPaths.value(path);
1279 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1280 if (item->checkState(0) == Qt::Checked)
1282 directorySetIcon(1, FolderWhiteChecked, path, item);
1283 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1290 * A function to set the icon state back to "folder" and to remove a record from
1291 * m_directoryIconStateHash when an exception is removed by a user.
1293 void restoreTree::directoryIconStateRemove()
1295 QHash<QString, int> shouldBeIconStateHash;
1296 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1297 /* Use iterator tera to iterate through m_fileExceptionHash */
1298 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1299 while (tera.hasNext()) {
1301 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1303 QString keyPath = tera.key();
1304 Qt::CheckState state = tera.value();
1307 fullPathtoSubPaths(paths, keyPath);
1308 /* if the state of the item in m_fileExceptionHash is checked
1309 * each of the subpaths should be "Checked Green" */
1310 if (state == Qt::Checked) {
1312 bool foundAsUnChecked = false;
1313 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1315 if (firstItem->checkState(0) == Qt::Unchecked)
1316 foundAsUnChecked = true;
1318 if (foundAsUnChecked) {
1319 /* The right most directory is Unchecked, iterate leftwards
1320 * as long as directory item is Unchecked, set icon state to "green check" */
1322 QListIterator<QString> siter(paths);
1323 while (siter.hasNext() && !done) {
1324 QString path = siter.next();
1325 QTreeWidgetItem *item = m_dirPaths.value(path);
1327 if (item->checkState(0) != Qt::Unchecked)
1330 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1331 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1337 /* The right most directory is Unchecked, iterate leftwards
1338 * until directory item is Checked, set icon state to "green check" */
1340 QListIterator<QString> siter(paths);
1341 while (siter.hasNext() && !done) {
1342 QString path = siter.next();
1343 QTreeWidgetItem *item = m_dirPaths.value(path);
1345 if (item->checkState(0) == Qt::Checked)
1347 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1352 /* if the state of the item in m_fileExceptionHash is UNChecked
1353 * each of the subpaths should be "Checked white" until the tree item
1354 * which represents that path is Qt::Checked */
1355 if (state == Qt::Unchecked) {
1357 QListIterator<QString> siter(paths);
1358 while (siter.hasNext() && !done) {
1359 QString path = siter.next();
1360 QTreeWidgetItem *item = m_dirPaths.value(path);
1362 if (item->checkState(0) == Qt::Checked)
1364 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1369 /* now iterate through m_directoryIconStateHash which are the items that are checked
1370 * and remove all of those that are not in shouldBeIconStateHash */
1371 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1372 while (iter.hasNext()) {
1374 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1376 QString keyPath = iter.key();
1377 if (shouldBeIconStateHash.value(keyPath)) {
1378 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1379 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1380 int newval = shouldBeIconStateHash.value(keyPath);
1382 newval = newval & FolderBothChecked;
1383 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1385 directorySetIcon(0, newval, keyPath, item);
1387 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1388 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1390 directorySetIcon(0, FolderBothChecked, keyPath, item);
1391 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1392 //m_directoryIconStateHash.remove(keyPath);
1397 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1399 /* we are adding a check type white or green */
1400 if (operation > 0) {
1401 /* get the old val and "bitwise OR" with the change */
1402 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1403 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1404 m_directoryIconStateHash.insert(path, newval);
1406 /* we are removing a check type white or green */
1407 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1409 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1410 m_directoryIconStateHash.remove(path);
1413 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1414 m_directoryIconStateHash.insert(path, newval);
1417 if (newval == FolderUnchecked)
1418 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1419 else if (newval == FolderGreenChecked)
1420 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1421 else if (newval == FolderWhiteChecked)
1422 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1423 else if (newval == FolderBothChecked)
1424 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1430 void restoreTree::restoreButtonPushed()
1432 /* Set progress bars and repaint */
1433 prLabel1->setVisible(true);
1434 prLabel1->setText(tr("Task 1 of 3"));
1435 prLabel2->setVisible(true);
1436 prLabel2->setText(tr("Processing Checked directories"));
1437 prBar1->setVisible(true);
1438 prBar1->setRange(0, 3);
1439 prBar1->setValue(0);
1440 prBar2->setVisible(true);
1441 prBar2->setRange(0, 0);
1443 QMultiHash<int, QString> versionFilesMulti;
1445 QHash <QString, bool> fullPathDone;
1446 QHash <QString, int> fileIndexHash;
1447 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1448 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1449 /* Use a tree widget item iterator to count directories for the progress bar */
1450 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1455 } /* while (*diterc) */
1456 prBar2->setRange(0, ditcount);
1457 prBar2->setValue(0);
1459 /* Use a tree widget item iterator filtering for Checked Items */
1460 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1462 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1463 int pathid = m_directoryPathIdHash.value(directory, -1);
1465 if (mainWin->m_rtRestore1Debug)
1466 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1467 /* With a checked directory, query for the files in the directory */
1470 "SELECT Filename.Name AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1472 " ( SELECT File.FilenameId AS FilenameId, MAX(Job.JobId) AS JobId"
1474 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1475 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1476 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1477 " GROUP BY File.FilenameId"
1479 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1480 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1481 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1482 " AND File.FilenameId=t1.FilenameId"
1483 " AND Job.Jobid=t1.JobId"
1484 " ORDER BY Filename";
1486 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1487 QStringList results;
1488 if (m_console->sql_cmd(cmd, results)) {
1489 QStringList fieldlist;
1492 /* Iterate through the record returned from the query */
1493 foreach (QString resultline, results) {
1494 /* Iterate through fields in the record */
1496 QString fullPath = "";
1497 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1498 fieldlist = resultline.split("\t");
1501 foreach (QString field, fieldlist) {
1503 fullPath = directory + field;
1506 version = field.toInt();
1509 fileIndex = field.toInt();
1513 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1515 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1516 if (fileExcpState != Qt::Unchecked) {
1518 if (excpVersion != 0) {
1519 debugtext = QString("*E* version=%1").arg(excpVersion);
1520 version = excpVersion;
1521 fileIndex = queryFileIndex(fullPath, excpVersion);
1523 debugtext = QString("___ version=%1").arg(version);
1524 if (mainWin->m_rtRestore1Debug)
1525 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1526 fullPathDone.insert(fullPath, 1);
1527 fileIndexHash.insert(fullPath, fileIndex);
1528 versionFilesMulti.insert(version, fullPath);
1536 prBar2->setValue(ditcount);
1538 } /* while (*diter) */
1539 prBar1->setValue(1);
1540 prLabel1->setText( tr("Task 2 of 3"));
1541 prLabel2->setText(tr("Processing Exceptions"));
1542 prBar2->setRange(0, 0);
1545 /* There may be some exceptions not accounted for yet with fullPathDone */
1546 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1547 while (ftera.hasNext()) {
1549 QString fullPath = ftera.key();
1550 Qt::CheckState state = ftera.value();
1552 /* now we don't want the ones already done */
1553 if (fullPathDone.value(fullPath, 0) == 0) {
1554 int version = m_versionExceptionHash.value(fullPath, 0);
1556 QString debugtext = "";
1558 fileIndex = queryFileIndex(fullPath, version);
1559 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1561 version = mostRecentVersionfromFullPath(fullPath);
1563 fileIndex = queryFileIndex(fullPath, version);
1564 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1566 debugtext = QString("Error det vers").arg(version);
1568 if (mainWin->m_rtRestore1Debug)
1569 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1570 versionFilesMulti.insert(version, fullPath);
1572 fileIndexHash.insert(fullPath, fileIndex);
1573 } /* if fullPathDone.value(fullPath, 0) == 0 */
1574 } /* if state != 0 */
1575 } /* while ftera.hasNext */
1576 /* The progress bars for the next step */
1577 prBar1->setValue(2);
1578 prLabel1->setText(tr("Task 3 of 3"));
1579 prLabel2->setText(tr("Filling Database Table"));
1580 prBar2->setRange(0, vFMCounter);
1582 prBar2->setValue(vFMCounter);
1585 /* now for the final spit out of the versions and lists of files for each version */
1586 QHash<int, int> doneKeys;
1587 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1588 QString tempTable = "";
1590 while (vFMiter.hasNext()) {
1592 int fversion = vFMiter.key();
1593 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1594 if (doneKeys.value(fversion, 0) == 0) {
1595 if (tempTable == "") {
1596 QSettings settings("www.bacula.org", "bat");
1597 settings.beginGroup("Restore");
1598 int counter = settings.value("Counter", 1).toInt();
1599 settings.setValue("Counter", counter+1);
1600 settings.endGroup();
1601 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1602 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1603 if (mainWin->m_sqlDebug)
1604 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1605 QStringList results;
1606 if (!m_console->sql_cmd(sqlcmd, results))
1607 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1610 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1611 QStringList fullPathList = versionFilesMulti.values(fversion);
1612 /* create the command to perform the restore */
1613 foreach(QString ffullPath, fullPathList) {
1614 int fileIndex = fileIndexHash.value(ffullPath);
1615 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1616 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1617 if (mainWin->m_rtRestore3Debug)
1618 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1619 QStringList results;
1620 if (!m_console->sql_cmd(sqlcmd, results))
1621 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1622 prBar2->setValue(++vFMCounter);
1623 } /* foreach fullPathList */
1624 doneKeys.insert(fversion,1);
1625 jobList.append(fversion);
1626 } /* if (doneKeys.value(fversion, 0) == 0) */
1627 } /* while (vFMiter.hasNext()) */
1628 if (tempTable != "") {
1629 /* a table was made, lets run the job */
1630 QString jobOption = " jobid=\"";
1632 /* create a list of jobs comma separated */
1633 foreach (int job, jobList) {
1634 if (first) first = false;
1635 else jobOption += ",";
1636 jobOption += QString("%1").arg(job);
1639 QString cmd = QString("restore");
1641 " client=\"" + m_prevClientCombo + "\"" +
1642 " file=\"?" + tempTable + "\" done";
1643 if (mainWin->m_commandDebug)
1644 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1645 consoleCommand(cmd);
1647 /* turn off the progress widgets */
1648 prBar1->setVisible(false);
1649 prBar2->setVisible(false);
1650 prLabel1->setVisible(false);
1651 prLabel2->setVisible(false);
1654 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1657 QString directory, fileName;
1658 int index = fullPath.lastIndexOf("/", -2);
1660 directory = fileName = fullPath;
1661 directory.replace(index+1, fullPath.length()-index-1, "");
1662 fileName.replace(0, index+1, "");
1664 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1665 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1666 Pmsg0(000, msg.toUtf8().data());
1668 int pathid = m_directoryPathIdHash.value(directory, -1);
1670 /* so now we need the latest version from the database */
1672 "SELECT MAX(Job.JobId)"
1674 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1675 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1676 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1677 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1678 " AND Filename.Name='" + fileName + "'"
1679 " AND File.FilenameId!=" + QString("%1").arg(m_nullFileNameId) +
1680 " GROUP BY Filename.Name";
1682 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1683 QStringList results;
1684 if (m_console->sql_cmd(cmd, results)) {
1685 QStringList fieldlist;
1687 /* Iterate through the record returned from the query */
1688 foreach (QString resultline, results) {
1689 /* Iterate through fields in the record */
1691 fieldlist = resultline.split("\t");
1692 foreach (QString field, fieldlist) {
1694 qversion = field.toInt();
1702 } /* if (index != -1) */
1707 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1710 QString directory, fileName;
1711 int index = fullPath.lastIndexOf("/", -2);
1712 if (mainWin->m_sqlDebug) Pmsg1(000, "Index=%d\n", index);
1714 directory = fileName = fullPath;
1715 directory.replace(index+1, fullPath.length()-index-1, "");
1716 fileName.replace(0, index+1, "");
1718 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1719 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1720 Pmsg0(000, msg.toUtf8().data());
1722 int pathid = m_directoryPathIdHash.value(directory, -1);
1724 /* so now we need the latest version from the database */
1729 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1730 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1731 " WHERE File.PathId=" + QString("%1").arg(pathid) +
1732 " AND Filename.Name='" + fileName + "'"
1733 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1734 " GROUP BY File.FileIndex";
1735 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1736 QStringList results;
1737 if (m_console->sql_cmd(cmd, results)) {
1738 QStringList fieldlist;
1740 /* Iterate through the record returned from the query */
1741 foreach (QString resultline, results) {
1742 /* Iterate through fields in the record */
1744 fieldlist = resultline.split("\t");
1745 foreach (QString field, fieldlist) {
1747 qfileIndex = field.toInt();
1755 } /* if (index != -1) */
1756 if (mainWin->m_sqlDebug) Pmsg1(000, "qfileIndex=%d\n", qfileIndex);
1761 void restoreTree::PgSeltreeWidgetClicked()
1763 if (!isOnceDocked()) {