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 *)));
118 QStringList titles = QStringList() << "Directories";
119 directoryTree->setHeaderLabels(titles);
120 clientCombo->addItems(m_console->client_list);
121 fileSetCombo->addItem("Any");
122 fileSetCombo->addItems(m_console->fileset_list);
123 jobCombo->addItem("Any");
124 jobCombo->addItems(m_console->job_list);
126 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
129 void restoreTree::updateRefresh()
131 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
132 m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
133 || (m_prevClientCombo != clientCombo->currentText())
134 || (m_prevFileSetCombo != fileSetCombo->currentText()
135 || (m_prevLimitSpinBox != limitSpinBox->value())
136 || (m_prevDaysSpinBox != daysSpinBox->value())
137 || (m_prevLimitCheckState != limitCheckBox->checkState())
138 || (m_prevDaysCheckState != daysCheckBox->checkState())
140 if (m_dropdownChanged) {
141 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
142 refreshLabel->setText("Refresh From Re-Select");
144 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
145 refreshLabel->setText("Refresh From JobChecks");
150 * When refresh button is pushed, perform a query getting the directories and
151 * use parseDirectory and addDirectory to populate the directory tree with items.
153 void restoreTree::populateDirectoryTree()
157 directoryTree->clear();
159 fileTable->setRowCount(0);
160 fileTable->setColumnCount(0);
161 versionTable->clear();
162 versionTable->setRowCount(0);
163 versionTable->setColumnCount(0);
164 m_fileExceptionHash.clear();
165 m_fileExceptionMulti.clear();
166 m_versionExceptionHash.clear();
167 m_directoryIconStateHash.clear();
169 QString jobComboText = jobCombo->currentText();
170 QString clientComboText = clientCombo->currentText();
171 QString fileSetComboText = fileSetCombo->currentText();
173 int taskcount = 2, ontask = 1;
174 if (m_dropdownChanged) taskcount += 1;
176 /* Set progress bars and repaint */
177 prBar1->setVisible(true);
178 prBar1->setRange(0,taskcount);
180 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
181 prLabel1->setVisible(true);
182 prBar2->setVisible(true);
183 prBar2->setRange(0,0);
184 prLabel2->setText("Querying Database");
185 prLabel2->setVisible(true);
188 if (m_dropdownChanged) {
189 m_prevJobCombo = jobComboText;
190 m_prevClientCombo = clientComboText;
191 m_prevFileSetCombo = fileSetComboText;
192 m_prevLimitSpinBox = limitSpinBox->value();
193 m_prevDaysSpinBox = daysSpinBox->value();
194 m_prevLimitCheckState = limitCheckBox->checkState();
195 m_prevDaysCheckState = daysCheckBox->checkState();
197 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
199 QString condition = " Client.Name='" + clientCombo->itemText(clientCombo->currentIndex()) + "'";
200 if ((jobCombo->currentIndex() >= 0) && (jobComboText != "Any")) {
201 condition.append(" AND Job.name = '" + jobComboText + "'");
203 if ((fileSetCombo->currentIndex() >= 0) && (fileSetComboText != "Any")) {
204 condition.append(" AND FileSet.FileSet='" + fileSetComboText + "'");
206 /* If Limit check box For limit by days is checked */
207 if (daysCheckBox->checkState() == Qt::Checked) {
208 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
209 QString since = stamp.toString(Qt::ISODate);
210 condition.append(" AND Job.Starttime>'" + since + "'");
213 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
214 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
215 " WHERE" + condition +
216 " AND Job.purgedfiles=0";
217 prBar1->setValue(ontask++);
218 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
220 prBar2->setRange(0,0);
221 prLabel2->setText("Querying Jobs");
224 setJobsCheckedList();
226 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
227 setJobsCheckedList();
230 if (m_checkedJobs != "") {
232 "SELECT DISTINCT Path.Path AS Path"
234 " INNER JOIN File ON (File.PathId=Path.PathId)"
235 " INNER JOIN Job ON (File.JobId=Job.JobId)"
236 " WHERE Job.Jobid IN (" + m_checkedJobs + ")"
238 if (mainWin->m_sqlDebug) {
239 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
241 prBar1->setValue(ontask++);
242 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
244 prLabel2->setText("Processing Directories");
245 QStringList directories;
246 if (m_console->sql_cmd(cmd, directories)) {
247 if (mainWin->m_miscDebug) {
248 Pmsg1(000, "Done with query %i directories\n", directories.count());
250 prBar2->setRange(0,directories.count());
252 foreach(QString directory, directories) {
254 prBar2->setValue(m_debugCnt);
255 parseDirectory(directory);
259 QMessageBox::warning(this, tr("Bat"),
260 tr("No jobs were selected in the job query !!!.\n"
261 "Press OK to continue?"),
264 prBar1->setVisible(false);
265 prBar2->setVisible(false);
266 prLabel1->setVisible(false);
267 prLabel2->setVisible(false);
271 * Function to set m_checkedJobs from the jobs that are checked in the table
274 void restoreTree::setJobsCheckedList()
276 m_JobsCheckedList = "";
278 /* Update the items in the version table */
279 int cnt = jobTable->rowCount();
280 for (int row=0; row<cnt; row++) {
281 QTableWidgetItem* jobItem = jobTable->item(row, 0);
282 if (jobItem->checkState() == Qt::Checked) {
284 m_JobsCheckedList += ",";
285 m_JobsCheckedList += jobItem->text();
287 jobItem->setBackground(Qt::green);
289 jobItem->setBackground(Qt::gray);
291 m_checkedJobs = m_JobsCheckedList;
295 * Function to parse a directory into all possible subdirectories, then add to
298 void restoreTree::parseDirectory(QString &dir_in)
300 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
301 * instead of printing out what could potentially a whole bunch */
304 /* Clean up the directory string remove some funny char after last '/' */
305 QRegExp rgx("[^/]$");
306 int lastslash = rgx.indexIn(dir_in);
307 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
308 if ((mainWin->m_miscDebug) && (m_debugTrap))
309 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
311 /* split and add if not in yet */
312 QString direct, path;
315 QStringList pathAfter, dirAfter;
316 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
317 * if not added into tree, then try /etc/ and somedir/ if not added, then try
318 * / and etc/ . That should succeed, then add the ones that failed in reverse */
319 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
320 direct = path = dir_in;
321 path.replace(index+1, dir_in.length()-index-1,"");
322 direct.replace(0, index+1, "");
323 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
324 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
325 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
326 Pmsg0(000, msg.toUtf8().data());
328 if (addDirectory(path, direct)) done = true;
330 if ((mainWin->m_miscDebug) && (m_debugTrap))
331 Pmsg0(000, "Saving for later\n");
332 pathAfter.prepend(path);
333 dirAfter.prepend(direct);
338 for (int k=0; k<pathAfter.count(); k++) {
339 if (addDirectory(pathAfter[k], dirAfter[k]))
340 if ((mainWin->m_miscDebug) && (m_debugTrap))
341 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
343 if ((mainWin->m_miscDebug) && (m_debugTrap))
344 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
349 * Function called from fill directory when a directory is found to see if this
350 * directory exists in the directory pane and then add it to the directory pane
352 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
354 QString newdir = newdirr;
355 QString fullPath = m_cwd + newdirr;
356 bool ok = true, added = false;
358 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
359 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
362 Pmsg0(000, msg.toUtf8().data());
366 /* add unix '/' directory first */
367 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
369 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
371 item->setText(0, text.toUtf8().data());
372 item->setData(0, Qt::UserRole, QVariant(text));
373 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
374 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
375 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
376 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
378 m_dirPaths.insert(text, item);
380 /* no need to check for windows drive if unix */
381 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
382 /* this is a windows drive add the base widget */
383 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
384 item->setText(0, m_cwd);
385 item->setData(0, Qt::UserRole, QVariant(fullPath));
386 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
387 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
388 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
389 Pmsg0(000, "Added Base \"letter\":/\n");
391 m_dirPaths.insert(m_cwd, item);
395 /* is it already existent ?? */
396 if (!m_dirPaths.contains(fullPath)) {
397 QTreeWidgetItem *item = NULL;
398 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
400 /* new directories to add */
401 item = new QTreeWidgetItem(parent);
402 item->setText(0, newdir.toUtf8().data());
403 item->setData(0, Qt::UserRole, QVariant(fullPath));
404 item->setCheckState(0, Qt::Unchecked);
405 /* Store the current state of the check status in column 1, which at
406 * this point has no text*/
407 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
410 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
411 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
414 Pmsg0(000, msg.toUtf8().data());
417 /* insert into hash */
419 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
420 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
422 m_dirPaths.insert(fullPath, item);
430 * Virtual function which is called when this page is visible on the stack
432 void restoreTree::currentStackItem()
435 if (!m_console->preventInUseConnect())
443 * Populate the tree when refresh button pushed.
445 void restoreTree::refreshButtonPushed()
447 populateDirectoryTree();
451 * Set the values of non-job combo boxes to the job defaults
453 void restoreTree::jobComboChanged(int)
455 if (jobCombo->currentText() == "Any") {
456 fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
459 job_defaults job_defs;
462 job_defs.job_name = jobCombo->currentText();
463 if (m_console->get_job_defaults(job_defs)) {
464 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
465 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
470 * Function to populate the file list table
472 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
477 m_fileCheckStateList.clear();
478 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
479 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
480 QBrush blackBrush(Qt::black);
481 QString directory = item->data(0, Qt::UserRole).toString();
482 directoryLabel->setText("Present Working Directory : " + directory);
484 "SELECT DISTINCT Filename.Name AS FileName"
486 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
487 " INNER JOIN Path ON (Path.PathId=File.PathId)"
488 " INNER JOIN Job ON (File.JobId=Job.JobId)"
489 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
490 " AND Job.Jobid IN (" + m_checkedJobs + ")"
491 " ORDER BY FileName";
493 QStringList headerlist = (QStringList() << "File Name");
495 /* Also clear the version table here */
496 versionTable->clear();
497 versionFileLabel->setText("");
498 versionTable->setRowCount(0);
499 versionTable->setColumnCount(0);
500 fileTable->setColumnCount(headerlist.size());
501 fileTable->setHorizontalHeaderLabels(headerlist);
503 if (mainWin->m_sqlDebug) {
504 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
507 if (m_console->sql_cmd(cmd, results)) {
509 QTableWidgetItem* tableItem;
511 QStringList fieldlist;
512 fileTable->setRowCount(results.size());
515 /* Iterate through the record returned from the query */
516 foreach (QString resultline, results) {
517 /* Iterate through fields in the record */
519 fieldlist = resultline.split("\t");
520 foreach (field, fieldlist) {
521 field = field.trimmed(); /* strip leading & trailing spaces */
522 tableItem = new QTableWidgetItem(field, 1);
523 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
524 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
525 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
526 tableItem->setForeground(blackBrush);
527 /* Just in case a column ever gets added */
529 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
530 tableItem->setFlags(flag);
531 tableItem->setData(Qt::UserRole, QVariant(directory));
532 fileTable->setItem(row, column, tableItem);
533 m_fileCheckStateList.append(Qt::Unchecked);
534 tableItem->setCheckState(Qt::Unchecked);
540 fileTable->setRowCount(row);
542 fileTable->resizeColumnsToContents();
543 fileTable->resizeRowsToContents();
544 fileTable->verticalHeader()->hide();
545 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
546 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
547 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
548 updateFileTableChecks();
552 * Function to populate the version table
554 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
556 if (fileTableItem == NULL)
559 m_versionCheckStateList.clear();
560 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
561 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
563 QString file = fileTableItem->text();
564 versionFileLabel->setText(file);
565 QString directory = fileTableItem->data(Qt::UserRole).toString();
567 QBrush blackBrush(Qt::black);
569 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
571 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
572 " INNER JOIN Path ON (Path.PathId=File.PathId)"
573 " INNER JOIN Job ON (File.JobId=Job.JobId)"
574 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
575 " AND Job.Jobid IN (" + m_checkedJobs + ")"
576 " ORDER BY Job.EndTime DESC";
578 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
579 versionTable->clear();
580 versionTable->setColumnCount(headerlist.size());
581 versionTable->setHorizontalHeaderLabels(headerlist);
583 if (mainWin->m_sqlDebug) {
584 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
587 if (m_console->sql_cmd(cmd, results)) {
589 QTableWidgetItem* tableItem;
591 QStringList fieldlist;
592 versionTable->setRowCount(results.size());
595 /* Iterate through the record returned from the query */
596 foreach (QString resultline, results) {
597 fieldlist = resultline.split("\t");
599 /* remove directory */
600 if (fieldlist[0].trimmed() != "") {
601 /* Iterate through fields in the record */
602 foreach (field, fieldlist) {
603 field = field.trimmed(); /* strip leading & trailing spaces */
604 tableItem = new QTableWidgetItem(field, 1);
605 tableItem->setFlags(0);
606 tableItem->setForeground(blackBrush);
607 tableItem->setData(Qt::UserRole, QVariant(directory));
608 versionTable->setItem(row, column, tableItem);
611 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
612 tableItem->setFlags(flag);
613 m_versionCheckStateList.append(Qt::Unchecked);
614 tableItem->setCheckState(Qt::Unchecked);
622 versionTable->resizeColumnsToContents();
623 versionTable->resizeRowsToContents();
624 versionTable->verticalHeader()->hide();
625 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
626 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
627 updateVersionTableChecks();
631 * Save user settings associated with this page
633 void restoreTree::writeSettings()
635 QSettings settings(m_console->m_dir->name(), "bat");
636 settings.beginGroup("RestoreTree");
637 settings.setValue("splitterSizes", splitter->saveState());
642 * Read and restore user settings associated with this page
644 void restoreTree::readSettings()
646 QSettings settings(m_console->m_dir->name(), "bat");
647 settings.beginGroup("RestoreTree");
648 splitter->restoreState(settings.value("splitterSizes").toByteArray());
653 * This is a funcion to accomplish the one thing I struggled to figure out what
654 * was taking so long. It add the icons, but after the tree is made. Seemed to
655 * work fast after changing from png to png file for graphic.
657 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
659 int childCount = item->childCount();
660 for (int i=0; i<childCount; i++) {
661 QTreeWidgetItem *child = item->child(i);
662 if (child->icon(0).isNull())
663 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
668 * I wanted a table to show what jobs meet the criterion and are being used to
669 * populate the directory tree and file and version tables.
671 void restoreTree::populateJobTable()
673 QBrush blackBrush(Qt::black);
674 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
676 jobTable->setColumnCount(headerlist.size());
677 jobTable->setHorizontalHeaderLabels(headerlist);
679 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
680 " FROM Job" + m_jobQueryPart +
681 " ORDER BY Job.EndTime DESC";
682 /* If Limit check box for limit records returned is checked */
683 if (limitCheckBox->checkState() == Qt::Checked) {
685 limit.setNum(limitSpinBox->value());
686 jobQuery += " LIMIT " + limit;
688 if (mainWin->m_sqlDebug)
689 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
692 if (m_console->sql_cmd(jobQuery, results)) {
694 QTableWidgetItem* tableItem;
696 QStringList fieldlist;
697 jobTable->setRowCount(results.size());
700 /* Iterate through the record returned from the query */
701 foreach (QString resultline, results) {
702 fieldlist = resultline.split("\t");
704 /* remove directory */
705 if (fieldlist[0].trimmed() != "") {
706 /* Iterate through fields in the record */
707 foreach (field, fieldlist) {
708 field = field.trimmed(); /* strip leading & trailing spaces */
709 tableItem = new QTableWidgetItem(field, 1);
710 tableItem->setFlags(0);
711 tableItem->setForeground(blackBrush);
712 jobTable->setItem(row, column, tableItem);
714 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
715 tableItem->setFlags(flag);
716 tableItem->setCheckState(Qt::Checked);
717 tableItem->setBackground(Qt::green);
725 jobTable->resizeColumnsToContents();
726 jobTable->resizeRowsToContents();
727 jobTable->verticalHeader()->hide();
731 * When a directory item is "changed" check the state of the checkable item
732 * to see if it is different than what it was which is stored in Qt::UserRole
733 * of the 2nd column, column 1, of the tree widget.
735 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
737 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
738 Qt::CheckState curState = item->checkState(0);
739 QTreeWidgetItem* parent = item->parent();
740 Qt::CheckState parState;
741 if (parent) parState = parent->checkState(0);
742 else parState = (Qt::CheckState)3;
743 if (mainWin->m_rtDirICDebug) {
744 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
745 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
746 Pmsg1(000, "%s", msg.toUtf8().data()); }
747 /* I only care when the check state changes */
748 if (prevState == curState) {
749 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
753 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
754 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
755 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
756 curState = Qt::PartiallyChecked;
758 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
759 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
760 directoryTreeDisconnectedSet(item, Qt::Unchecked);
761 curState = Qt::Unchecked;
763 if (mainWin->m_rtDirICDebug) {
764 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
765 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
766 Pmsg1(000, "%s", msg.toUtf8().data()); }
768 item->setData(1, Qt::UserRole, QVariant(curState));
769 Qt::CheckState childState = curState;
770 if (childState == Qt::Checked)
771 childState = Qt::PartiallyChecked;
772 setCheckofChildren(item, childState);
774 /* Remove items from the exception lists. The multi exception list is my index
775 * of what exceptions can be removed when the directory is known*/
776 QString directory = item->data(0, Qt::UserRole).toString();
777 QStringList fullPathList = m_fileExceptionMulti.values(directory);
778 int fullPathListCount = fullPathList.count();
779 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
780 foreach (QString fullPath, fullPathList) {
781 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
782 * which will match no Qt::xxx values */
783 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
784 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
785 if (hashState == Qt::Unchecked) {
786 fileExceptionRemove(fullPath, directory);
787 m_versionExceptionHash.remove(fullPath);
788 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
790 if (hashState == Qt::Checked) {
791 fileExceptionRemove(fullPath, directory);
792 m_versionExceptionHash.remove(fullPath);
793 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
797 if (item == directoryTree->currentItem()) {
798 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
799 updateFileTableChecks();
800 versionTable->clear();
801 versionTable->setRowCount(0);
802 versionTable->setColumnCount(0);
804 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
808 * When a directory item check state is changed, this function iterates through
809 * all subdirectories and sets all to the passed state, which is either partially
810 * checked or unchecked.
812 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
815 childCount = item->childCount();
816 for (int i=0; i<childCount; i++) {
817 QTreeWidgetItem *child = item->child(i);
818 child->setData(1, Qt::UserRole, QVariant(state));
819 child->setCheckState(0, state);
820 setCheckofChildren(child, state);
825 * When a File Table Item is "changed" check to see if the state of the checkable
826 * item has changed which is stored in m_fileCheckStateList
827 * If changed store in a hash m_fileExceptionHash that whether this file should be
829 * Called as a slot, connected after populated (after directory current changed called)
831 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
833 /* get the previous and current check states */
834 int row = fileTable->row(item);
835 Qt::CheckState prevState;
836 /* prevent a segfault */
837 prevState = m_fileCheckStateList[row];
838 Qt::CheckState curState = item->checkState();
840 /* deterimine the default state from the state of the directory */
841 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
842 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
843 Qt::CheckState defState = Qt::PartiallyChecked;
844 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
846 /* determine if it is already in the m_fileExceptionHash */
847 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
848 QString file = item->text();
849 QString fullPath = directory + file;
850 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
851 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
853 if (mainWin->m_rtFileTabICDebug) {
854 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
855 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
856 Pmsg1(000, "%s", msg.toUtf8().data()); }
858 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
859 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
860 /* it can behave as defaulted so current of unchecked is fine */
861 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
862 fileExceptionRemove(fullPath, directory);
863 m_versionExceptionHash.remove(fullPath);
864 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
865 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
866 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
867 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
868 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
869 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
870 fileExceptionRemove(fullPath, directory);
871 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
872 /* Check dir, check version, attempt uncheck in file
873 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
874 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
875 fileExceptionRemove(fullPath, directory);
876 m_versionExceptionHash.remove(fullPath);
877 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
878 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
879 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
880 } else if (prevState != curState) {
881 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
882 /* A user did not set the check state to Partially checked, ignore if so */
883 if (curState != Qt::PartiallyChecked) {
884 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
885 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
887 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
888 fileExceptionInsert(fullPath, directory, curState);
891 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
892 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
893 m_versionExceptionHash.remove(fullPath);
897 updateFileTableChecks();
898 updateVersionTableChecks();
902 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
904 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
906 m_fileExceptionHash.insert(fullPath, state);
907 m_fileExceptionMulti.insert(direcotry, fullPath);
908 directoryIconStateInsert(fullPath, state);
912 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
914 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
916 m_fileExceptionHash.remove(fullPath);
917 /* pull the list of values in the multi */
918 QStringList fullPathList = m_fileExceptionMulti.values(directory);
919 /* get the index of the fullpath to remove */
920 int index = fullPathList.indexOf(fullPath);
922 /* remove the desired item in the list */
923 fullPathList.removeAt(index);
924 /* remove the entire list from the multi */
925 m_fileExceptionMulti.remove(directory);
926 /* readd the remaining */
927 foreach (QString fp, fullPathList) {
928 m_fileExceptionMulti.insert(directory, fp);
931 directoryIconStateRemove();
935 * Overloaded function to be called from the slot and from other places to set the state
936 * of the check marks in the version table
938 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
940 /* get the previous and current check states */
941 int row = versionTable->row(item);
942 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
943 Qt::CheckState prevState = m_versionCheckStateList[row];
944 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
945 m_versionCheckStateList[row] = curState;
947 /* deterimine the default state from the state of the file */
948 QTableWidgetItem *fileTableItem = fileTable->currentItem();
949 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
951 /* determine the default state */
952 Qt::CheckState defState;
954 defState = Qt::PartiallyChecked;
955 if (fileState == Qt::Unchecked)
956 defState = Qt::Unchecked;
959 defState = Qt::Unchecked;
961 /* determine if it is already in the versionExceptionHash */
962 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
963 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
964 QString file = fileTableItem->text();
965 QString fullPath = directory + file;
966 int thisJobNum = colZeroItem->text().toInt();
967 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
969 if (mainWin->m_rtVerTabICDebug) {
970 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
971 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
972 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
973 Pmsg1(000, "%s", msg.toUtf8().data()); }
974 /* if changed from partially checked to checked, make it unchecked */
975 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
976 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
977 fileTableItem->setCheckState(Qt::Checked);
978 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
979 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
980 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
981 fileExceptionRemove(fullPath, directory);
982 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
983 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
984 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
985 m_versionExceptionHash.remove(fullPath);
986 fileExceptionRemove(fullPath, directory);
987 } else if ((curState == Qt::Checked) && (row == 0)) {
988 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
989 m_versionExceptionHash.remove(fullPath);
990 } else if (prevState != curState) {
991 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
992 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
993 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
994 m_versionExceptionHash.insert(fullPath, thisJobNum);
995 if (fileState != Qt::Checked) {
996 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
997 fileExceptionInsert(fullPath, directory, curState);
1000 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1003 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1006 updateFileTableChecks();
1007 updateVersionTableChecks();
1011 * Simple function to set the check state in the file table by disconnecting the
1012 * signal/slot the setting then reconnecting the signal/slot
1014 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1016 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1017 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1018 item->setCheckState(state);
1019 if (color) item->setBackground(Qt::yellow);
1020 else item->setBackground(Qt::white);
1021 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1022 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1026 * Simple function to set the check state in the version table by disconnecting the
1027 * signal/slot the setting then reconnecting the signal/slot
1029 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1031 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1032 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1033 item->setCheckState(state);
1034 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1035 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1039 * Simple function to set the check state in the directory tree by disconnecting the
1040 * signal/slot the setting then reconnecting the signal/slot
1042 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1044 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1045 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1046 item->setCheckState(0, state);
1047 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1048 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1052 * Simplify the updating of the check state in the File table by iterating through
1053 * each item in the file table to determine it's appropriate state.
1054 * !! Will probably want to concoct a way to do this without iterating for the possibility
1055 * of the very large directories.
1057 void restoreTree::updateFileTableChecks()
1059 /* deterimine the default state from the state of the directory */
1060 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1061 Qt::CheckState dirState = dirTreeItem->checkState(0);
1063 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1065 /* Update the items in the version table */
1066 int rcnt = fileTable->rowCount();
1067 for (int row=0; row<rcnt; row++) {
1068 QTableWidgetItem* item = fileTable->item(row, 0);
1070 Qt::CheckState curState = item->checkState();
1071 Qt::CheckState newState = Qt::PartiallyChecked;
1072 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1074 /* determine if it is already in the m_fileExceptionHash */
1075 QString file = item->text();
1076 QString fullPath = dirName + file;
1077 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1078 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1080 if (hashState != 3) newState = hashState;
1082 if (mainWin->m_rtUpdateFTDebug) {
1083 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1084 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1085 Pmsg1(000, "%s", msg.toUtf8().data());
1088 bool docolor = false;
1089 if (hashJobNum != 0) docolor = true;
1090 bool isyellow = item->background().color() == QColor(Qt::yellow);
1091 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1092 fileTableDisconnectedSet(item, newState, docolor);
1093 m_fileCheckStateList[row] = newState;
1098 * Simplify the updating of the check state in the Version table by iterating through
1099 * each item in the file table to determine it's appropriate state.
1101 void restoreTree::updateVersionTableChecks()
1103 /* deterimine the default state from the state of the directory */
1104 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1105 Qt::CheckState dirState = dirTreeItem->checkState(0);
1106 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1108 /* deterimine the default state from the state of the file */
1109 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1110 Qt::CheckState fileState = fileTableItem->checkState();
1111 QString file = fileTableItem->text();
1112 QString fullPath = dirName + file;
1113 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1115 /* Update the items in the version table */
1116 int cnt = versionTable->rowCount();
1117 for (int row=0; row<cnt; row++) {
1118 QTableWidgetItem* item = versionTable->item(row, 0);
1120 Qt::CheckState curState = item->checkState();
1121 Qt::CheckState newState = Qt::Unchecked;
1123 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1124 newState = Qt::PartiallyChecked;
1125 /* determine if it is already in the versionExceptionHash */
1127 int thisJobNum = item->text().toInt();
1128 if (thisJobNum == hashJobNum)
1129 newState = Qt::Checked;
1131 if (mainWin->m_rtChecksDebug) {
1132 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1133 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1134 Pmsg1(000, "%s", msg.toUtf8().data());
1136 if (newState != curState)
1137 versionTableDisconnectedSet(item, newState);
1138 m_versionCheckStateList[row] = newState;
1143 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1145 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1149 QString fullPath = fullPath_in;
1150 QString direct, path;
1151 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1152 direct = path = fullPath;
1153 path.replace(index+1, fullPath.length()-index-1, "");
1154 direct.replace(0, index+1, "");
1156 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1157 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1158 Pmsg0(000, msg.toUtf8().data());
1161 subPaths.append(fullPath);
1166 * A Function to set the icon state and insert a record into
1167 * m_directoryIconStateHash when an exception is added by the user
1169 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1172 fullPathtoSubPaths(paths, fullPath);
1173 /* an exception that causes the item in the file table to be "Checked" has occured */
1174 if (excpState == Qt::Checked) {
1175 bool foundAsUnChecked = false;
1176 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1178 if (firstItem->checkState(0) == Qt::Unchecked)
1179 foundAsUnChecked = true;
1181 if (foundAsUnChecked) {
1182 /* as long as directory item is Unchecked, set icon state to "green check" */
1184 QListIterator<QString> siter(paths);
1185 while (siter.hasNext() && !done) {
1186 QString path = siter.next();
1187 QTreeWidgetItem *item = m_dirPaths.value(path);
1189 if (item->checkState(0) != Qt::Unchecked)
1192 directorySetIcon(1, FolderGreenChecked, path, item);
1193 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1198 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1199 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1201 QListIterator<QString> siter(paths);
1202 while (siter.hasNext() && !done) {
1203 QString path = siter.next();
1204 QTreeWidgetItem *item = m_dirPaths.value(path);
1205 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1206 if (item->checkState(0) == Qt::Checked)
1208 directorySetIcon(1, FolderGreenChecked, path, item);
1209 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1214 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1215 if (excpState == Qt::Unchecked) {
1217 QListIterator<QString> siter(paths);
1218 while (siter.hasNext() && !done) {
1219 QString path = siter.next();
1220 QTreeWidgetItem *item = m_dirPaths.value(path);
1221 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1222 if (item->checkState(0) == Qt::Checked)
1224 directorySetIcon(1, FolderWhiteChecked, path, item);
1225 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1232 * A function to set the icon state back to "folder" and to remove a record from
1233 * m_directoryIconStateHash when an exception is removed by a user.
1235 void restoreTree::directoryIconStateRemove()
1237 QHash<QString, int> shouldBeIconStateHash;
1238 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1239 /* Use iterator tera to iterate through m_fileExceptionHash */
1240 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1241 while (tera.hasNext()) {
1243 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1245 QString keyPath = tera.key();
1246 Qt::CheckState state = tera.value();
1249 fullPathtoSubPaths(paths, keyPath);
1250 /* if the state of the item in m_fileExceptionHash is checked
1251 * each of the subpaths should be "Checked Green" */
1252 if (state == Qt::Checked) {
1254 bool foundAsUnChecked = false;
1255 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1257 if (firstItem->checkState(0) == Qt::Unchecked)
1258 foundAsUnChecked = true;
1260 if (foundAsUnChecked) {
1261 /* The right most directory is Unchecked, iterate leftwards
1262 * as long as directory item is Unchecked, set icon state to "green check" */
1264 QListIterator<QString> siter(paths);
1265 while (siter.hasNext() && !done) {
1266 QString path = siter.next();
1267 QTreeWidgetItem *item = m_dirPaths.value(path);
1269 if (item->checkState(0) != Qt::Unchecked)
1272 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1273 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1279 /* The right most directory is Unchecked, iterate leftwards
1280 * until directory item is Checked, set icon state to "green check" */
1282 QListIterator<QString> siter(paths);
1283 while (siter.hasNext() && !done) {
1284 QString path = siter.next();
1285 QTreeWidgetItem *item = m_dirPaths.value(path);
1287 if (item->checkState(0) == Qt::Checked)
1289 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1294 /* if the state of the item in m_fileExceptionHash is UNChecked
1295 * each of the subpaths should be "Checked white" until the tree item
1296 * which represents that path is Qt::Checked */
1297 if (state == Qt::Unchecked) {
1299 QListIterator<QString> siter(paths);
1300 while (siter.hasNext() && !done) {
1301 QString path = siter.next();
1302 QTreeWidgetItem *item = m_dirPaths.value(path);
1304 if (item->checkState(0) == Qt::Checked)
1306 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1311 /* now iterate through m_directoryIconStateHash which are the items that are checked
1312 * and remove all of those that are not in shouldBeIconStateHash */
1313 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1314 while (iter.hasNext()) {
1316 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1318 QString keyPath = iter.key();
1319 if (shouldBeIconStateHash.value(keyPath)) {
1320 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1321 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1322 int newval = shouldBeIconStateHash.value(keyPath);
1324 newval = newval & FolderBothChecked;
1325 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1327 directorySetIcon(0, newval, keyPath, item);
1329 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1330 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1332 directorySetIcon(0, FolderBothChecked, keyPath, item);
1333 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1334 //m_directoryIconStateHash.remove(keyPath);
1339 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1341 /* we are adding a check type white or green */
1342 if (operation > 0) {
1343 /* get the old val and "bitwise OR" with the change */
1344 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1345 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1346 m_directoryIconStateHash.insert(path, newval);
1348 /* we are removing a check type white or green */
1349 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1351 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1352 m_directoryIconStateHash.remove(path);
1355 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1356 m_directoryIconStateHash.insert(path, newval);
1359 if (newval == FolderUnchecked)
1360 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1361 else if (newval == FolderGreenChecked)
1362 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1363 else if (newval == FolderWhiteChecked)
1364 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1365 else if (newval == FolderBothChecked)
1366 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1372 void restoreTree::restoreButtonPushed()
1374 /* Set progress bars and repaint */
1375 prLabel1->setVisible(true);
1376 prLabel1->setText("Task 1 of 3");
1377 prLabel2->setVisible(true);
1378 prLabel2->setText("Processing Checked directories");
1379 prBar1->setVisible(true);
1380 prBar1->setRange(0, 3);
1381 prBar1->setValue(0);
1382 prBar2->setVisible(true);
1383 prBar2->setRange(0, 0);
1385 QMultiHash<int, QString> versionFilesMulti;
1387 QHash <QString, bool> fullPathDone;
1388 QHash <QString, int> fileIndexHash;
1389 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1390 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1391 /* Use a tree widget item iterator to count directories for the progress bar */
1392 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1397 } /* while (*diterc) */
1398 prBar2->setRange(0, ditcount);
1399 prBar2->setValue(0);
1401 /* Use a tree widget item iterator filtering for Checked Items */
1402 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1404 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1405 if (mainWin->m_rtRestore1Debug)
1406 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1407 /* With a checked directory, query for the files in the directory */
1410 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1412 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1414 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1415 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1416 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1417 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1418 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1419 " GROUP BY Filename.Name"
1421 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1422 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1423 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1425 " Path.Path='" + directory + "'"
1426 " AND Filename.Name=t1.Filename"
1427 " AND Job.Jobid=t1.JobId"
1428 " ORDER BY Filename";
1430 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1431 QStringList results;
1432 if (m_console->sql_cmd(cmd, results)) {
1433 QStringList fieldlist;
1436 /* Iterate through the record returned from the query */
1437 foreach (QString resultline, results) {
1438 /* Iterate through fields in the record */
1440 QString fullPath = "";
1441 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1442 fieldlist = resultline.split("\t");
1445 foreach (QString field, fieldlist) {
1447 fullPath = directory + field;
1450 version = field.toInt();
1453 fileIndex = field.toInt();
1457 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1459 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1460 if (fileExcpState != Qt::Unchecked) {
1462 if (excpVersion != 0) {
1463 debugtext = QString("*E* version=%1").arg(excpVersion);
1464 version = excpVersion;
1465 fileIndex = queryFileIndex(fullPath, excpVersion);
1467 debugtext = QString("___ version=%1").arg(version);
1468 if (mainWin->m_rtRestore1Debug)
1469 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1470 fullPathDone.insert(fullPath, 1);
1471 fileIndexHash.insert(fullPath, fileIndex);
1472 versionFilesMulti.insert(version, fullPath);
1479 prBar2->setValue(ditcount);
1481 } /* while (*diter) */
1482 prBar1->setValue(1);
1483 prLabel1->setText("Task 2 of 3");
1484 prLabel2->setText("Processing Exceptions");
1485 prBar2->setRange(0, 0);
1488 /* There may be some exceptions not accounted for yet with fullPathDone */
1489 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1490 while (ftera.hasNext()) {
1492 QString fullPath = ftera.key();
1493 Qt::CheckState state = ftera.value();
1495 /* now we don't want the ones already done */
1496 if (fullPathDone.value(fullPath, 0) == 0) {
1497 int version = m_versionExceptionHash.value(fullPath, 0);
1499 QString debugtext = "";
1501 fileIndex = queryFileIndex(fullPath, version);
1502 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1504 version = mostRecentVersionfromFullPath(fullPath);
1506 fileIndex = queryFileIndex(fullPath, version);
1507 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1509 debugtext = QString("Error det vers").arg(version);
1511 if (mainWin->m_rtRestore1Debug)
1512 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1513 versionFilesMulti.insert(version, fullPath);
1515 fileIndexHash.insert(fullPath, fileIndex);
1516 } /* if fullPathDone.value(fullPath, 0) == 0 */
1517 } /* if state != 0 */
1518 } /* while ftera.hasNext */
1519 /* The progress bars for the next step */
1520 prBar1->setValue(2);
1521 prLabel1->setText("Task 3 of 3");
1522 prLabel2->setText("Filling Database Table");
1523 prBar2->setRange(0, vFMCounter);
1525 prBar2->setValue(vFMCounter);
1528 /* now for the final spit out of the versions and lists of files for each version */
1529 QHash<int, int> doneKeys;
1530 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1531 QString tempTable = "";
1533 while (vFMiter.hasNext()) {
1535 int fversion = vFMiter.key();
1536 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1537 if (doneKeys.value(fversion, 0) == 0) {
1538 if (tempTable == "") {
1539 QSettings settings("www.bacula.org", "bat");
1540 settings.beginGroup("Restore");
1541 int counter = settings.value("Counter", 1).toInt();
1542 settings.setValue("Counter", counter+1);
1543 settings.endGroup();
1544 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1545 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1546 if (mainWin->m_sqlDebug)
1547 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1548 QStringList results;
1549 if (!m_console->sql_cmd(sqlcmd, results))
1550 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1553 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1554 QStringList fullPathList = versionFilesMulti.values(fversion);
1555 /* create the command to perform the restore */
1556 foreach(QString ffullPath, fullPathList) {
1557 int fileIndex = fileIndexHash.value(ffullPath);
1558 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1559 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1560 if (mainWin->m_rtRestore3Debug)
1561 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1562 QStringList results;
1563 if (!m_console->sql_cmd(sqlcmd, results))
1564 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1565 prBar2->setValue(++vFMCounter);
1566 } /* foreach fullPathList */
1567 doneKeys.insert(fversion,1);
1568 jobList.append(fversion);
1569 } /* if (doneKeys.value(fversion, 0) == 0) */
1570 } /* while (vFMiter.hasNext()) */
1571 if (tempTable != "") {
1572 /* a table was made, lets run the job */
1573 QString jobOption = " jobid=\"";
1575 /* create a list of jobs comma separated */
1576 foreach (int job, jobList) {
1577 if (first) first = false;
1578 else jobOption += ",";
1579 jobOption += QString("%1").arg(job);
1582 QString cmd = QString("restore");
1584 " client=\"" + m_prevClientCombo + "\"" +
1585 " file=\"?" + tempTable + "\" done";
1586 if (mainWin->m_commandDebug)
1587 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1588 consoleCommand(cmd);
1590 /* turn off the progress widgets */
1591 prBar1->setVisible(false);
1592 prBar2->setVisible(false);
1593 prLabel1->setVisible(false);
1594 prLabel2->setVisible(false);
1597 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1600 QString directory, fileName;
1601 int index = m_slashregex.lastIndexIn(fullPath, -2);
1603 directory = fileName = fullPath;
1604 directory.replace(index+1, fullPath.length()-index-1, "");
1605 fileName.replace(0, index+1, "");
1607 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1608 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1609 Pmsg0(000, msg.toUtf8().data());
1611 /* so now we need the latest version from the database */
1613 "SELECT MAX(Job.JobId)"
1615 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1616 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1617 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1618 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1619 " AND Job.Jobid IN (" + m_checkedJobs + ")"
1620 " AND Filename.Name='" + fileName + "'"
1621 " GROUP BY Filename.Name";
1623 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1624 QStringList results;
1625 if (m_console->sql_cmd(cmd, results)) {
1626 QStringList fieldlist;
1628 /* Iterate through the record returned from the query */
1629 foreach (QString resultline, results) {
1630 /* Iterate through fields in the record */
1632 fieldlist = resultline.split("\t");
1633 foreach (QString field, fieldlist) {
1635 qversion = field.toInt();
1642 } /* if (index != -1) */
1647 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1650 QString directory, fileName;
1651 int index = m_slashregex.lastIndexIn(fullPath, -2);
1653 directory = fileName = fullPath;
1654 directory.replace(index+1, fullPath.length()-index-1, "");
1655 fileName.replace(0, index+1, "");
1657 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1658 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1659 Pmsg0(000, msg.toUtf8().data());
1661 /* so now we need the latest version from the database */
1666 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1667 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1668 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1670 " Path.Path='" + directory + "'"
1671 " AND Filename.Name='" + fileName + "'"
1672 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1673 " GROUP BY File.FileIndex";
1675 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1676 QStringList results;
1677 if (m_console->sql_cmd(cmd, results)) {
1678 QStringList fieldlist;
1680 /* Iterate through the record returned from the query */
1681 foreach (QString resultline, results) {
1682 /* Iterate through fields in the record */
1684 fieldlist = resultline.split("\t");
1685 foreach (QString field, fieldlist) {
1687 qfileIndex = field.toInt();
1694 } /* if (index != -1) */