2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
34 * Kern Sibbald, February MMVII
39 #include "restoretree.h"
42 restoreTree::restoreTree()
45 m_name = "Version Browser";
47 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
55 m_winRegExpDrive.setPattern("^[a-z]:/$");
56 m_winRegExpPath.setPattern("^[a-z]:/");
57 m_slashregex.setPattern("/");
61 QGridLayout *m_gridLayout = new QGridLayout(this);
62 m_gridLayout->setSpacing(6);
63 m_gridLayout->setMargin(9);
64 m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
66 QSplitter *splitter_2 = new QSplitter(Qt::Vertical, this);
67 QScrollArea *area = new QScrollArea();
68 area->setObjectName(QString::fromUtf8("area"));
69 area->setWidget(widget);
70 area->setWidgetResizable(true);
71 splitter_2->addWidget(splitter);
72 splitter_2->addWidget(area);
74 m_gridLayout->addWidget(splitter_2, 0, 0, 1, 1);
76 /* progress widgets */
77 prBar1->setVisible(false);
78 prBar2->setVisible(false);
79 prLabel1->setVisible(false);
80 prLabel2->setVisible(false);
82 /* Set Defaults for check and spin for limits */
83 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
84 limitSpinBox->setValue(mainWin->m_recordLimitVal);
85 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
86 daysSpinBox->setValue(mainWin->m_daysLimitVal);
89 restoreTree::~restoreTree()
95 * Called from the constructor to set up the page widgets and connections.
97 void restoreTree::setupPage()
99 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
100 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
101 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
102 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
103 connect(clientCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
104 connect(fileSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
105 connect(limitCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
106 connect(daysCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
107 connect(daysSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
108 connect(limitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
109 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
110 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
111 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
112 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
113 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
114 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
115 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
116 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
117 connect(jobTable, SIGNAL(cellClicked(int, int)),
118 this, SLOT(jobTableCellClicked(int, int)));
120 QStringList titles = QStringList() << "Directories";
121 directoryTree->setHeaderLabels(titles);
122 clientCombo->addItems(m_console->client_list);
123 fileSetCombo->addItem("Any");
124 fileSetCombo->addItems(m_console->fileset_list);
125 jobCombo->addItem("Any");
126 jobCombo->addItems(m_console->job_list);
128 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
131 void restoreTree::updateRefresh()
133 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
134 m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
135 || (m_prevClientCombo != clientCombo->currentText())
136 || (m_prevFileSetCombo != fileSetCombo->currentText()
137 || (m_prevLimitSpinBox != limitSpinBox->value())
138 || (m_prevDaysSpinBox != daysSpinBox->value())
139 || (m_prevLimitCheckState != limitCheckBox->checkState())
140 || (m_prevDaysCheckState != daysCheckBox->checkState())
142 if (m_dropdownChanged) {
143 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
144 refreshLabel->setText("Refresh From Re-Select");
146 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
147 refreshLabel->setText("Refresh From JobChecks");
152 * When refresh button is pushed, perform a query getting the directories and
153 * use parseDirectory and addDirectory to populate the directory tree with items.
155 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 = 2, 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("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
180 prLabel1->setVisible(true);
181 prBar2->setVisible(true);
182 prBar2->setRange(0,0);
183 prLabel2->setText("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("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
199 prBar2->setRange(0,0);
200 prLabel2->setText("Querying Jobs");
203 setJobsCheckedList();
205 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
206 setJobsCheckedList();
209 if (m_checkedJobs != "") {
211 "SELECT DISTINCT Path.Path AS Path"
213 " INNER JOIN File ON (File.PathId=Path.PathId)"
214 " INNER JOIN Job ON (File.JobId=Job.JobId)"
215 " WHERE Job.Jobid IN (" + m_checkedJobs + ")"
217 if (mainWin->m_sqlDebug) {
218 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
220 prBar1->setValue(ontask++);
221 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
223 prLabel2->setText("Processing Directories");
224 QStringList directories;
225 if (m_console->sql_cmd(cmd, directories)) {
226 if (mainWin->m_miscDebug) {
227 Pmsg1(000, "Done with query %i directories\n", directories.count());
229 prBar2->setRange(0,directories.count());
231 foreach(QString directory, directories) {
233 prBar2->setValue(m_debugCnt);
234 parseDirectory(directory);
238 QMessageBox::warning(this, tr("Bat"),
239 tr("No jobs were selected in the job query !!!.\n"
240 "Press OK to continue?"),
243 prBar1->setVisible(false);
244 prBar2->setVisible(false);
245 prLabel1->setVisible(false);
246 prLabel2->setVisible(false);
250 * Function to set m_checkedJobs from the jobs that are checked in the table
253 void restoreTree::setJobsCheckedList()
255 m_JobsCheckedList = "";
257 /* Update the items in the version table */
258 int cnt = jobTable->rowCount();
259 for (int row=0; row<cnt; row++) {
260 QTableWidgetItem* jobItem = jobTable->item(row, 0);
261 if (jobItem->checkState() == Qt::Checked) {
263 m_JobsCheckedList += ",";
264 m_JobsCheckedList += jobItem->text();
266 jobItem->setBackground(Qt::green);
268 if (jobItem->flags())
269 jobItem->setBackground(Qt::gray);
271 jobItem->setBackground(Qt::darkYellow);
274 m_checkedJobs = m_JobsCheckedList;
278 * Function to parse a directory into all possible subdirectories, then add to
281 void restoreTree::parseDirectory(QString &dir_in)
283 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
284 * instead of printing out what could potentially a whole bunch */
287 /* Clean up the directory string remove some funny char after last '/' */
288 QRegExp rgx("[^/]$");
289 int lastslash = rgx.indexIn(dir_in);
290 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
291 if ((mainWin->m_miscDebug) && (m_debugTrap))
292 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
294 /* split and add if not in yet */
295 QString direct, path;
298 QStringList pathAfter, dirAfter;
299 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
300 * if not added into tree, then try /etc/ and somedir/ if not added, then try
301 * / and etc/ . That should succeed, then add the ones that failed in reverse */
302 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
303 direct = path = dir_in;
304 path.replace(index+1, dir_in.length()-index-1,"");
305 direct.replace(0, index+1, "");
306 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
307 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
308 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
309 Pmsg0(000, msg.toUtf8().data());
311 if (addDirectory(path, direct)) done = true;
313 if ((mainWin->m_miscDebug) && (m_debugTrap))
314 Pmsg0(000, "Saving for later\n");
315 pathAfter.prepend(path);
316 dirAfter.prepend(direct);
321 for (int k=0; k<pathAfter.count(); k++) {
322 if (addDirectory(pathAfter[k], dirAfter[k]))
323 if ((mainWin->m_miscDebug) && (m_debugTrap))
324 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
326 if ((mainWin->m_miscDebug) && (m_debugTrap))
327 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
332 * Function called from fill directory when a directory is found to see if this
333 * directory exists in the directory pane and then add it to the directory pane
335 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
337 QString newdir = newdirr;
338 QString fullPath = m_cwd + newdirr;
339 bool ok = true, added = false;
341 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
342 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
345 Pmsg0(000, msg.toUtf8().data());
349 /* add unix '/' directory first */
350 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
352 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
354 item->setText(0, text.toUtf8().data());
355 item->setData(0, Qt::UserRole, QVariant(text));
356 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
357 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
358 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
359 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
361 m_dirPaths.insert(text, item);
363 /* no need to check for windows drive if unix */
364 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
365 if (!m_dirPaths.contains(m_cwd)) {
366 /* this is a windows drive add the base widget */
367 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
368 item->setText(0, m_cwd);
369 item->setData(0, Qt::UserRole, QVariant(fullPath));
370 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
371 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
372 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
373 Pmsg0(000, "Added Base \"letter\":/\n");
375 m_dirPaths.insert(m_cwd, item);
380 /* is it already existent ?? */
381 if (!m_dirPaths.contains(fullPath)) {
382 QTreeWidgetItem *item = NULL;
383 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
385 /* new directories to add */
386 item = new QTreeWidgetItem(parent);
387 item->setText(0, newdir.toUtf8().data());
388 item->setData(0, Qt::UserRole, QVariant(fullPath));
389 item->setCheckState(0, Qt::Unchecked);
390 /* Store the current state of the check status in column 1, which at
391 * this point has no text*/
392 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
395 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
396 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
399 Pmsg0(000, msg.toUtf8().data());
402 /* insert into hash */
404 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
405 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
407 m_dirPaths.insert(fullPath, item);
415 * Virtual function which is called when this page is visible on the stack
417 void restoreTree::currentStackItem()
420 if (!m_console->preventInUseConnect())
428 * Populate the tree when refresh button pushed.
430 void restoreTree::refreshButtonPushed()
432 populateDirectoryTree();
436 * Set the values of non-job combo boxes to the job defaults
438 void restoreTree::jobComboChanged(int)
440 if (jobCombo->currentText() == "Any") {
441 fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
444 job_defaults job_defs;
447 job_defs.job_name = jobCombo->currentText();
448 if (m_console->get_job_defaults(job_defs)) {
449 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
450 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
455 * Function to populate the file list table
457 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
462 m_fileCheckStateList.clear();
463 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
464 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
465 QBrush blackBrush(Qt::black);
466 QString directory = item->data(0, Qt::UserRole).toString();
467 directoryLabel->setText("Present Working Directory : " + directory);
469 "SELECT DISTINCT Filename.Name AS FileName"
471 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
472 " INNER JOIN Path ON (Path.PathId=File.PathId)"
473 " INNER JOIN Job ON (File.JobId=Job.JobId)"
474 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
475 " AND Job.Jobid IN (" + m_checkedJobs + ")"
476 " ORDER BY FileName";
478 QStringList headerlist = (QStringList() << "File Name");
480 /* Also clear the version table here */
481 versionTable->clear();
482 versionFileLabel->setText("");
483 versionTable->setRowCount(0);
484 versionTable->setColumnCount(0);
485 fileTable->setColumnCount(headerlist.size());
486 fileTable->setHorizontalHeaderLabels(headerlist);
488 if (mainWin->m_sqlDebug) {
489 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
492 if (m_console->sql_cmd(cmd, results)) {
494 QTableWidgetItem* tableItem;
496 QStringList fieldlist;
497 fileTable->setRowCount(results.size());
500 /* Iterate through the record returned from the query */
501 foreach (QString resultline, results) {
502 /* Iterate through fields in the record */
504 fieldlist = resultline.split("\t");
505 foreach (field, fieldlist) {
506 field = field.trimmed(); /* strip leading & trailing spaces */
507 tableItem = new QTableWidgetItem(field, 1);
508 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
509 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
510 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
511 tableItem->setForeground(blackBrush);
512 /* Just in case a column ever gets added */
514 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
515 tableItem->setFlags(flag);
516 tableItem->setData(Qt::UserRole, QVariant(directory));
517 fileTable->setItem(row, column, tableItem);
518 m_fileCheckStateList.append(Qt::Unchecked);
519 tableItem->setCheckState(Qt::Unchecked);
525 fileTable->setRowCount(row);
527 fileTable->resizeColumnsToContents();
528 fileTable->resizeRowsToContents();
529 fileTable->verticalHeader()->hide();
530 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
531 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
532 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
533 updateFileTableChecks();
537 * Function to populate the version table
539 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
541 if (fileTableItem == NULL)
544 m_versionCheckStateList.clear();
545 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
546 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
548 QString file = fileTableItem->text();
549 versionFileLabel->setText(file);
550 QString directory = fileTableItem->data(Qt::UserRole).toString();
552 QBrush blackBrush(Qt::black);
554 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
556 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
557 " INNER JOIN Path ON (Path.PathId=File.PathId)"
558 " INNER JOIN Job ON (File.JobId=Job.JobId)"
559 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
560 " AND Job.Jobid IN (" + m_checkedJobs + ")"
561 " ORDER BY Job.EndTime DESC";
563 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
564 versionTable->clear();
565 versionTable->setColumnCount(headerlist.size());
566 versionTable->setHorizontalHeaderLabels(headerlist);
568 if (mainWin->m_sqlDebug) {
569 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
572 if (m_console->sql_cmd(cmd, results)) {
574 QTableWidgetItem* tableItem;
576 QStringList fieldlist;
577 versionTable->setRowCount(results.size());
580 /* Iterate through the record returned from the query */
581 foreach (QString resultline, results) {
582 fieldlist = resultline.split("\t");
584 /* remove directory */
585 if (fieldlist[0].trimmed() != "") {
586 /* Iterate through fields in the record */
587 foreach (field, fieldlist) {
588 field = field.trimmed(); /* strip leading & trailing spaces */
589 tableItem = new QTableWidgetItem(field, 1);
590 tableItem->setFlags(0);
591 tableItem->setForeground(blackBrush);
592 tableItem->setData(Qt::UserRole, QVariant(directory));
593 versionTable->setItem(row, column, tableItem);
596 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
597 tableItem->setFlags(flag);
598 m_versionCheckStateList.append(Qt::Unchecked);
599 tableItem->setCheckState(Qt::Unchecked);
607 versionTable->resizeColumnsToContents();
608 versionTable->resizeRowsToContents();
609 versionTable->verticalHeader()->hide();
610 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
611 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
612 updateVersionTableChecks();
616 * Save user settings associated with this page
618 void restoreTree::writeSettings()
620 QSettings settings(m_console->m_dir->name(), "bat");
621 settings.beginGroup("RestoreTree");
622 settings.setValue("splitterSizes", splitter->saveState());
627 * Read and restore user settings associated with this page
629 void restoreTree::readSettings()
631 QSettings settings(m_console->m_dir->name(), "bat");
632 settings.beginGroup("RestoreTree");
633 splitter->restoreState(settings.value("splitterSizes").toByteArray());
638 * This is a funcion to accomplish the one thing I struggled to figure out what
639 * was taking so long. It add the icons, but after the tree is made. Seemed to
640 * work fast after changing from png to png file for graphic.
642 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
644 int childCount = item->childCount();
645 for (int i=0; i<childCount; i++) {
646 QTreeWidgetItem *child = item->child(i);
647 if (child->icon(0).isNull())
648 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
653 * I wanted a table to show what jobs meet the criterion and are being used to
654 * populate the directory tree and file and version tables.
656 void restoreTree::populateJobTable()
658 QBrush blackBrush(Qt::black);
660 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
661 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Level" << "Name" << "Purged" << "TU" << "TD");
662 m_toggleUpIndex = headerlist.indexOf("TU");
663 m_toggleDownIndex = headerlist.indexOf("TD");
664 int purgedIndex = headerlist.indexOf("Purged");
666 jobTable->setColumnCount(headerlist.size());
667 jobTable->setHorizontalHeaderLabels(headerlist);
669 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level, Job.Name AS JobName, Job.purgedfiles AS Purged"
671 /* INNER JOIN FileSet eliminates all restore jobs */
672 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
673 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
675 " Client.Name='" + clientCombo->currentText() + "'";
676 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != "Any")) {
677 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
679 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != "Any")) {
680 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
682 /* If Limit check box For limit by days is checked */
683 if (daysCheckBox->checkState() == Qt::Checked) {
684 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
685 QString since = stamp.toString(Qt::ISODate);
686 jobQuery += " AND Job.Starttime>'" + since + "'";
688 //jobQuery += " AND Job.purgedfiles=0";
689 jobQuery += " ORDER BY Job.EndTime DESC";
690 /* If Limit check box for limit records returned is checked */
691 if (limitCheckBox->checkState() == Qt::Checked) {
693 limit.setNum(limitSpinBox->value());
694 jobQuery += " LIMIT " + limit;
696 if (mainWin->m_sqlDebug)
697 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
700 if (m_console->sql_cmd(jobQuery, results)) {
702 QTableWidgetItem* tableItem;
704 QStringList fieldlist;
705 jobTable->setRowCount(results.size());
708 /* Iterate through the record returned from the query */
709 foreach (QString resultline, results) {
710 fieldlist = resultline.split("\t");
712 /* remove directory */
713 if (fieldlist[0].trimmed() != "") {
714 /* Iterate through fields in the record */
715 foreach (field, fieldlist) {
716 field = field.trimmed(); /* strip leading & trailing spaces */
718 tableItem = new QTableWidgetItem(field, 1);
719 tableItem->setFlags(0);
720 tableItem->setForeground(blackBrush);
721 jobTable->setItem(row, column, tableItem);
724 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
725 if (!((ok) && (purged == 1))) {
726 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
727 tableItem->setFlags(flag);
728 tableItem->setCheckState(Qt::Checked);
729 tableItem->setBackground(Qt::green);
731 tableItem->setFlags(0);
732 tableItem->setCheckState(Qt::Unchecked);
738 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
739 tableItem->setFlags(0);
740 tableItem->setForeground(blackBrush);
741 jobTable->setItem(row, column, tableItem);
743 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
744 tableItem->setFlags(0);
745 tableItem->setForeground(blackBrush);
746 jobTable->setItem(row, column, tableItem);
751 jobTable->resizeColumnsToContents();
752 jobTable->resizeRowsToContents();
753 jobTable->verticalHeader()->hide();
754 jobTable->hideColumn(purgedIndex);
757 void restoreTree::jobTableCellClicked(int row, int column)
759 if (column == m_toggleUpIndex){
761 for (cnt=0; cnt<row+1; cnt++) {
762 QTableWidgetItem *item = jobTable->item(cnt, 0);
764 Qt::CheckState state = item->checkState();
765 if (state == Qt::Checked)
766 item->setCheckState(Qt::Unchecked);
767 else if (state == Qt::Unchecked)
768 item->setCheckState(Qt::Checked);
772 if (column == m_toggleDownIndex){
773 int cnt, max = jobTable->rowCount();
774 for (cnt=row; cnt<max; cnt++) {
775 QTableWidgetItem *item = jobTable->item(cnt, 0);
777 Qt::CheckState state = item->checkState();
778 if (state == Qt::Checked)
779 item->setCheckState(Qt::Unchecked);
780 else if (state == Qt::Unchecked)
781 item->setCheckState(Qt::Checked);
788 * When a directory item is "changed" check the state of the checkable item
789 * to see if it is different than what it was which is stored in Qt::UserRole
790 * of the 2nd column, column 1, of the tree widget.
792 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
794 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
795 Qt::CheckState curState = item->checkState(0);
796 QTreeWidgetItem* parent = item->parent();
797 Qt::CheckState parState;
798 if (parent) parState = parent->checkState(0);
799 else parState = (Qt::CheckState)3;
800 if (mainWin->m_rtDirICDebug) {
801 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
802 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
803 Pmsg1(000, "%s", msg.toUtf8().data()); }
804 /* I only care when the check state changes */
805 if (prevState == curState) {
806 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
810 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
811 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
812 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
813 curState = Qt::PartiallyChecked;
815 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
816 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
817 directoryTreeDisconnectedSet(item, Qt::Unchecked);
818 curState = Qt::Unchecked;
820 if (mainWin->m_rtDirICDebug) {
821 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
822 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
823 Pmsg1(000, "%s", msg.toUtf8().data()); }
825 item->setData(1, Qt::UserRole, QVariant(curState));
826 Qt::CheckState childState = curState;
827 if (childState == Qt::Checked)
828 childState = Qt::PartiallyChecked;
829 setCheckofChildren(item, childState);
831 /* Remove items from the exception lists. The multi exception list is my index
832 * of what exceptions can be removed when the directory is known*/
833 QString directory = item->data(0, Qt::UserRole).toString();
834 QStringList fullPathList = m_fileExceptionMulti.values(directory);
835 int fullPathListCount = fullPathList.count();
836 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
837 foreach (QString fullPath, fullPathList) {
838 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
839 * which will match no Qt::xxx values */
840 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
841 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
842 if (hashState == Qt::Unchecked) {
843 fileExceptionRemove(fullPath, directory);
844 m_versionExceptionHash.remove(fullPath);
845 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
847 if (hashState == Qt::Checked) {
848 fileExceptionRemove(fullPath, directory);
849 m_versionExceptionHash.remove(fullPath);
850 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
854 if (item == directoryTree->currentItem()) {
855 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
856 updateFileTableChecks();
857 versionTable->clear();
858 versionTable->setRowCount(0);
859 versionTable->setColumnCount(0);
861 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
865 * When a directory item check state is changed, this function iterates through
866 * all subdirectories and sets all to the passed state, which is either partially
867 * checked or unchecked.
869 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
872 childCount = item->childCount();
873 for (int i=0; i<childCount; i++) {
874 QTreeWidgetItem *child = item->child(i);
875 child->setData(1, Qt::UserRole, QVariant(state));
876 child->setCheckState(0, state);
877 setCheckofChildren(child, state);
882 * When a File Table Item is "changed" check to see if the state of the checkable
883 * item has changed which is stored in m_fileCheckStateList
884 * If changed store in a hash m_fileExceptionHash that whether this file should be
886 * Called as a slot, connected after populated (after directory current changed called)
888 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
890 /* get the previous and current check states */
891 int row = fileTable->row(item);
892 Qt::CheckState prevState;
893 /* prevent a segfault */
894 prevState = m_fileCheckStateList[row];
895 Qt::CheckState curState = item->checkState();
897 /* deterimine the default state from the state of the directory */
898 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
899 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
900 Qt::CheckState defState = Qt::PartiallyChecked;
901 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
903 /* determine if it is already in the m_fileExceptionHash */
904 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
905 QString file = item->text();
906 QString fullPath = directory + file;
907 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
908 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
910 if (mainWin->m_rtFileTabICDebug) {
911 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
912 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
913 Pmsg1(000, "%s", msg.toUtf8().data()); }
915 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
916 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
917 /* it can behave as defaulted so current of unchecked is fine */
918 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
919 fileExceptionRemove(fullPath, directory);
920 m_versionExceptionHash.remove(fullPath);
921 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
922 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
923 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
924 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
925 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
926 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
927 fileExceptionRemove(fullPath, directory);
928 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
929 /* Check dir, check version, attempt uncheck in file
930 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
931 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
932 fileExceptionRemove(fullPath, directory);
933 m_versionExceptionHash.remove(fullPath);
934 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
935 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
936 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
937 } else if (prevState != curState) {
938 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
939 /* A user did not set the check state to Partially checked, ignore if so */
940 if (curState != Qt::PartiallyChecked) {
941 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
942 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
944 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
945 fileExceptionInsert(fullPath, directory, curState);
948 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
949 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
950 m_versionExceptionHash.remove(fullPath);
954 updateFileTableChecks();
955 updateVersionTableChecks();
959 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
961 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
963 m_fileExceptionHash.insert(fullPath, state);
964 m_fileExceptionMulti.insert(direcotry, fullPath);
965 directoryIconStateInsert(fullPath, state);
969 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
971 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
973 m_fileExceptionHash.remove(fullPath);
974 /* pull the list of values in the multi */
975 QStringList fullPathList = m_fileExceptionMulti.values(directory);
976 /* get the index of the fullpath to remove */
977 int index = fullPathList.indexOf(fullPath);
979 /* remove the desired item in the list */
980 fullPathList.removeAt(index);
981 /* remove the entire list from the multi */
982 m_fileExceptionMulti.remove(directory);
983 /* readd the remaining */
984 foreach (QString fp, fullPathList) {
985 m_fileExceptionMulti.insert(directory, fp);
988 directoryIconStateRemove();
992 * Overloaded function to be called from the slot and from other places to set the state
993 * of the check marks in the version table
995 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
997 /* get the previous and current check states */
998 int row = versionTable->row(item);
999 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
1000 Qt::CheckState prevState = m_versionCheckStateList[row];
1001 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
1002 m_versionCheckStateList[row] = curState;
1004 /* deterimine the default state from the state of the file */
1005 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1006 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1008 /* determine the default state */
1009 Qt::CheckState defState;
1011 defState = Qt::PartiallyChecked;
1012 if (fileState == Qt::Unchecked)
1013 defState = Qt::Unchecked;
1016 defState = Qt::Unchecked;
1018 /* determine if it is already in the versionExceptionHash */
1019 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1020 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1021 QString file = fileTableItem->text();
1022 QString fullPath = directory + file;
1023 int thisJobNum = colZeroItem->text().toInt();
1024 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1026 if (mainWin->m_rtVerTabICDebug) {
1027 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1028 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1029 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1030 Pmsg1(000, "%s", msg.toUtf8().data()); }
1031 /* if changed from partially checked to checked, make it unchecked */
1032 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1033 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1034 fileTableItem->setCheckState(Qt::Checked);
1035 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1036 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1037 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1038 fileExceptionRemove(fullPath, directory);
1039 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1040 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1041 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1042 m_versionExceptionHash.remove(fullPath);
1043 fileExceptionRemove(fullPath, directory);
1044 } else if ((curState == Qt::Checked) && (row == 0)) {
1045 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1046 m_versionExceptionHash.remove(fullPath);
1047 } else if (prevState != curState) {
1048 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1049 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
1050 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1051 m_versionExceptionHash.insert(fullPath, thisJobNum);
1052 if (fileState != Qt::Checked) {
1053 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1054 fileExceptionInsert(fullPath, directory, curState);
1057 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1060 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1063 updateFileTableChecks();
1064 updateVersionTableChecks();
1068 * Simple function to set the check state in the file table by disconnecting the
1069 * signal/slot the setting then reconnecting the signal/slot
1071 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1073 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1074 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1075 item->setCheckState(state);
1076 if (color) item->setBackground(Qt::yellow);
1077 else item->setBackground(Qt::white);
1078 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1079 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1083 * Simple function to set the check state in the version table by disconnecting the
1084 * signal/slot the setting then reconnecting the signal/slot
1086 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1088 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1089 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1090 item->setCheckState(state);
1091 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1092 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1096 * Simple function to set the check state in the directory tree by disconnecting the
1097 * signal/slot the setting then reconnecting the signal/slot
1099 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1101 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1102 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1103 item->setCheckState(0, state);
1104 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1105 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1109 * Simplify the updating of the check state in the File table by iterating through
1110 * each item in the file table to determine it's appropriate state.
1111 * !! Will probably want to concoct a way to do this without iterating for the possibility
1112 * of the very large directories.
1114 void restoreTree::updateFileTableChecks()
1116 /* deterimine the default state from the state of the directory */
1117 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1118 Qt::CheckState dirState = dirTreeItem->checkState(0);
1120 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1122 /* Update the items in the version table */
1123 int rcnt = fileTable->rowCount();
1124 for (int row=0; row<rcnt; row++) {
1125 QTableWidgetItem* item = fileTable->item(row, 0);
1127 Qt::CheckState curState = item->checkState();
1128 Qt::CheckState newState = Qt::PartiallyChecked;
1129 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1131 /* determine if it is already in the m_fileExceptionHash */
1132 QString file = item->text();
1133 QString fullPath = dirName + file;
1134 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1135 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1137 if (hashState != 3) newState = hashState;
1139 if (mainWin->m_rtUpdateFTDebug) {
1140 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1141 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1142 Pmsg1(000, "%s", msg.toUtf8().data());
1145 bool docolor = false;
1146 if (hashJobNum != 0) docolor = true;
1147 bool isyellow = item->background().color() == QColor(Qt::yellow);
1148 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1149 fileTableDisconnectedSet(item, newState, docolor);
1150 m_fileCheckStateList[row] = newState;
1155 * Simplify the updating of the check state in the Version table by iterating through
1156 * each item in the file table to determine it's appropriate state.
1158 void restoreTree::updateVersionTableChecks()
1160 /* deterimine the default state from the state of the directory */
1161 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1162 Qt::CheckState dirState = dirTreeItem->checkState(0);
1163 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1165 /* deterimine the default state from the state of the file */
1166 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
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);
1177 Qt::CheckState curState = item->checkState();
1178 Qt::CheckState newState = Qt::Unchecked;
1180 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1181 newState = Qt::PartiallyChecked;
1182 /* determine if it is already in the versionExceptionHash */
1184 int thisJobNum = item->text().toInt();
1185 if (thisJobNum == hashJobNum)
1186 newState = Qt::Checked;
1188 if (mainWin->m_rtChecksDebug) {
1189 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1190 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1191 Pmsg1(000, "%s", msg.toUtf8().data());
1193 if (newState != curState)
1194 versionTableDisconnectedSet(item, newState);
1195 m_versionCheckStateList[row] = newState;
1200 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1202 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1206 QString fullPath = fullPath_in;
1207 QString direct, path;
1208 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1209 direct = path = fullPath;
1210 path.replace(index+1, fullPath.length()-index-1, "");
1211 direct.replace(0, index+1, "");
1213 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1214 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1215 Pmsg0(000, msg.toUtf8().data());
1218 subPaths.append(fullPath);
1223 * A Function to set the icon state and insert a record into
1224 * m_directoryIconStateHash when an exception is added by the user
1226 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1229 fullPathtoSubPaths(paths, fullPath);
1230 /* an exception that causes the item in the file table to be "Checked" has occured */
1231 if (excpState == Qt::Checked) {
1232 bool foundAsUnChecked = false;
1233 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1235 if (firstItem->checkState(0) == Qt::Unchecked)
1236 foundAsUnChecked = true;
1238 if (foundAsUnChecked) {
1239 /* as long as directory item is Unchecked, set icon state to "green check" */
1241 QListIterator<QString> siter(paths);
1242 while (siter.hasNext() && !done) {
1243 QString path = siter.next();
1244 QTreeWidgetItem *item = m_dirPaths.value(path);
1246 if (item->checkState(0) != Qt::Unchecked)
1249 directorySetIcon(1, FolderGreenChecked, path, item);
1250 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1255 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1256 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1258 QListIterator<QString> siter(paths);
1259 while (siter.hasNext() && !done) {
1260 QString path = siter.next();
1261 QTreeWidgetItem *item = m_dirPaths.value(path);
1262 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1263 if (item->checkState(0) == Qt::Checked)
1265 directorySetIcon(1, FolderGreenChecked, path, item);
1266 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1271 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1272 if (excpState == Qt::Unchecked) {
1274 QListIterator<QString> siter(paths);
1275 while (siter.hasNext() && !done) {
1276 QString path = siter.next();
1277 QTreeWidgetItem *item = m_dirPaths.value(path);
1278 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1279 if (item->checkState(0) == Qt::Checked)
1281 directorySetIcon(1, FolderWhiteChecked, path, item);
1282 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1289 * A function to set the icon state back to "folder" and to remove a record from
1290 * m_directoryIconStateHash when an exception is removed by a user.
1292 void restoreTree::directoryIconStateRemove()
1294 QHash<QString, int> shouldBeIconStateHash;
1295 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1296 /* Use iterator tera to iterate through m_fileExceptionHash */
1297 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1298 while (tera.hasNext()) {
1300 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1302 QString keyPath = tera.key();
1303 Qt::CheckState state = tera.value();
1306 fullPathtoSubPaths(paths, keyPath);
1307 /* if the state of the item in m_fileExceptionHash is checked
1308 * each of the subpaths should be "Checked Green" */
1309 if (state == Qt::Checked) {
1311 bool foundAsUnChecked = false;
1312 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1314 if (firstItem->checkState(0) == Qt::Unchecked)
1315 foundAsUnChecked = true;
1317 if (foundAsUnChecked) {
1318 /* The right most directory is Unchecked, iterate leftwards
1319 * as long as directory item is Unchecked, set icon state to "green check" */
1321 QListIterator<QString> siter(paths);
1322 while (siter.hasNext() && !done) {
1323 QString path = siter.next();
1324 QTreeWidgetItem *item = m_dirPaths.value(path);
1326 if (item->checkState(0) != Qt::Unchecked)
1329 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1330 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1336 /* The right most directory is Unchecked, iterate leftwards
1337 * until directory item is Checked, set icon state to "green check" */
1339 QListIterator<QString> siter(paths);
1340 while (siter.hasNext() && !done) {
1341 QString path = siter.next();
1342 QTreeWidgetItem *item = m_dirPaths.value(path);
1344 if (item->checkState(0) == Qt::Checked)
1346 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1351 /* if the state of the item in m_fileExceptionHash is UNChecked
1352 * each of the subpaths should be "Checked white" until the tree item
1353 * which represents that path is Qt::Checked */
1354 if (state == Qt::Unchecked) {
1356 QListIterator<QString> siter(paths);
1357 while (siter.hasNext() && !done) {
1358 QString path = siter.next();
1359 QTreeWidgetItem *item = m_dirPaths.value(path);
1361 if (item->checkState(0) == Qt::Checked)
1363 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1368 /* now iterate through m_directoryIconStateHash which are the items that are checked
1369 * and remove all of those that are not in shouldBeIconStateHash */
1370 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1371 while (iter.hasNext()) {
1373 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1375 QString keyPath = iter.key();
1376 if (shouldBeIconStateHash.value(keyPath)) {
1377 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1378 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1379 int newval = shouldBeIconStateHash.value(keyPath);
1381 newval = newval & FolderBothChecked;
1382 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1384 directorySetIcon(0, newval, keyPath, item);
1386 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1387 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1389 directorySetIcon(0, FolderBothChecked, keyPath, item);
1390 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1391 //m_directoryIconStateHash.remove(keyPath);
1396 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1398 /* we are adding a check type white or green */
1399 if (operation > 0) {
1400 /* get the old val and "bitwise OR" with the change */
1401 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1402 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1403 m_directoryIconStateHash.insert(path, newval);
1405 /* we are removing a check type white or green */
1406 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1408 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1409 m_directoryIconStateHash.remove(path);
1412 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1413 m_directoryIconStateHash.insert(path, newval);
1416 if (newval == FolderUnchecked)
1417 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1418 else if (newval == FolderGreenChecked)
1419 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1420 else if (newval == FolderWhiteChecked)
1421 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1422 else if (newval == FolderBothChecked)
1423 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1429 void restoreTree::restoreButtonPushed()
1431 /* Set progress bars and repaint */
1432 prLabel1->setVisible(true);
1433 prLabel1->setText("Task 1 of 3");
1434 prLabel2->setVisible(true);
1435 prLabel2->setText("Processing Checked directories");
1436 prBar1->setVisible(true);
1437 prBar1->setRange(0, 3);
1438 prBar1->setValue(0);
1439 prBar2->setVisible(true);
1440 prBar2->setRange(0, 0);
1442 QMultiHash<int, QString> versionFilesMulti;
1444 QHash <QString, bool> fullPathDone;
1445 QHash <QString, int> fileIndexHash;
1446 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1447 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1448 /* Use a tree widget item iterator to count directories for the progress bar */
1449 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1454 } /* while (*diterc) */
1455 prBar2->setRange(0, ditcount);
1456 prBar2->setValue(0);
1458 /* Use a tree widget item iterator filtering for Checked Items */
1459 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1461 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1462 if (mainWin->m_rtRestore1Debug)
1463 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1464 /* With a checked directory, query for the files in the directory */
1467 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1469 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1471 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1472 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1473 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1474 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1475 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1476 " GROUP BY Filename.Name"
1478 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1479 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1480 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1482 " Path.Path='" + directory + "'"
1483 " AND Filename.Name=t1.Filename"
1484 " AND Job.Jobid=t1.JobId"
1485 " ORDER BY Filename";
1487 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1488 QStringList results;
1489 if (m_console->sql_cmd(cmd, results)) {
1490 QStringList fieldlist;
1493 /* Iterate through the record returned from the query */
1494 foreach (QString resultline, results) {
1495 /* Iterate through fields in the record */
1497 QString fullPath = "";
1498 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1499 fieldlist = resultline.split("\t");
1502 foreach (QString field, fieldlist) {
1504 fullPath = directory + field;
1507 version = field.toInt();
1510 fileIndex = field.toInt();
1514 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1516 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1517 if (fileExcpState != Qt::Unchecked) {
1519 if (excpVersion != 0) {
1520 debugtext = QString("*E* version=%1").arg(excpVersion);
1521 version = excpVersion;
1522 fileIndex = queryFileIndex(fullPath, excpVersion);
1524 debugtext = QString("___ version=%1").arg(version);
1525 if (mainWin->m_rtRestore1Debug)
1526 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1527 fullPathDone.insert(fullPath, 1);
1528 fileIndexHash.insert(fullPath, fileIndex);
1529 versionFilesMulti.insert(version, fullPath);
1536 prBar2->setValue(ditcount);
1538 } /* while (*diter) */
1539 prBar1->setValue(1);
1540 prLabel1->setText("Task 2 of 3");
1541 prLabel2->setText("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("Task 3 of 3");
1579 prLabel2->setText("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 = m_slashregex.lastIndexIn(fullPath, -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 /* so now we need the latest version from the database */
1670 "SELECT MAX(Job.JobId)"
1672 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1673 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1674 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1675 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1676 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1677 " AND Filename.Name='" + fileName + "'"
1678 " GROUP BY Filename.Name";
1680 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1681 QStringList results;
1682 if (m_console->sql_cmd(cmd, results)) {
1683 QStringList fieldlist;
1685 /* Iterate through the record returned from the query */
1686 foreach (QString resultline, results) {
1687 /* Iterate through fields in the record */
1689 fieldlist = resultline.split("\t");
1690 foreach (QString field, fieldlist) {
1692 qversion = field.toInt();
1699 } /* if (index != -1) */
1704 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1707 QString directory, fileName;
1708 int index = m_slashregex.lastIndexIn(fullPath, -2);
1710 directory = fileName = fullPath;
1711 directory.replace(index+1, fullPath.length()-index-1, "");
1712 fileName.replace(0, index+1, "");
1714 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1715 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1716 Pmsg0(000, msg.toUtf8().data());
1718 /* so now we need the latest version from the database */
1723 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1724 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1725 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1727 " Path.Path='" + directory + "'"
1728 " AND Filename.Name='" + fileName + "'"
1729 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1730 " GROUP BY File.FileIndex";
1732 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1733 QStringList results;
1734 if (m_console->sql_cmd(cmd, results)) {
1735 QStringList fieldlist;
1737 /* Iterate through the record returned from the query */
1738 foreach (QString resultline, results) {
1739 /* Iterate through fields in the record */
1741 fieldlist = resultline.split("\t");
1742 foreach (QString field, fieldlist) {
1744 qfileIndex = field.toInt();
1751 } /* if (index != -1) */