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")));
54 m_winRegExpDrive.setPattern("^[a-z]:/$");
55 m_winRegExpPath.setPattern("^[a-z]:/");
56 m_slashregex.setPattern("/");
60 QGridLayout *gridLayout = new QGridLayout(this);
61 gridLayout->setSpacing(6);
62 gridLayout->setMargin(9);
63 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
65 m_splitter = new QSplitter(Qt::Vertical, this);
66 QScrollArea *area = new QScrollArea();
67 area->setObjectName(QString::fromUtf8("area"));
68 area->setWidget(widget);
69 area->setWidgetResizable(true);
70 m_splitter->addWidget(splitter);
71 m_splitter->addWidget(area);
73 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
75 /* progress widgets */
76 prBar1->setVisible(false);
77 prBar2->setVisible(false);
78 prLabel1->setVisible(false);
79 prLabel2->setVisible(false);
81 /* Set Defaults for check and spin for limits */
82 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
83 limitSpinBox->setValue(mainWin->m_recordLimitVal);
84 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
85 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(m_groupText);
622 settings.setValue(m_splitText, m_splitter->saveState());
627 * Read and restore user settings associated with this page
629 void restoreTree::readSettings()
631 m_groupText = "RestoreTreePage";
632 m_splitText = "splitterSizes_1";
633 QSettings settings(m_console->m_dir->name(), "bat");
634 settings.beginGroup(m_groupText);
635 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
640 * This is a funcion to accomplish the one thing I struggled to figure out what
641 * was taking so long. It add the icons, but after the tree is made. Seemed to
642 * work fast after changing from png to png file for graphic.
644 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
646 int childCount = item->childCount();
647 for (int i=0; i<childCount; i++) {
648 QTreeWidgetItem *child = item->child(i);
649 if (child->icon(0).isNull())
650 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
655 * I wanted a table to show what jobs meet the criterion and are being used to
656 * populate the directory tree and file and version tables.
658 void restoreTree::populateJobTable()
660 QBrush blackBrush(Qt::black);
662 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
663 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Level" << "Name" << "Purged" << "TU" << "TD");
664 m_toggleUpIndex = headerlist.indexOf("TU");
665 m_toggleDownIndex = headerlist.indexOf("TD");
666 int purgedIndex = headerlist.indexOf("Purged");
668 jobTable->setColumnCount(headerlist.size());
669 jobTable->setHorizontalHeaderLabels(headerlist);
671 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level, Job.Name AS JobName, Job.purgedfiles AS Purged"
673 /* INNER JOIN FileSet eliminates all restore jobs */
674 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
675 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
677 " Client.Name='" + clientCombo->currentText() + "'";
678 if ((jobCombo->currentIndex() >= 0) && (jobCombo->currentText() != "Any")) {
679 jobQuery += " AND Job.name = '" + jobCombo->currentText() + "'";
681 if ((fileSetCombo->currentIndex() >= 0) && (fileSetCombo->currentText() != "Any")) {
682 jobQuery += " AND FileSet.FileSet='" + fileSetCombo->currentText() + "'";
684 /* If Limit check box For limit by days is checked */
685 if (daysCheckBox->checkState() == Qt::Checked) {
686 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
687 QString since = stamp.toString(Qt::ISODate);
688 jobQuery += " AND Job.Starttime>'" + since + "'";
690 //jobQuery += " AND Job.purgedfiles=0";
691 jobQuery += " ORDER BY Job.EndTime DESC";
692 /* If Limit check box for limit records returned is checked */
693 if (limitCheckBox->checkState() == Qt::Checked) {
695 limit.setNum(limitSpinBox->value());
696 jobQuery += " LIMIT " + limit;
698 if (mainWin->m_sqlDebug)
699 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
702 if (m_console->sql_cmd(jobQuery, results)) {
704 QTableWidgetItem* tableItem;
706 QStringList fieldlist;
707 jobTable->setRowCount(results.size());
710 /* Iterate through the record returned from the query */
711 foreach (QString resultline, results) {
712 fieldlist = resultline.split("\t");
714 /* remove directory */
715 if (fieldlist[0].trimmed() != "") {
716 /* Iterate through fields in the record */
717 foreach (field, fieldlist) {
718 field = field.trimmed(); /* strip leading & trailing spaces */
720 tableItem = new QTableWidgetItem(field, 1);
721 tableItem->setFlags(0);
722 tableItem->setForeground(blackBrush);
723 jobTable->setItem(row, column, tableItem);
726 int purged = fieldlist[purgedIndex].toInt(&ok, 10);
727 if (!((ok) && (purged == 1))) {
728 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
729 tableItem->setFlags(flag);
730 tableItem->setCheckState(Qt::Checked);
731 tableItem->setBackground(Qt::green);
733 tableItem->setFlags(0);
734 tableItem->setCheckState(Qt::Unchecked);
740 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-up.png")), "", 1);
741 tableItem->setFlags(0);
742 tableItem->setForeground(blackBrush);
743 jobTable->setItem(row, column, tableItem);
745 tableItem = new QTableWidgetItem(QIcon(QString::fromUtf8(":images/go-down.png")), "", 1);
746 tableItem->setFlags(0);
747 tableItem->setForeground(blackBrush);
748 jobTable->setItem(row, column, tableItem);
753 jobTable->resizeColumnsToContents();
754 jobTable->resizeRowsToContents();
755 jobTable->verticalHeader()->hide();
756 jobTable->hideColumn(purgedIndex);
759 void restoreTree::jobTableCellClicked(int row, int column)
761 if (column == m_toggleUpIndex){
763 for (cnt=0; cnt<row+1; cnt++) {
764 QTableWidgetItem *item = jobTable->item(cnt, 0);
766 Qt::CheckState state = item->checkState();
767 if (state == Qt::Checked)
768 item->setCheckState(Qt::Unchecked);
769 else if (state == Qt::Unchecked)
770 item->setCheckState(Qt::Checked);
774 if (column == m_toggleDownIndex){
775 int cnt, max = jobTable->rowCount();
776 for (cnt=row; cnt<max; cnt++) {
777 QTableWidgetItem *item = jobTable->item(cnt, 0);
779 Qt::CheckState state = item->checkState();
780 if (state == Qt::Checked)
781 item->setCheckState(Qt::Unchecked);
782 else if (state == Qt::Unchecked)
783 item->setCheckState(Qt::Checked);
790 * When a directory item is "changed" check the state of the checkable item
791 * to see if it is different than what it was which is stored in Qt::UserRole
792 * of the 2nd column, column 1, of the tree widget.
794 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
796 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
797 Qt::CheckState curState = item->checkState(0);
798 QTreeWidgetItem* parent = item->parent();
799 Qt::CheckState parState;
800 if (parent) parState = parent->checkState(0);
801 else parState = (Qt::CheckState)3;
802 if (mainWin->m_rtDirICDebug) {
803 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
804 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
805 Pmsg1(000, "%s", msg.toUtf8().data()); }
806 /* I only care when the check state changes */
807 if (prevState == curState) {
808 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
812 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
813 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
814 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
815 curState = Qt::PartiallyChecked;
817 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
818 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
819 directoryTreeDisconnectedSet(item, Qt::Unchecked);
820 curState = Qt::Unchecked;
822 if (mainWin->m_rtDirICDebug) {
823 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
824 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
825 Pmsg1(000, "%s", msg.toUtf8().data()); }
827 item->setData(1, Qt::UserRole, QVariant(curState));
828 Qt::CheckState childState = curState;
829 if (childState == Qt::Checked)
830 childState = Qt::PartiallyChecked;
831 setCheckofChildren(item, childState);
833 /* Remove items from the exception lists. The multi exception list is my index
834 * of what exceptions can be removed when the directory is known*/
835 QString directory = item->data(0, Qt::UserRole).toString();
836 QStringList fullPathList = m_fileExceptionMulti.values(directory);
837 int fullPathListCount = fullPathList.count();
838 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
839 foreach (QString fullPath, fullPathList) {
840 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
841 * which will match no Qt::xxx values */
842 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
843 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
844 if (hashState == Qt::Unchecked) {
845 fileExceptionRemove(fullPath, directory);
846 m_versionExceptionHash.remove(fullPath);
847 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
849 if (hashState == Qt::Checked) {
850 fileExceptionRemove(fullPath, directory);
851 m_versionExceptionHash.remove(fullPath);
852 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
856 if (item == directoryTree->currentItem()) {
857 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
858 updateFileTableChecks();
859 versionTable->clear();
860 versionTable->setRowCount(0);
861 versionTable->setColumnCount(0);
863 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
867 * When a directory item check state is changed, this function iterates through
868 * all subdirectories and sets all to the passed state, which is either partially
869 * checked or unchecked.
871 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
874 childCount = item->childCount();
875 for (int i=0; i<childCount; i++) {
876 QTreeWidgetItem *child = item->child(i);
877 child->setData(1, Qt::UserRole, QVariant(state));
878 child->setCheckState(0, state);
879 setCheckofChildren(child, state);
884 * When a File Table Item is "changed" check to see if the state of the checkable
885 * item has changed which is stored in m_fileCheckStateList
886 * If changed store in a hash m_fileExceptionHash that whether this file should be
888 * Called as a slot, connected after populated (after directory current changed called)
890 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
892 /* get the previous and current check states */
893 int row = fileTable->row(item);
894 Qt::CheckState prevState;
895 /* prevent a segfault */
896 prevState = m_fileCheckStateList[row];
897 Qt::CheckState curState = item->checkState();
899 /* deterimine the default state from the state of the directory */
900 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
901 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
902 Qt::CheckState defState = Qt::PartiallyChecked;
903 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
905 /* determine if it is already in the m_fileExceptionHash */
906 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
907 QString file = item->text();
908 QString fullPath = directory + file;
909 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
910 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
912 if (mainWin->m_rtFileTabICDebug) {
913 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
914 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
915 Pmsg1(000, "%s", msg.toUtf8().data()); }
917 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
918 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
919 /* it can behave as defaulted so current of unchecked is fine */
920 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
921 fileExceptionRemove(fullPath, directory);
922 m_versionExceptionHash.remove(fullPath);
923 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
924 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
925 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
926 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
927 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
928 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
929 fileExceptionRemove(fullPath, directory);
930 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
931 /* Check dir, check version, attempt uncheck in file
932 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
933 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
934 fileExceptionRemove(fullPath, directory);
935 m_versionExceptionHash.remove(fullPath);
936 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
937 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
938 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
939 } else if (prevState != curState) {
940 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
941 /* A user did not set the check state to Partially checked, ignore if so */
942 if (curState != Qt::PartiallyChecked) {
943 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
944 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
946 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
947 fileExceptionInsert(fullPath, directory, curState);
950 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
951 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
952 m_versionExceptionHash.remove(fullPath);
956 updateFileTableChecks();
957 updateVersionTableChecks();
961 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
963 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
965 m_fileExceptionHash.insert(fullPath, state);
966 m_fileExceptionMulti.insert(direcotry, fullPath);
967 directoryIconStateInsert(fullPath, state);
971 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
973 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
975 m_fileExceptionHash.remove(fullPath);
976 /* pull the list of values in the multi */
977 QStringList fullPathList = m_fileExceptionMulti.values(directory);
978 /* get the index of the fullpath to remove */
979 int index = fullPathList.indexOf(fullPath);
981 /* remove the desired item in the list */
982 fullPathList.removeAt(index);
983 /* remove the entire list from the multi */
984 m_fileExceptionMulti.remove(directory);
985 /* readd the remaining */
986 foreach (QString fp, fullPathList) {
987 m_fileExceptionMulti.insert(directory, fp);
990 directoryIconStateRemove();
994 * Overloaded function to be called from the slot and from other places to set the state
995 * of the check marks in the version table
997 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
999 /* get the previous and current check states */
1000 int row = versionTable->row(item);
1001 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
1002 Qt::CheckState prevState = m_versionCheckStateList[row];
1003 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
1004 m_versionCheckStateList[row] = curState;
1006 /* deterimine the default state from the state of the file */
1007 QTableWidgetItem *fileTableItem = fileTable->currentItem();
1008 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
1010 /* determine the default state */
1011 Qt::CheckState defState;
1013 defState = Qt::PartiallyChecked;
1014 if (fileState == Qt::Unchecked)
1015 defState = Qt::Unchecked;
1018 defState = Qt::Unchecked;
1020 /* determine if it is already in the versionExceptionHash */
1021 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
1022 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
1023 QString file = fileTableItem->text();
1024 QString fullPath = directory + file;
1025 int thisJobNum = colZeroItem->text().toInt();
1026 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1028 if (mainWin->m_rtVerTabICDebug) {
1029 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
1030 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
1031 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
1032 Pmsg1(000, "%s", msg.toUtf8().data()); }
1033 /* if changed from partially checked to checked, make it unchecked */
1034 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
1035 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
1036 fileTableItem->setCheckState(Qt::Checked);
1037 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
1038 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
1039 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
1040 fileExceptionRemove(fullPath, directory);
1041 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
1042 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
1043 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1044 m_versionExceptionHash.remove(fullPath);
1045 fileExceptionRemove(fullPath, directory);
1046 } else if ((curState == Qt::Checked) && (row == 0)) {
1047 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
1048 m_versionExceptionHash.remove(fullPath);
1049 } else if (prevState != curState) {
1050 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
1051 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
1052 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1053 m_versionExceptionHash.insert(fullPath, thisJobNum);
1054 if (fileState != Qt::Checked) {
1055 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1056 fileExceptionInsert(fullPath, directory, curState);
1059 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1062 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1065 updateFileTableChecks();
1066 updateVersionTableChecks();
1070 * Simple function to set the check state in the file table by disconnecting the
1071 * signal/slot the setting then reconnecting the signal/slot
1073 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1075 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1076 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1077 item->setCheckState(state);
1078 if (color) item->setBackground(Qt::yellow);
1079 else item->setBackground(Qt::white);
1080 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1081 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1085 * Simple function to set the check state in the version table by disconnecting the
1086 * signal/slot the setting then reconnecting the signal/slot
1088 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1090 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1091 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1092 item->setCheckState(state);
1093 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1094 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1098 * Simple function to set the check state in the directory tree by disconnecting the
1099 * signal/slot the setting then reconnecting the signal/slot
1101 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1103 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1104 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1105 item->setCheckState(0, state);
1106 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1107 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1111 * Simplify the updating of the check state in the File table by iterating through
1112 * each item in the file table to determine it's appropriate state.
1113 * !! Will probably want to concoct a way to do this without iterating for the possibility
1114 * of the very large directories.
1116 void restoreTree::updateFileTableChecks()
1118 /* deterimine the default state from the state of the directory */
1119 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1120 Qt::CheckState dirState = dirTreeItem->checkState(0);
1122 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1124 /* Update the items in the version table */
1125 int rcnt = fileTable->rowCount();
1126 for (int row=0; row<rcnt; row++) {
1127 QTableWidgetItem* item = fileTable->item(row, 0);
1129 Qt::CheckState curState = item->checkState();
1130 Qt::CheckState newState = Qt::PartiallyChecked;
1131 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1133 /* determine if it is already in the m_fileExceptionHash */
1134 QString file = item->text();
1135 QString fullPath = dirName + file;
1136 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1137 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1139 if (hashState != 3) newState = hashState;
1141 if (mainWin->m_rtUpdateFTDebug) {
1142 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1143 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1144 Pmsg1(000, "%s", msg.toUtf8().data());
1147 bool docolor = false;
1148 if (hashJobNum != 0) docolor = true;
1149 bool isyellow = item->background().color() == QColor(Qt::yellow);
1150 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1151 fileTableDisconnectedSet(item, newState, docolor);
1152 m_fileCheckStateList[row] = newState;
1157 * Simplify the updating of the check state in the Version table by iterating through
1158 * each item in the file table to determine it's appropriate state.
1160 void restoreTree::updateVersionTableChecks()
1162 /* deterimine the default state from the state of the directory */
1163 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1164 Qt::CheckState dirState = dirTreeItem->checkState(0);
1165 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1167 /* deterimine the default state from the state of the file */
1168 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1169 Qt::CheckState fileState = fileTableItem->checkState();
1170 QString file = fileTableItem->text();
1171 QString fullPath = dirName + file;
1172 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1174 /* Update the items in the version table */
1175 int cnt = versionTable->rowCount();
1176 for (int row=0; row<cnt; row++) {
1177 QTableWidgetItem* item = versionTable->item(row, 0);
1179 Qt::CheckState curState = item->checkState();
1180 Qt::CheckState newState = Qt::Unchecked;
1182 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1183 newState = Qt::PartiallyChecked;
1184 /* determine if it is already in the versionExceptionHash */
1186 int thisJobNum = item->text().toInt();
1187 if (thisJobNum == hashJobNum)
1188 newState = Qt::Checked;
1190 if (mainWin->m_rtChecksDebug) {
1191 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1192 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1193 Pmsg1(000, "%s", msg.toUtf8().data());
1195 if (newState != curState)
1196 versionTableDisconnectedSet(item, newState);
1197 m_versionCheckStateList[row] = newState;
1202 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1204 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1208 QString fullPath = fullPath_in;
1209 QString direct, path;
1210 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1211 direct = path = fullPath;
1212 path.replace(index+1, fullPath.length()-index-1, "");
1213 direct.replace(0, index+1, "");
1215 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1216 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1217 Pmsg0(000, msg.toUtf8().data());
1220 subPaths.append(fullPath);
1225 * A Function to set the icon state and insert a record into
1226 * m_directoryIconStateHash when an exception is added by the user
1228 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1231 fullPathtoSubPaths(paths, fullPath);
1232 /* an exception that causes the item in the file table to be "Checked" has occured */
1233 if (excpState == Qt::Checked) {
1234 bool foundAsUnChecked = false;
1235 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1237 if (firstItem->checkState(0) == Qt::Unchecked)
1238 foundAsUnChecked = true;
1240 if (foundAsUnChecked) {
1241 /* as long as directory item is Unchecked, set icon state to "green check" */
1243 QListIterator<QString> siter(paths);
1244 while (siter.hasNext() && !done) {
1245 QString path = siter.next();
1246 QTreeWidgetItem *item = m_dirPaths.value(path);
1248 if (item->checkState(0) != Qt::Unchecked)
1251 directorySetIcon(1, FolderGreenChecked, path, item);
1252 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1257 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1258 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1260 QListIterator<QString> siter(paths);
1261 while (siter.hasNext() && !done) {
1262 QString path = siter.next();
1263 QTreeWidgetItem *item = m_dirPaths.value(path);
1264 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1265 if (item->checkState(0) == Qt::Checked)
1267 directorySetIcon(1, FolderGreenChecked, path, item);
1268 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1273 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1274 if (excpState == Qt::Unchecked) {
1276 QListIterator<QString> siter(paths);
1277 while (siter.hasNext() && !done) {
1278 QString path = siter.next();
1279 QTreeWidgetItem *item = m_dirPaths.value(path);
1280 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1281 if (item->checkState(0) == Qt::Checked)
1283 directorySetIcon(1, FolderWhiteChecked, path, item);
1284 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1291 * A function to set the icon state back to "folder" and to remove a record from
1292 * m_directoryIconStateHash when an exception is removed by a user.
1294 void restoreTree::directoryIconStateRemove()
1296 QHash<QString, int> shouldBeIconStateHash;
1297 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1298 /* Use iterator tera to iterate through m_fileExceptionHash */
1299 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1300 while (tera.hasNext()) {
1302 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1304 QString keyPath = tera.key();
1305 Qt::CheckState state = tera.value();
1308 fullPathtoSubPaths(paths, keyPath);
1309 /* if the state of the item in m_fileExceptionHash is checked
1310 * each of the subpaths should be "Checked Green" */
1311 if (state == Qt::Checked) {
1313 bool foundAsUnChecked = false;
1314 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1316 if (firstItem->checkState(0) == Qt::Unchecked)
1317 foundAsUnChecked = true;
1319 if (foundAsUnChecked) {
1320 /* The right most directory is Unchecked, iterate leftwards
1321 * as long as directory item is Unchecked, set icon state to "green check" */
1323 QListIterator<QString> siter(paths);
1324 while (siter.hasNext() && !done) {
1325 QString path = siter.next();
1326 QTreeWidgetItem *item = m_dirPaths.value(path);
1328 if (item->checkState(0) != Qt::Unchecked)
1331 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1332 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1338 /* The right most directory is Unchecked, iterate leftwards
1339 * until directory item is Checked, set icon state to "green check" */
1341 QListIterator<QString> siter(paths);
1342 while (siter.hasNext() && !done) {
1343 QString path = siter.next();
1344 QTreeWidgetItem *item = m_dirPaths.value(path);
1346 if (item->checkState(0) == Qt::Checked)
1348 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1353 /* if the state of the item in m_fileExceptionHash is UNChecked
1354 * each of the subpaths should be "Checked white" until the tree item
1355 * which represents that path is Qt::Checked */
1356 if (state == Qt::Unchecked) {
1358 QListIterator<QString> siter(paths);
1359 while (siter.hasNext() && !done) {
1360 QString path = siter.next();
1361 QTreeWidgetItem *item = m_dirPaths.value(path);
1363 if (item->checkState(0) == Qt::Checked)
1365 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1370 /* now iterate through m_directoryIconStateHash which are the items that are checked
1371 * and remove all of those that are not in shouldBeIconStateHash */
1372 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1373 while (iter.hasNext()) {
1375 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1377 QString keyPath = iter.key();
1378 if (shouldBeIconStateHash.value(keyPath)) {
1379 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1380 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1381 int newval = shouldBeIconStateHash.value(keyPath);
1383 newval = newval & FolderBothChecked;
1384 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1386 directorySetIcon(0, newval, keyPath, item);
1388 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1389 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1391 directorySetIcon(0, FolderBothChecked, keyPath, item);
1392 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1393 //m_directoryIconStateHash.remove(keyPath);
1398 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1400 /* we are adding a check type white or green */
1401 if (operation > 0) {
1402 /* get the old val and "bitwise OR" with the change */
1403 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1404 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1405 m_directoryIconStateHash.insert(path, newval);
1407 /* we are removing a check type white or green */
1408 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1410 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1411 m_directoryIconStateHash.remove(path);
1414 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1415 m_directoryIconStateHash.insert(path, newval);
1418 if (newval == FolderUnchecked)
1419 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1420 else if (newval == FolderGreenChecked)
1421 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1422 else if (newval == FolderWhiteChecked)
1423 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1424 else if (newval == FolderBothChecked)
1425 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1431 void restoreTree::restoreButtonPushed()
1433 /* Set progress bars and repaint */
1434 prLabel1->setVisible(true);
1435 prLabel1->setText("Task 1 of 3");
1436 prLabel2->setVisible(true);
1437 prLabel2->setText("Processing Checked directories");
1438 prBar1->setVisible(true);
1439 prBar1->setRange(0, 3);
1440 prBar1->setValue(0);
1441 prBar2->setVisible(true);
1442 prBar2->setRange(0, 0);
1444 QMultiHash<int, QString> versionFilesMulti;
1446 QHash <QString, bool> fullPathDone;
1447 QHash <QString, int> fileIndexHash;
1448 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1449 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1450 /* Use a tree widget item iterator to count directories for the progress bar */
1451 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1456 } /* while (*diterc) */
1457 prBar2->setRange(0, ditcount);
1458 prBar2->setValue(0);
1460 /* Use a tree widget item iterator filtering for Checked Items */
1461 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1463 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1464 if (mainWin->m_rtRestore1Debug)
1465 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1466 /* With a checked directory, query for the files in the directory */
1469 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1471 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1473 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1474 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1475 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1476 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1477 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1478 " GROUP BY Filename.Name"
1480 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1481 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1482 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1484 " Path.Path='" + directory + "'"
1485 " AND Filename.Name=t1.Filename"
1486 " AND Job.Jobid=t1.JobId"
1487 " ORDER BY Filename";
1489 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1490 QStringList results;
1491 if (m_console->sql_cmd(cmd, results)) {
1492 QStringList fieldlist;
1495 /* Iterate through the record returned from the query */
1496 foreach (QString resultline, results) {
1497 /* Iterate through fields in the record */
1499 QString fullPath = "";
1500 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1501 fieldlist = resultline.split("\t");
1504 foreach (QString field, fieldlist) {
1506 fullPath = directory + field;
1509 version = field.toInt();
1512 fileIndex = field.toInt();
1516 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1518 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1519 if (fileExcpState != Qt::Unchecked) {
1521 if (excpVersion != 0) {
1522 debugtext = QString("*E* version=%1").arg(excpVersion);
1523 version = excpVersion;
1524 fileIndex = queryFileIndex(fullPath, excpVersion);
1526 debugtext = QString("___ version=%1").arg(version);
1527 if (mainWin->m_rtRestore1Debug)
1528 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1529 fullPathDone.insert(fullPath, 1);
1530 fileIndexHash.insert(fullPath, fileIndex);
1531 versionFilesMulti.insert(version, fullPath);
1538 prBar2->setValue(ditcount);
1540 } /* while (*diter) */
1541 prBar1->setValue(1);
1542 prLabel1->setText("Task 2 of 3");
1543 prLabel2->setText("Processing Exceptions");
1544 prBar2->setRange(0, 0);
1547 /* There may be some exceptions not accounted for yet with fullPathDone */
1548 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1549 while (ftera.hasNext()) {
1551 QString fullPath = ftera.key();
1552 Qt::CheckState state = ftera.value();
1554 /* now we don't want the ones already done */
1555 if (fullPathDone.value(fullPath, 0) == 0) {
1556 int version = m_versionExceptionHash.value(fullPath, 0);
1558 QString debugtext = "";
1560 fileIndex = queryFileIndex(fullPath, version);
1561 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1563 version = mostRecentVersionfromFullPath(fullPath);
1565 fileIndex = queryFileIndex(fullPath, version);
1566 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1568 debugtext = QString("Error det vers").arg(version);
1570 if (mainWin->m_rtRestore1Debug)
1571 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1572 versionFilesMulti.insert(version, fullPath);
1574 fileIndexHash.insert(fullPath, fileIndex);
1575 } /* if fullPathDone.value(fullPath, 0) == 0 */
1576 } /* if state != 0 */
1577 } /* while ftera.hasNext */
1578 /* The progress bars for the next step */
1579 prBar1->setValue(2);
1580 prLabel1->setText("Task 3 of 3");
1581 prLabel2->setText("Filling Database Table");
1582 prBar2->setRange(0, vFMCounter);
1584 prBar2->setValue(vFMCounter);
1587 /* now for the final spit out of the versions and lists of files for each version */
1588 QHash<int, int> doneKeys;
1589 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1590 QString tempTable = "";
1592 while (vFMiter.hasNext()) {
1594 int fversion = vFMiter.key();
1595 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1596 if (doneKeys.value(fversion, 0) == 0) {
1597 if (tempTable == "") {
1598 QSettings settings("www.bacula.org", "bat");
1599 settings.beginGroup("Restore");
1600 int counter = settings.value("Counter", 1).toInt();
1601 settings.setValue("Counter", counter+1);
1602 settings.endGroup();
1603 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1604 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1605 if (mainWin->m_sqlDebug)
1606 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1607 QStringList results;
1608 if (!m_console->sql_cmd(sqlcmd, results))
1609 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1612 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1613 QStringList fullPathList = versionFilesMulti.values(fversion);
1614 /* create the command to perform the restore */
1615 foreach(QString ffullPath, fullPathList) {
1616 int fileIndex = fileIndexHash.value(ffullPath);
1617 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1618 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1619 if (mainWin->m_rtRestore3Debug)
1620 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1621 QStringList results;
1622 if (!m_console->sql_cmd(sqlcmd, results))
1623 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1624 prBar2->setValue(++vFMCounter);
1625 } /* foreach fullPathList */
1626 doneKeys.insert(fversion,1);
1627 jobList.append(fversion);
1628 } /* if (doneKeys.value(fversion, 0) == 0) */
1629 } /* while (vFMiter.hasNext()) */
1630 if (tempTable != "") {
1631 /* a table was made, lets run the job */
1632 QString jobOption = " jobid=\"";
1634 /* create a list of jobs comma separated */
1635 foreach (int job, jobList) {
1636 if (first) first = false;
1637 else jobOption += ",";
1638 jobOption += QString("%1").arg(job);
1641 QString cmd = QString("restore");
1643 " client=\"" + m_prevClientCombo + "\"" +
1644 " file=\"?" + tempTable + "\" done";
1645 if (mainWin->m_commandDebug)
1646 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1647 consoleCommand(cmd);
1649 /* turn off the progress widgets */
1650 prBar1->setVisible(false);
1651 prBar2->setVisible(false);
1652 prLabel1->setVisible(false);
1653 prLabel2->setVisible(false);
1656 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1659 QString directory, fileName;
1660 int index = m_slashregex.lastIndexIn(fullPath, -2);
1662 directory = fileName = fullPath;
1663 directory.replace(index+1, fullPath.length()-index-1, "");
1664 fileName.replace(0, index+1, "");
1666 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1667 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1668 Pmsg0(000, msg.toUtf8().data());
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 Path ON (Path.PathId=File.PathId)"
1676 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1677 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1678 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1679 " AND Filename.Name='" + fileName + "'"
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();
1701 } /* if (index != -1) */
1706 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1709 QString directory, fileName;
1710 int index = m_slashregex.lastIndexIn(fullPath, -2);
1712 directory = fileName = fullPath;
1713 directory.replace(index+1, fullPath.length()-index-1, "");
1714 fileName.replace(0, index+1, "");
1716 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1717 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1718 Pmsg0(000, msg.toUtf8().data());
1720 /* so now we need the latest version from the database */
1725 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1726 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1727 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1729 " Path.Path='" + directory + "'"
1730 " AND Filename.Name='" + fileName + "'"
1731 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1732 " GROUP BY File.FileIndex";
1734 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1735 QStringList results;
1736 if (m_console->sql_cmd(cmd, results)) {
1737 QStringList fieldlist;
1739 /* Iterate through the record returned from the query */
1740 foreach (QString resultline, results) {
1741 /* Iterate through fields in the record */
1743 fieldlist = resultline.split("\t");
1744 foreach (QString field, fieldlist) {
1746 qfileIndex = field.toInt();
1753 } /* if (index != -1) */