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";
219 " From Job" + m_jobQueryPart;
220 /* If Limit check box for limit records returned is checked */
221 if (limitCheckBox->checkState() == Qt::Checked) {
223 limit.setNum(limitSpinBox->value());
224 m_jobQuery += " LIMIT " + limit;
227 if (mainWin->m_rtPopDirDebug)
228 Pmsg1(000, "m_jobQuery : %s\n", m_jobQuery.toUtf8().data());
229 prBar1->setValue(ontask++);
230 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
232 prBar2->setRange(0,0);
233 prLabel2->setText("Querying Jobs");
236 setJobsCheckedList();
238 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
239 setJobsCheckedList();
243 "SELECT DISTINCT Path.Path AS Path"
245 " INNER JOIN File ON (File.PathId=Path.PathId)"
246 " INNER JOIN Job ON (File.JobId=Job.JobId)"
247 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
249 if (mainWin->m_sqlDebug) {
250 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
252 prBar1->setValue(ontask++);
253 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
255 prLabel2->setText("Processing Directories");
256 QStringList directories;
257 if (m_console->sql_cmd(cmd, directories)) {
258 if (mainWin->m_miscDebug) {
259 Pmsg1(000, "Done with query %i directories\n", directories.count());
261 prBar2->setRange(0,directories.count());
263 foreach(QString directory, directories) {
265 prBar2->setValue(m_debugCnt);
266 parseDirectory(directory);
269 prBar1->setVisible(false);
270 prBar2->setVisible(false);
271 prLabel1->setVisible(false);
272 prLabel2->setVisible(false);
276 * Function to set m_jobQuery from the jobs that are checked in the table
279 void restoreTree::setJobsCheckedList()
281 m_JobsCheckedList = "";
283 /* Update the items in the version table */
284 int cnt = jobTable->rowCount();
285 for (int row=0; row<cnt; row++) {
286 QTableWidgetItem* jobItem = jobTable->item(row, 0);
287 if (jobItem->checkState() == Qt::Checked) {
289 m_JobsCheckedList += ",";
290 m_JobsCheckedList += jobItem->text();
292 jobItem->setBackground(Qt::green);
294 jobItem->setBackground(Qt::gray);
296 m_jobQuery = m_JobsCheckedList;
300 * Function to parse a directory into all possible subdirectories, then add to
303 void restoreTree::parseDirectory(QString &dir_in)
305 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
306 * instead of printing out what could potentially a whole bunch */
309 /* Clean up the directory string remove some funny char after last '/' */
310 QRegExp rgx("[^/]$");
311 int lastslash = rgx.indexIn(dir_in);
312 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
313 if ((mainWin->m_miscDebug) && (m_debugTrap))
314 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
316 /* split and add if not in yet */
317 QString direct, path;
320 QStringList pathAfter, dirAfter;
321 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
322 * if not added into tree, then try /etc/ and somedir/ if not added, then try
323 * / and etc/ . That should succeed, then add the ones that failed in reverse */
324 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
325 direct = path = dir_in;
326 path.replace(index+1, dir_in.length()-index-1,"");
327 direct.replace(0, index+1, "");
328 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
329 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
330 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
331 Pmsg0(000, msg.toUtf8().data());
333 if (addDirectory(path, direct)) done = true;
335 if ((mainWin->m_miscDebug) && (m_debugTrap))
336 Pmsg0(000, "Saving for later\n");
337 pathAfter.prepend(path);
338 dirAfter.prepend(direct);
343 for (int k=0; k<pathAfter.count(); k++) {
344 if (addDirectory(pathAfter[k], dirAfter[k]))
345 if ((mainWin->m_miscDebug) && (m_debugTrap))
346 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
348 if ((mainWin->m_miscDebug) && (m_debugTrap))
349 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
354 * Function called from fill directory when a directory is found to see if this
355 * directory exists in the directory pane and then add it to the directory pane
357 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
359 QString newdir = newdirr;
360 QString fullPath = m_cwd + newdirr;
361 bool ok = true, added = false;
363 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
364 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
367 Pmsg0(000, msg.toUtf8().data());
371 /* add unix '/' directory first */
372 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
374 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
376 item->setText(0, text.toUtf8().data());
377 item->setData(0, Qt::UserRole, QVariant(text));
378 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
379 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
380 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
381 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
383 m_dirPaths.insert(text, item);
385 /* no need to check for windows drive if unix */
386 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
387 /* this is a windows drive add the base widget */
388 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
389 item->setText(0, m_cwd);
390 item->setData(0, Qt::UserRole, QVariant(fullPath));
391 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
392 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
393 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
394 Pmsg0(000, "Added Base \"letter\":/\n");
396 m_dirPaths.insert(m_cwd, item);
400 /* is it already existent ?? */
401 if (!m_dirPaths.contains(fullPath)) {
402 QTreeWidgetItem *item = NULL;
403 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
405 /* new directories to add */
406 item = new QTreeWidgetItem(parent);
407 item->setText(0, newdir.toUtf8().data());
408 item->setData(0, Qt::UserRole, QVariant(fullPath));
409 item->setCheckState(0, Qt::Unchecked);
410 /* Store the current state of the check status in column 1, which at
411 * this point has no text*/
412 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
415 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
416 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
419 Pmsg0(000, msg.toUtf8().data());
422 /* insert into hash */
424 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
425 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
427 m_dirPaths.insert(fullPath, item);
435 * Virtual function which is called when this page is visible on the stack
437 void restoreTree::currentStackItem()
440 if (!m_console->preventInUseConnect())
448 * Populate the tree when refresh button pushed.
450 void restoreTree::refreshButtonPushed()
452 populateDirectoryTree();
456 * Set the values of non-job combo boxes to the job defaults
458 void restoreTree::jobComboChanged(int)
460 if (jobCombo->currentText() == "Any") {
461 fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
464 job_defaults job_defs;
467 job_defs.job_name = jobCombo->currentText();
468 if (m_console->get_job_defaults(job_defs)) {
469 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
470 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
475 * Function to populate the file list table
477 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
482 m_fileCheckStateList.clear();
483 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
484 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
485 QBrush blackBrush(Qt::black);
486 QString directory = item->data(0, Qt::UserRole).toString();
487 directoryLabel->setText("Present Working Directory : " + directory);
489 "SELECT DISTINCT Filename.Name AS FileName"
491 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
492 " INNER JOIN Path ON (Path.PathId=File.PathId)"
493 " INNER JOIN Job ON (File.JobId=Job.JobId)"
494 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
495 " AND Job.Jobid IN (" + m_jobQuery + ")"
496 " ORDER BY FileName";
498 QStringList headerlist = (QStringList() << "File Name");
500 /* Also clear the version table here */
501 versionTable->clear();
502 versionFileLabel->setText("");
503 versionTable->setRowCount(0);
504 versionTable->setColumnCount(0);
505 fileTable->setColumnCount(headerlist.size());
506 fileTable->setHorizontalHeaderLabels(headerlist);
508 if (mainWin->m_sqlDebug) {
509 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
512 if (m_console->sql_cmd(cmd, results)) {
514 QTableWidgetItem* tableItem;
516 QStringList fieldlist;
517 fileTable->setRowCount(results.size());
520 /* Iterate through the record returned from the query */
521 foreach (QString resultline, results) {
522 /* Iterate through fields in the record */
524 fieldlist = resultline.split("\t");
525 foreach (field, fieldlist) {
526 field = field.trimmed(); /* strip leading & trailing spaces */
527 tableItem = new QTableWidgetItem(field, 1);
528 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
529 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
530 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
531 tableItem->setForeground(blackBrush);
532 /* Just in case a column ever gets added */
534 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
535 tableItem->setFlags(flag);
536 tableItem->setData(Qt::UserRole, QVariant(directory));
537 fileTable->setItem(row, column, tableItem);
538 m_fileCheckStateList.append(Qt::Unchecked);
539 tableItem->setCheckState(Qt::Unchecked);
545 fileTable->setRowCount(row);
547 fileTable->resizeColumnsToContents();
548 fileTable->resizeRowsToContents();
549 fileTable->verticalHeader()->hide();
550 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
551 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
552 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
553 updateFileTableChecks();
557 * Function to populate the version table
559 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
561 if (fileTableItem == NULL)
564 m_versionCheckStateList.clear();
565 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
566 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
568 QString file = fileTableItem->text();
569 versionFileLabel->setText(file);
570 QString directory = fileTableItem->data(Qt::UserRole).toString();
572 QBrush blackBrush(Qt::black);
574 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
576 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
577 " INNER JOIN Path ON (Path.PathId=File.PathId)"
578 " INNER JOIN Job ON (File.JobId=Job.JobId)"
579 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
580 " AND Job.Jobid IN (" + m_jobQuery + ")"
581 " ORDER BY Job.EndTime DESC";
583 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
584 versionTable->clear();
585 versionTable->setColumnCount(headerlist.size());
586 versionTable->setHorizontalHeaderLabels(headerlist);
588 if (mainWin->m_sqlDebug) {
589 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
592 if (m_console->sql_cmd(cmd, results)) {
594 QTableWidgetItem* tableItem;
596 QStringList fieldlist;
597 versionTable->setRowCount(results.size());
600 /* Iterate through the record returned from the query */
601 foreach (QString resultline, results) {
602 fieldlist = resultline.split("\t");
604 /* remove directory */
605 if (fieldlist[0].trimmed() != "") {
606 /* Iterate through fields in the record */
607 foreach (field, fieldlist) {
608 field = field.trimmed(); /* strip leading & trailing spaces */
609 tableItem = new QTableWidgetItem(field, 1);
610 tableItem->setFlags(0);
611 tableItem->setForeground(blackBrush);
612 tableItem->setData(Qt::UserRole, QVariant(directory));
613 versionTable->setItem(row, column, tableItem);
616 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
617 tableItem->setFlags(flag);
618 m_versionCheckStateList.append(Qt::Unchecked);
619 tableItem->setCheckState(Qt::Unchecked);
627 versionTable->resizeColumnsToContents();
628 versionTable->resizeRowsToContents();
629 versionTable->verticalHeader()->hide();
630 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
631 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
632 updateVersionTableChecks();
636 * Save user settings associated with this page
638 void restoreTree::writeSettings()
640 QSettings settings(m_console->m_dir->name(), "bat");
641 settings.beginGroup("RestoreTree");
642 settings.setValue("splitterSizes", splitter->saveState());
647 * Read and restore user settings associated with this page
649 void restoreTree::readSettings()
651 QSettings settings(m_console->m_dir->name(), "bat");
652 settings.beginGroup("RestoreTree");
653 splitter->restoreState(settings.value("splitterSizes").toByteArray());
658 * This is a funcion to accomplish the one thing I struggled to figure out what
659 * was taking so long. It add the icons, but after the tree is made. Seemed to
660 * work fast after changing from svg to png file for graphic.
662 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
664 int childCount = item->childCount();
665 for (int i=0; i<childCount; i++) {
666 QTreeWidgetItem *child = item->child(i);
667 if (child->icon(0).isNull())
668 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
673 * I wanted a table to show what jobs meet the criterion and are being used to
674 * populate the directory tree and file and version tables.
676 void restoreTree::populateJobTable()
678 QBrush blackBrush(Qt::black);
679 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
681 jobTable->setColumnCount(headerlist.size());
682 jobTable->setHorizontalHeaderLabels(headerlist);
684 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
685 " FROM Job" + m_jobQueryPart +
686 " ORDER BY Job.EndTime DESC";
687 /* If Limit check box for limit records returned is checked */
688 if (limitCheckBox->checkState() == Qt::Checked) {
690 limit.setNum(limitSpinBox->value());
691 jobQuery += " LIMIT " + limit;
693 if (mainWin->m_sqlDebug)
694 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
697 if (m_console->sql_cmd(jobQuery, results)) {
699 QTableWidgetItem* tableItem;
701 QStringList fieldlist;
702 jobTable->setRowCount(results.size());
705 /* Iterate through the record returned from the query */
706 foreach (QString resultline, results) {
707 fieldlist = resultline.split("\t");
709 /* remove directory */
710 if (fieldlist[0].trimmed() != "") {
711 /* Iterate through fields in the record */
712 foreach (field, fieldlist) {
713 field = field.trimmed(); /* strip leading & trailing spaces */
714 tableItem = new QTableWidgetItem(field, 1);
715 tableItem->setFlags(0);
716 tableItem->setForeground(blackBrush);
717 jobTable->setItem(row, column, tableItem);
719 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
720 tableItem->setFlags(flag);
721 tableItem->setCheckState(Qt::Checked);
722 tableItem->setBackground(Qt::green);
730 jobTable->resizeColumnsToContents();
731 jobTable->resizeRowsToContents();
732 jobTable->verticalHeader()->hide();
736 * When a directory item is "changed" check the state of the checkable item
737 * to see if it is different than what it was which is stored in Qt::UserRole
738 * of the 2nd column, column 1, of the tree widget.
740 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
742 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
743 Qt::CheckState curState = item->checkState(0);
744 QTreeWidgetItem* parent = item->parent();
745 Qt::CheckState parState;
746 if (parent) parState = parent->checkState(0);
747 else parState = (Qt::CheckState)3;
748 if (mainWin->m_rtDirICDebug) {
749 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
750 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
751 Pmsg1(000, "%s", msg.toUtf8().data()); }
752 /* I only care when the check state changes */
753 if (prevState == curState) {
754 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
758 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
759 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
760 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
761 curState = Qt::PartiallyChecked;
763 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
764 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
765 directoryTreeDisconnectedSet(item, Qt::Unchecked);
766 curState = Qt::Unchecked;
768 if (mainWin->m_rtDirICDebug) {
769 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
770 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
771 Pmsg1(000, "%s", msg.toUtf8().data()); }
773 item->setData(1, Qt::UserRole, QVariant(curState));
774 Qt::CheckState childState = curState;
775 if (childState == Qt::Checked)
776 childState = Qt::PartiallyChecked;
777 setCheckofChildren(item, childState);
779 /* Remove items from the exception lists. The multi exception list is my index
780 * of what exceptions can be removed when the directory is known*/
781 QString directory = item->data(0, Qt::UserRole).toString();
782 QStringList fullPathList = m_fileExceptionMulti.values(directory);
783 int fullPathListCount = fullPathList.count();
784 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
785 foreach (QString fullPath, fullPathList) {
786 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
787 * which will match no Qt::xxx values */
788 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
789 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
790 if (hashState == Qt::Unchecked) {
791 fileExceptionRemove(fullPath, directory);
792 m_versionExceptionHash.remove(fullPath);
793 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
795 if (hashState == Qt::Checked) {
796 fileExceptionRemove(fullPath, directory);
797 m_versionExceptionHash.remove(fullPath);
798 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
802 if (item == directoryTree->currentItem()) {
803 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
804 updateFileTableChecks();
805 versionTable->clear();
806 versionTable->setRowCount(0);
807 versionTable->setColumnCount(0);
809 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
813 * When a directory item check state is changed, this function iterates through
814 * all subdirectories and sets all to the passed state, which is either partially
815 * checked or unchecked.
817 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
820 childCount = item->childCount();
821 for (int i=0; i<childCount; i++) {
822 QTreeWidgetItem *child = item->child(i);
823 child->setData(1, Qt::UserRole, QVariant(state));
824 child->setCheckState(0, state);
825 setCheckofChildren(child, state);
830 * When a File Table Item is "changed" check to see if the state of the checkable
831 * item has changed which is stored in m_fileCheckStateList
832 * If changed store in a hash m_fileExceptionHash that whether this file should be
834 * Called as a slot, connected after populated (after directory current changed called)
836 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
838 /* get the previous and current check states */
839 int row = fileTable->row(item);
840 Qt::CheckState prevState;
841 /* prevent a segfault */
842 prevState = m_fileCheckStateList[row];
843 Qt::CheckState curState = item->checkState();
845 /* deterimine the default state from the state of the directory */
846 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
847 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
848 Qt::CheckState defState = Qt::PartiallyChecked;
849 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
851 /* determine if it is already in the m_fileExceptionHash */
852 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
853 QString file = item->text();
854 QString fullPath = directory + file;
855 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
856 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
858 if (mainWin->m_rtFileTabICDebug) {
859 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
860 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
861 Pmsg1(000, "%s", msg.toUtf8().data()); }
863 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
864 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
865 /* it can behave as defaulted so current of unchecked is fine */
866 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
867 fileExceptionRemove(fullPath, directory);
868 m_versionExceptionHash.remove(fullPath);
869 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
870 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
871 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
872 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
873 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
874 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
875 fileExceptionRemove(fullPath, directory);
876 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
877 /* Check dir, check version, attempt uncheck in file
878 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
879 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
880 fileExceptionRemove(fullPath, directory);
881 m_versionExceptionHash.remove(fullPath);
882 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
883 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
884 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
885 } else if (prevState != curState) {
886 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
887 /* A user did not set the check state to Partially checked, ignore if so */
888 if (curState != Qt::PartiallyChecked) {
889 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
890 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
892 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
893 fileExceptionInsert(fullPath, directory, curState);
896 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
897 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
898 m_versionExceptionHash.remove(fullPath);
902 updateFileTableChecks();
903 updateVersionTableChecks();
907 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
909 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
911 m_fileExceptionHash.insert(fullPath, state);
912 m_fileExceptionMulti.insert(direcotry, fullPath);
913 directoryIconStateInsert(fullPath, state);
917 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
919 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
921 m_fileExceptionHash.remove(fullPath);
922 /* pull the list of values in the multi */
923 QStringList fullPathList = m_fileExceptionMulti.values(directory);
924 /* get the index of the fullpath to remove */
925 int index = fullPathList.indexOf(fullPath);
927 /* remove the desired item in the list */
928 fullPathList.removeAt(index);
929 /* remove the entire list from the multi */
930 m_fileExceptionMulti.remove(directory);
931 /* readd the remaining */
932 foreach (QString fp, fullPathList) {
933 m_fileExceptionMulti.insert(directory, fp);
936 directoryIconStateRemove();
940 * Overloaded function to be called from the slot and from other places to set the state
941 * of the check marks in the version table
943 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
945 /* get the previous and current check states */
946 int row = versionTable->row(item);
947 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
948 Qt::CheckState prevState = m_versionCheckStateList[row];
949 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
950 m_versionCheckStateList[row] = curState;
952 /* deterimine the default state from the state of the file */
953 QTableWidgetItem *fileTableItem = fileTable->currentItem();
954 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
956 /* determine the default state */
957 Qt::CheckState defState;
959 defState = Qt::PartiallyChecked;
960 if (fileState == Qt::Unchecked)
961 defState = Qt::Unchecked;
964 defState = Qt::Unchecked;
966 /* determine if it is already in the versionExceptionHash */
967 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
968 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
969 QString file = fileTableItem->text();
970 QString fullPath = directory + file;
971 int thisJobNum = colZeroItem->text().toInt();
972 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
974 if (mainWin->m_rtVerTabICDebug) {
975 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
976 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
977 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
978 Pmsg1(000, "%s", msg.toUtf8().data()); }
979 /* if changed from partially checked to checked, make it unchecked */
980 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
981 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
982 fileTableItem->setCheckState(Qt::Checked);
983 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
984 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
985 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
986 fileExceptionRemove(fullPath, directory);
987 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
988 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
989 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
990 m_versionExceptionHash.remove(fullPath);
991 fileExceptionRemove(fullPath, directory);
992 } else if ((curState == Qt::Checked) && (row == 0)) {
993 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
994 m_versionExceptionHash.remove(fullPath);
995 } else if (prevState != curState) {
996 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
997 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
998 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
999 m_versionExceptionHash.insert(fullPath, thisJobNum);
1000 if (fileState != Qt::Checked) {
1001 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1002 fileExceptionInsert(fullPath, directory, curState);
1005 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1008 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1011 updateFileTableChecks();
1012 updateVersionTableChecks();
1016 * Simple function to set the check state in the file table by disconnecting the
1017 * signal/slot the setting then reconnecting the signal/slot
1019 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1021 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1022 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1023 item->setCheckState(state);
1024 if (color) item->setBackground(Qt::yellow);
1025 else item->setBackground(Qt::white);
1026 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1027 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1031 * Simple function to set the check state in the version table by disconnecting the
1032 * signal/slot the setting then reconnecting the signal/slot
1034 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1036 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1037 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1038 item->setCheckState(state);
1039 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1040 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1044 * Simple function to set the check state in the directory tree by disconnecting the
1045 * signal/slot the setting then reconnecting the signal/slot
1047 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1049 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1050 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1051 item->setCheckState(0, state);
1052 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1053 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1057 * Simplify the updating of the check state in the File table by iterating through
1058 * each item in the file table to determine it's appropriate state.
1059 * !! Will probably want to concoct a way to do this without iterating for the possibility
1060 * of the very large directories.
1062 void restoreTree::updateFileTableChecks()
1064 /* deterimine the default state from the state of the directory */
1065 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1066 Qt::CheckState dirState = dirTreeItem->checkState(0);
1068 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1070 /* Update the items in the version table */
1071 int rcnt = fileTable->rowCount();
1072 for (int row=0; row<rcnt; row++) {
1073 QTableWidgetItem* item = fileTable->item(row, 0);
1075 Qt::CheckState curState = item->checkState();
1076 Qt::CheckState newState = Qt::PartiallyChecked;
1077 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1079 /* determine if it is already in the m_fileExceptionHash */
1080 QString file = item->text();
1081 QString fullPath = dirName + file;
1082 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1083 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1085 if (hashState != 3) newState = hashState;
1087 if (mainWin->m_rtUpdateFTDebug) {
1088 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1089 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1090 Pmsg1(000, "%s", msg.toUtf8().data());
1093 bool docolor = false;
1094 if (hashJobNum != 0) docolor = true;
1095 bool isyellow = item->background().color() == QColor(Qt::yellow);
1096 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1097 fileTableDisconnectedSet(item, newState, docolor);
1098 m_fileCheckStateList[row] = newState;
1103 * Simplify the updating of the check state in the Version table by iterating through
1104 * each item in the file table to determine it's appropriate state.
1106 void restoreTree::updateVersionTableChecks()
1108 /* deterimine the default state from the state of the directory */
1109 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1110 Qt::CheckState dirState = dirTreeItem->checkState(0);
1111 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1113 /* deterimine the default state from the state of the file */
1114 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1115 Qt::CheckState fileState = fileTableItem->checkState();
1116 QString file = fileTableItem->text();
1117 QString fullPath = dirName + file;
1118 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1120 /* Update the items in the version table */
1121 int cnt = versionTable->rowCount();
1122 for (int row=0; row<cnt; row++) {
1123 QTableWidgetItem* item = versionTable->item(row, 0);
1125 Qt::CheckState curState = item->checkState();
1126 Qt::CheckState newState = Qt::Unchecked;
1128 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1129 newState = Qt::PartiallyChecked;
1130 /* determine if it is already in the versionExceptionHash */
1132 int thisJobNum = item->text().toInt();
1133 if (thisJobNum == hashJobNum)
1134 newState = Qt::Checked;
1136 if (mainWin->m_rtChecksDebug) {
1137 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1138 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1139 Pmsg1(000, "%s", msg.toUtf8().data());
1141 if (newState != curState)
1142 versionTableDisconnectedSet(item, newState);
1143 m_versionCheckStateList[row] = newState;
1148 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1150 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1154 QString fullPath = fullPath_in;
1155 QString direct, path;
1156 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1157 direct = path = fullPath;
1158 path.replace(index+1, fullPath.length()-index-1, "");
1159 direct.replace(0, index+1, "");
1161 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1162 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1163 Pmsg0(000, msg.toUtf8().data());
1166 subPaths.append(fullPath);
1171 * A Function to set the icon state and insert a record into
1172 * m_directoryIconStateHash when an exception is added by the user
1174 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1177 fullPathtoSubPaths(paths, fullPath);
1178 /* an exception that causes the item in the file table to be "Checked" has occured */
1179 if (excpState == Qt::Checked) {
1180 bool foundAsUnChecked = false;
1181 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1183 if (firstItem->checkState(0) == Qt::Unchecked)
1184 foundAsUnChecked = true;
1186 if (foundAsUnChecked) {
1187 /* as long as directory item is Unchecked, set icon state to "green check" */
1189 QListIterator<QString> siter(paths);
1190 while (siter.hasNext() && !done) {
1191 QString path = siter.next();
1192 QTreeWidgetItem *item = m_dirPaths.value(path);
1194 if (item->checkState(0) != Qt::Unchecked)
1197 directorySetIcon(1, FolderGreenChecked, path, item);
1198 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1203 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1204 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1206 QListIterator<QString> siter(paths);
1207 while (siter.hasNext() && !done) {
1208 QString path = siter.next();
1209 QTreeWidgetItem *item = m_dirPaths.value(path);
1210 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1211 if (item->checkState(0) == Qt::Checked)
1213 directorySetIcon(1, FolderGreenChecked, path, item);
1214 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1219 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1220 if (excpState == Qt::Unchecked) {
1222 QListIterator<QString> siter(paths);
1223 while (siter.hasNext() && !done) {
1224 QString path = siter.next();
1225 QTreeWidgetItem *item = m_dirPaths.value(path);
1226 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1227 if (item->checkState(0) == Qt::Checked)
1229 directorySetIcon(1, FolderWhiteChecked, path, item);
1230 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1237 * A function to set the icon state back to "folder" and to remove a record from
1238 * m_directoryIconStateHash when an exception is removed by a user.
1240 void restoreTree::directoryIconStateRemove()
1242 QHash<QString, int> shouldBeIconStateHash;
1243 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1244 /* Use iterator tera to iterate through m_fileExceptionHash */
1245 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1246 while (tera.hasNext()) {
1248 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1250 QString keyPath = tera.key();
1251 Qt::CheckState state = tera.value();
1254 fullPathtoSubPaths(paths, keyPath);
1255 /* if the state of the item in m_fileExceptionHash is checked
1256 * each of the subpaths should be "Checked Green" */
1257 if (state == Qt::Checked) {
1259 bool foundAsUnChecked = false;
1260 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1262 if (firstItem->checkState(0) == Qt::Unchecked)
1263 foundAsUnChecked = true;
1265 if (foundAsUnChecked) {
1266 /* The right most directory is Unchecked, iterate leftwards
1267 * as long as directory item is Unchecked, set icon state to "green check" */
1269 QListIterator<QString> siter(paths);
1270 while (siter.hasNext() && !done) {
1271 QString path = siter.next();
1272 QTreeWidgetItem *item = m_dirPaths.value(path);
1274 if (item->checkState(0) != Qt::Unchecked)
1277 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1278 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1284 /* The right most directory is Unchecked, iterate leftwards
1285 * until directory item is Checked, set icon state to "green check" */
1287 QListIterator<QString> siter(paths);
1288 while (siter.hasNext() && !done) {
1289 QString path = siter.next();
1290 QTreeWidgetItem *item = m_dirPaths.value(path);
1292 if (item->checkState(0) == Qt::Checked)
1294 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1299 /* if the state of the item in m_fileExceptionHash is UNChecked
1300 * each of the subpaths should be "Checked white" until the tree item
1301 * which represents that path is Qt::Checked */
1302 if (state == Qt::Unchecked) {
1304 QListIterator<QString> siter(paths);
1305 while (siter.hasNext() && !done) {
1306 QString path = siter.next();
1307 QTreeWidgetItem *item = m_dirPaths.value(path);
1309 if (item->checkState(0) == Qt::Checked)
1311 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1316 /* now iterate through m_directoryIconStateHash which are the items that are checked
1317 * and remove all of those that are not in shouldBeIconStateHash */
1318 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1319 while (iter.hasNext()) {
1321 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1323 QString keyPath = iter.key();
1324 if (shouldBeIconStateHash.value(keyPath)) {
1325 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1326 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1327 int newval = shouldBeIconStateHash.value(keyPath);
1329 newval = newval & FolderBothChecked;
1330 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1332 directorySetIcon(0, newval, keyPath, item);
1334 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1335 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1337 directorySetIcon(0, FolderBothChecked, keyPath, item);
1338 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1339 //m_directoryIconStateHash.remove(keyPath);
1344 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1346 /* we are adding a check type white or green */
1347 if (operation > 0) {
1348 /* get the old val and "bitwise OR" with the change */
1349 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1350 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1351 m_directoryIconStateHash.insert(path, newval);
1353 /* we are removing a check type white or green */
1354 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1356 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1357 m_directoryIconStateHash.remove(path);
1360 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1361 m_directoryIconStateHash.insert(path, newval);
1364 if (newval == FolderUnchecked)
1365 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1366 else if (newval == FolderGreenChecked)
1367 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1368 else if (newval == FolderWhiteChecked)
1369 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1370 else if (newval == FolderBothChecked)
1371 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1377 void restoreTree::restoreButtonPushed()
1379 /* Set progress bars and repaint */
1380 prLabel1->setVisible(true);
1381 prLabel1->setText("Task 1 of 3");
1382 prLabel2->setVisible(true);
1383 prLabel2->setText("Processing Checked directories");
1384 prBar1->setVisible(true);
1385 prBar1->setRange(0, 3);
1386 prBar1->setValue(0);
1387 prBar2->setVisible(true);
1388 prBar2->setRange(0, 0);
1390 QMultiHash<int, QString> versionFilesMulti;
1392 QHash <QString, bool> fullPathDone;
1393 QHash <QString, int> fileIndexHash;
1394 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1395 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1396 /* Use a tree widget item iterator to count directories for the progress bar */
1397 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1402 } /* while (*diterc) */
1403 prBar2->setRange(0, ditcount);
1404 prBar2->setValue(0);
1406 /* Use a tree widget item iterator filtering for Checked Items */
1407 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1409 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1410 if (mainWin->m_rtRestore1Debug)
1411 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1412 /* With a checked directory, query for the files in the directory */
1415 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1417 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1419 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1420 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1421 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1422 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1423 " AND Job.Jobid IN (" + m_jobQuery + ")"
1424 " GROUP BY Filename.Name"
1426 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1427 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1428 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1430 " Path.Path='" + directory + "'"
1431 " AND Filename.Name=t1.Filename"
1432 " AND Job.Jobid=t1.JobId"
1433 " ORDER BY Filename";
1435 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1436 QStringList results;
1437 if (m_console->sql_cmd(cmd, results)) {
1438 QStringList fieldlist;
1441 /* Iterate through the record returned from the query */
1442 foreach (QString resultline, results) {
1443 /* Iterate through fields in the record */
1445 QString fullPath = "";
1446 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1447 fieldlist = resultline.split("\t");
1450 foreach (QString field, fieldlist) {
1452 fullPath = directory + field;
1455 version = field.toInt();
1458 fileIndex = field.toInt();
1462 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1464 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1465 if (fileExcpState != Qt::Unchecked) {
1467 if (excpVersion != 0) {
1468 debugtext = QString("*E* version=%1").arg(excpVersion);
1469 version = excpVersion;
1470 fileIndex = queryFileIndex(fullPath, excpVersion);
1472 debugtext = QString("___ version=%1").arg(version);
1473 if (mainWin->m_rtRestore1Debug)
1474 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1475 fullPathDone.insert(fullPath, 1);
1476 fileIndexHash.insert(fullPath, fileIndex);
1477 versionFilesMulti.insert(version, fullPath);
1484 prBar2->setValue(ditcount);
1486 } /* while (*diter) */
1487 prBar1->setValue(1);
1488 prLabel1->setText("Task 2 of 3");
1489 prLabel2->setText("Processing Exceptions");
1490 prBar2->setRange(0, 0);
1493 /* There may be some exceptions not accounted for yet with fullPathDone */
1494 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1495 while (ftera.hasNext()) {
1497 QString fullPath = ftera.key();
1498 Qt::CheckState state = ftera.value();
1500 /* now we don't want the ones already done */
1501 if (fullPathDone.value(fullPath, 0) == 0) {
1502 int version = m_versionExceptionHash.value(fullPath, 0);
1504 QString debugtext = "";
1506 fileIndex = queryFileIndex(fullPath, version);
1507 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1509 version = mostRecentVersionfromFullPath(fullPath);
1511 fileIndex = queryFileIndex(fullPath, version);
1512 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1514 debugtext = QString("Error det vers").arg(version);
1516 if (mainWin->m_rtRestore1Debug)
1517 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1518 versionFilesMulti.insert(version, fullPath);
1520 fileIndexHash.insert(fullPath, fileIndex);
1521 } /* if fullPathDone.value(fullPath, 0) == 0 */
1522 } /* if state != 0 */
1523 } /* while ftera.hasNext */
1524 /* The progress bars for the next step */
1525 prBar1->setValue(2);
1526 prLabel1->setText("Task 3 of 3");
1527 prLabel2->setText("Filling Database Table");
1528 prBar2->setRange(0, vFMCounter);
1530 prBar2->setValue(vFMCounter);
1533 /* now for the final spit out of the versions and lists of files for each version */
1534 QHash<int, int> doneKeys;
1535 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1536 QString tempTable = "";
1538 while (vFMiter.hasNext()) {
1540 int fversion = vFMiter.key();
1541 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1542 if (doneKeys.value(fversion, 0) == 0) {
1543 if (tempTable == "") {
1544 QSettings settings("www.bacula.org", "bat");
1545 settings.beginGroup("Restore");
1546 int counter = settings.value("Counter", 1).toInt();
1547 settings.setValue("Counter", counter+1);
1548 settings.endGroup();
1549 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1550 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1551 if (mainWin->m_sqlDebug)
1552 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1553 QStringList results;
1554 if (!m_console->sql_cmd(sqlcmd, results))
1555 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1558 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1559 QStringList fullPathList = versionFilesMulti.values(fversion);
1560 /* create the command to perform the restore */
1561 foreach(QString ffullPath, fullPathList) {
1562 int fileIndex = fileIndexHash.value(ffullPath);
1563 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1564 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1565 if (mainWin->m_rtRestore3Debug)
1566 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1567 QStringList results;
1568 if (!m_console->sql_cmd(sqlcmd, results))
1569 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1570 prBar2->setValue(++vFMCounter);
1571 } /* foreach fullPathList */
1572 doneKeys.insert(fversion,1);
1573 jobList.append(fversion);
1574 } /* if (doneKeys.value(fversion, 0) == 0) */
1575 } /* while (vFMiter.hasNext()) */
1576 if (tempTable != "") {
1577 /* a table was made, lets run the job */
1578 QString jobOption = " jobid=\"";
1580 /* create a list of jobs comma separated */
1581 foreach (int job, jobList) {
1582 if (first) first = false;
1583 else jobOption += ",";
1584 jobOption += QString("%1").arg(job);
1587 QString cmd = QString("restore");
1589 " client=\"" + m_prevClientCombo + "\"" +
1590 " file=\"?" + tempTable + "\" done";
1591 if (mainWin->m_commandDebug)
1592 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1593 consoleCommand(cmd);
1595 /* turn off the progress widgets */
1596 prBar1->setVisible(false);
1597 prBar2->setVisible(false);
1598 prLabel1->setVisible(false);
1599 prLabel2->setVisible(false);
1602 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1605 QString directory, fileName;
1606 int index = m_slashregex.lastIndexIn(fullPath, -2);
1608 directory = fileName = fullPath;
1609 directory.replace(index+1, fullPath.length()-index-1, "");
1610 fileName.replace(0, index+1, "");
1612 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1613 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1614 Pmsg0(000, msg.toUtf8().data());
1616 /* so now we need the latest version from the database */
1618 "SELECT MAX(Job.JobId)"
1620 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1621 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1622 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1623 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1624 " AND Job.Jobid IN (" + m_jobQuery + ")"
1625 " AND Filename.Name='" + fileName + "'"
1626 " GROUP BY Filename.Name";
1628 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1629 QStringList results;
1630 if (m_console->sql_cmd(cmd, results)) {
1631 QStringList fieldlist;
1633 /* Iterate through the record returned from the query */
1634 foreach (QString resultline, results) {
1635 /* Iterate through fields in the record */
1637 fieldlist = resultline.split("\t");
1638 foreach (QString field, fieldlist) {
1640 qversion = field.toInt();
1647 } /* if (index != -1) */
1652 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1655 QString directory, fileName;
1656 int index = m_slashregex.lastIndexIn(fullPath, -2);
1658 directory = fileName = fullPath;
1659 directory.replace(index+1, fullPath.length()-index-1, "");
1660 fileName.replace(0, index+1, "");
1662 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1663 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1664 Pmsg0(000, msg.toUtf8().data());
1666 /* so now we need the latest version from the database */
1671 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1672 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1673 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1675 " Path.Path='" + directory + "'"
1676 " AND Filename.Name='" + fileName + "'"
1677 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1678 " GROUP BY File.FileIndex";
1680 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1681 QStringList results;
1682 if (m_console->sql_cmd(cmd, results)) {
1683 QStringList fieldlist;
1685 /* Iterate through the record returned from the query */
1686 foreach (QString resultline, results) {
1687 /* Iterate through fields in the record */
1689 fieldlist = resultline.split("\t");
1690 foreach (QString field, fieldlist) {
1692 qfileIndex = field.toInt();
1699 } /* if (index != -1) */