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(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
103 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
104 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
105 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
106 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
107 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
108 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
109 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
111 QStringList titles = QStringList() << "Directories";
112 directoryTree->setHeaderLabels(titles);
113 clientCombo->addItems(m_console->client_list);
114 fileSetCombo->addItem("Any");
115 fileSetCombo->addItems(m_console->fileset_list);
116 jobCombo->addItem("Any");
117 jobCombo->addItems(m_console->job_list);
119 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
123 * When refresh button is pushed, perform a query getting the directories and
124 * use parseDirectory and addDirectory to populate the directory tree with items.
126 void restoreTree::populateDirectoryTree()
130 directoryTree->clear();
132 fileTable->setRowCount(0);
133 fileTable->setColumnCount(0);
134 versionTable->clear();
135 versionTable->setRowCount(0);
136 versionTable->setColumnCount(0);
137 m_fileExceptionHash.clear();
138 m_fileExceptionMulti.clear();
139 m_versionExceptionHash.clear();
140 m_directoryIconStateHash.clear();
142 QString jobComboText = jobCombo->currentText();
143 QString clientComboText = clientCombo->currentText();
144 QString fileSetComboText = fileSetCombo->currentText();
145 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobComboText.toUtf8().data());
146 bool dropdownChanged = (m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText);
147 int taskcount = 2, ontask = 1;
148 if (dropdownChanged) taskcount += 1;
149 // QString taskCountString = QString("%1").arg(taskcount);
151 /* Set progress bars and repaint */
152 prBar1->setVisible(true);
153 prBar1->setRange(0,taskcount);
155 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
156 prLabel1->setVisible(true);
157 prBar2->setVisible(true);
158 prBar2->setRange(0,0);
159 prLabel2->setText("Querying Database");
160 prLabel2->setVisible(true);
163 if (dropdownChanged) {
164 m_prevJobCombo = jobComboText;
165 m_prevClientCombo = clientComboText;
166 m_prevFileSetCombo = fileSetComboText;
167 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
169 QString condition = " Client.Name='" + clientCombo->itemText(clientCombo->currentIndex()) + "'";
170 if ((jobCombo->currentIndex() >= 0) && (jobComboText != "Any")) {
171 condition.append(" AND Job.name = '" + jobComboText + "'");
173 if ((fileSetCombo->currentIndex() >= 0) && (fileSetComboText != "Any")) {
174 condition.append(" AND FileSet.FileSet='" + fileSetComboText + "'");
176 /* If Limit check box For limit by days is checked */
177 if (daysCheckBox->checkState() == Qt::Checked) {
178 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
179 QString since = stamp.toString(Qt::ISODate);
180 condition.append(" AND Job.Starttime>'" + since + "'");
183 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
184 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
185 " WHERE" + condition +
186 " AND Job.purgedfiles=0";
189 " From Job" + m_jobQueryPart;
190 /* If Limit check box for limit records returned is checked */
191 if (limitCheckBox->checkState() == Qt::Checked) {
193 limit.setNum(limitSpinBox->value());
194 m_jobQuery += " LIMIT " + limit;
197 if (mainWin->m_sqlDebug) {
198 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
200 prBar1->setValue(ontask++);
201 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
203 prBar2->setRange(0,0);
204 prLabel2->setText("Querying Jobs");
207 setJobsCheckedList();
209 setJobsCheckedList();
213 "SELECT DISTINCT Path.Path AS Path"
215 " INNER JOIN File ON (File.PathId=Path.PathId)"
216 " INNER JOIN Job ON (File.JobId=Job.JobId)"
217 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
219 if (mainWin->m_sqlDebug) {
220 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
222 prBar1->setValue(ontask++);
223 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
225 prLabel2->setText("Processing Directories");
226 QStringList directories;
227 if (m_console->sql_cmd(cmd, directories)) {
228 if (mainWin->m_miscDebug) {
229 Pmsg1(000, "Done with query %i directories\n", directories.count());
231 prBar2->setRange(0,directories.count());
233 foreach(QString directory, directories) {
235 prBar2->setValue(m_debugCnt);
236 parseDirectory(directory);
239 prBar1->setVisible(false);
240 prBar2->setVisible(false);
241 prLabel1->setVisible(false);
242 prLabel2->setVisible(false);
246 * Function to set m_jobQuery from the jobs that are checked in the table
249 void restoreTree::setJobsCheckedList()
251 m_JobsCheckedList = "";
253 /* Update the items in the version table */
254 int cnt = jobTable->rowCount();
255 for (int row=0; row<cnt; row++) {
256 QTableWidgetItem* jobItem = jobTable->item(row, 0);
257 if (jobItem->checkState() == Qt::Checked) {
259 m_JobsCheckedList += ",";
260 m_JobsCheckedList += jobItem->text();
262 jobItem->setBackground(Qt::green);
264 jobItem->setBackground(Qt::gray);
266 m_jobQuery = m_JobsCheckedList;
270 * Function to parse a directory into all possible subdirectories, then add to
273 void restoreTree::parseDirectory(QString &dir_in)
275 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
276 * instead of printing out what could potentially a whole bunch */
279 /* Clean up the directory string remove some funny char after last '/' */
280 QRegExp rgx("[^/]$");
281 int lastslash = rgx.indexIn(dir_in);
282 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
283 if ((mainWin->m_miscDebug) && (m_debugTrap))
284 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
286 /* split and add if not in yet */
287 QString direct, path;
290 QStringList pathAfter, dirAfter;
291 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
292 * if not added into tree, then try /etc/ and somedir/ if not added, then try
293 * / and etc/ . That should succeed, then add the ones that failed in reverse */
294 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
295 direct = path = dir_in;
296 path.replace(index+1, dir_in.length()-index-1,"");
297 direct.replace(0, index+1, "");
298 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
299 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
300 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
301 Pmsg0(000, msg.toUtf8().data());
303 if (addDirectory(path, direct)) done = true;
305 if ((mainWin->m_miscDebug) && (m_debugTrap))
306 Pmsg0(000, "Saving for later\n");
307 pathAfter.prepend(path);
308 dirAfter.prepend(direct);
313 for (int k=0; k<pathAfter.count(); k++) {
314 if (addDirectory(pathAfter[k], dirAfter[k]))
315 if ((mainWin->m_miscDebug) && (m_debugTrap))
316 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
318 if ((mainWin->m_miscDebug) && (m_debugTrap))
319 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
324 * Function called from fill directory when a directory is found to see if this
325 * directory exists in the directory pane and then add it to the directory pane
327 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
329 QString newdir = newdirr;
330 QString fullPath = m_cwd + newdirr;
331 bool ok = true, added = false;
333 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
334 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
337 Pmsg0(000, msg.toUtf8().data());
341 /* add unix '/' directory first */
342 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
344 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
346 item->setText(0, text.toUtf8().data());
347 item->setData(0, Qt::UserRole, QVariant(text));
348 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
349 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
350 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
351 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
353 m_dirPaths.insert(text, item);
355 /* no need to check for windows drive if unix */
356 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
357 /* this is a windows drive add the base widget */
358 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
359 item->setText(0, m_cwd);
360 item->setData(0, Qt::UserRole, QVariant(fullPath));
361 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
362 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
363 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
364 Pmsg0(000, "Added Base \"letter\":/\n");
366 m_dirPaths.insert(m_cwd, item);
370 /* is it already existent ?? */
371 if (!m_dirPaths.contains(fullPath)) {
372 QTreeWidgetItem *item = NULL;
373 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
375 /* new directories to add */
376 item = new QTreeWidgetItem(parent);
377 item->setText(0, newdir.toUtf8().data());
378 item->setData(0, Qt::UserRole, QVariant(fullPath));
379 item->setCheckState(0, Qt::Unchecked);
380 /* Store the current state of the check status in column 1, which at
381 * this point has no text*/
382 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
385 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
386 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
389 Pmsg0(000, msg.toUtf8().data());
392 /* insert into hash */
394 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
395 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
397 m_dirPaths.insert(fullPath, item);
405 * Virtual function which is called when this page is visible on the stack
407 void restoreTree::currentStackItem()
410 if (!m_console->preventInUseConnect())
418 * Populate the tree when refresh button pushed.
420 void restoreTree::refreshButtonPushed()
422 populateDirectoryTree();
426 * Set the values of non-job combo boxes to the job defaults
428 void restoreTree::jobComboChanged(int)
430 if (jobCombo->currentText() == "Any") {
431 fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
434 job_defaults job_defs;
437 job_defs.job_name = jobCombo->currentText();
438 if (m_console->get_job_defaults(job_defs)) {
439 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
440 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
445 * Function to populate the file list table
447 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
452 m_fileCheckStateList.clear();
453 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
454 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
455 QBrush blackBrush(Qt::black);
456 QString directory = item->data(0, Qt::UserRole).toString();
457 directoryLabel->setText("Present Working Directory : " + directory);
459 "SELECT DISTINCT Filename.Name AS FileName"
461 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
462 " INNER JOIN Path ON (Path.PathId=File.PathId)"
463 " INNER JOIN Job ON (File.JobId=Job.JobId)"
464 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
465 " AND Job.Jobid IN (" + m_jobQuery + ")"
466 " ORDER BY FileName";
468 QStringList headerlist = (QStringList() << "File Name");
470 /* Also clear the version table here */
471 versionTable->clear();
472 versionFileLabel->setText("");
473 versionTable->setRowCount(0);
474 versionTable->setColumnCount(0);
475 fileTable->setColumnCount(headerlist.size());
476 fileTable->setHorizontalHeaderLabels(headerlist);
478 if (mainWin->m_sqlDebug) {
479 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
482 if (m_console->sql_cmd(cmd, results)) {
484 QTableWidgetItem* tableItem;
486 QStringList fieldlist;
487 fileTable->setRowCount(results.size());
490 /* Iterate through the record returned from the query */
491 foreach (QString resultline, results) {
492 /* Iterate through fields in the record */
494 fieldlist = resultline.split("\t");
495 foreach (field, fieldlist) {
496 field = field.trimmed(); /* strip leading & trailing spaces */
497 tableItem = new QTableWidgetItem(field, 1);
498 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
499 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
500 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
501 tableItem->setForeground(blackBrush);
502 /* Just in case a column ever gets added */
504 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
505 tableItem->setFlags(flag);
506 tableItem->setData(Qt::UserRole, QVariant(directory));
507 fileTable->setItem(row, column, tableItem);
508 m_fileCheckStateList.append(Qt::Unchecked);
509 tableItem->setCheckState(Qt::Unchecked);
515 fileTable->setRowCount(row);
517 fileTable->resizeColumnsToContents();
518 fileTable->resizeRowsToContents();
519 fileTable->verticalHeader()->hide();
520 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
521 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
522 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
523 updateFileTableChecks();
527 * Function to populate the version table
529 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
531 if (fileTableItem == NULL)
534 m_versionCheckStateList.clear();
535 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
536 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
538 QString file = fileTableItem->text();
539 versionFileLabel->setText(file);
540 QString directory = fileTableItem->data(Qt::UserRole).toString();
542 QBrush blackBrush(Qt::black);
544 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
546 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
547 " INNER JOIN Path ON (Path.PathId=File.PathId)"
548 " INNER JOIN Job ON (File.JobId=Job.JobId)"
549 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
550 " AND Job.Jobid IN (" + m_jobQuery + ")"
551 " ORDER BY Job.EndTime DESC";
553 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
554 versionTable->clear();
555 versionTable->setColumnCount(headerlist.size());
556 versionTable->setHorizontalHeaderLabels(headerlist);
558 if (mainWin->m_sqlDebug) {
559 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
562 if (m_console->sql_cmd(cmd, results)) {
564 QTableWidgetItem* tableItem;
566 QStringList fieldlist;
567 versionTable->setRowCount(results.size());
570 /* Iterate through the record returned from the query */
571 foreach (QString resultline, results) {
572 fieldlist = resultline.split("\t");
574 /* remove directory */
575 if (fieldlist[0].trimmed() != "") {
576 /* Iterate through fields in the record */
577 foreach (field, fieldlist) {
578 field = field.trimmed(); /* strip leading & trailing spaces */
579 tableItem = new QTableWidgetItem(field, 1);
580 tableItem->setFlags(0);
581 tableItem->setForeground(blackBrush);
582 tableItem->setData(Qt::UserRole, QVariant(directory));
583 versionTable->setItem(row, column, tableItem);
586 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
587 tableItem->setFlags(flag);
588 m_versionCheckStateList.append(Qt::Unchecked);
589 tableItem->setCheckState(Qt::Unchecked);
597 versionTable->resizeColumnsToContents();
598 versionTable->resizeRowsToContents();
599 versionTable->verticalHeader()->hide();
600 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
601 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
602 updateVersionTableChecks();
606 * Save user settings associated with this page
608 void restoreTree::writeSettings()
610 QSettings settings(m_console->m_dir->name(), "bat");
611 settings.beginGroup("RestoreTree");
612 settings.setValue("splitterSizes", splitter->saveState());
617 * Read and restore user settings associated with this page
619 void restoreTree::readSettings()
621 QSettings settings(m_console->m_dir->name(), "bat");
622 settings.beginGroup("RestoreTree");
623 splitter->restoreState(settings.value("splitterSizes").toByteArray());
628 * This is a funcion to accomplish the one thing I struggled to figure out what
629 * was taking so long. It add the icons, but after the tree is made. Seemed to
630 * work fast after changing from svg to png file for graphic.
632 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
634 int childCount = item->childCount();
635 for (int i=0; i<childCount; i++) {
636 QTreeWidgetItem *child = item->child(i);
637 if (child->icon(0).isNull())
638 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
643 * I wanted a table to show what jobs meet the criterion and are being used to
644 * populate the directory tree and file and version tables.
646 void restoreTree::populateJobTable()
648 QBrush blackBrush(Qt::black);
649 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
651 jobTable->setColumnCount(headerlist.size());
652 jobTable->setHorizontalHeaderLabels(headerlist);
654 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
655 " FROM Job" + m_jobQueryPart +
656 " ORDER BY Job.EndTime DESC";
657 /* If Limit check box for limit records returned is checked */
658 if (limitCheckBox->checkState() == Qt::Checked) {
660 limit.setNum(limitSpinBox->value());
661 jobQuery += " LIMIT " + limit;
663 if (mainWin->m_sqlDebug) {
664 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
668 if (m_console->sql_cmd(jobQuery, results)) {
670 QTableWidgetItem* tableItem;
672 QStringList fieldlist;
673 jobTable->setRowCount(results.size());
676 /* Iterate through the record returned from the query */
677 foreach (QString resultline, results) {
678 fieldlist = resultline.split("\t");
680 /* remove directory */
681 if (fieldlist[0].trimmed() != "") {
682 /* Iterate through fields in the record */
683 foreach (field, fieldlist) {
684 field = field.trimmed(); /* strip leading & trailing spaces */
685 tableItem = new QTableWidgetItem(field, 1);
686 tableItem->setFlags(0);
687 tableItem->setForeground(blackBrush);
688 jobTable->setItem(row, column, tableItem);
690 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
691 tableItem->setFlags(flag);
692 tableItem->setCheckState(Qt::Checked);
693 tableItem->setBackground(Qt::green);
701 jobTable->resizeColumnsToContents();
702 jobTable->resizeRowsToContents();
703 jobTable->verticalHeader()->hide();
707 * When a directory item is "changed" check the state of the checkable item
708 * to see if it is different than what it was which is stored in Qt::UserRole
709 * of the 2nd column, column 1, of the tree widget.
711 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
713 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
714 Qt::CheckState curState = item->checkState(0);
715 QTreeWidgetItem* parent = item->parent();
716 Qt::CheckState parState;
717 if (parent) parState = parent->checkState(0);
718 else parState = (Qt::CheckState)3;
719 if (mainWin->m_rtDirICDebug) {
720 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
721 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
722 Pmsg1(000, "%s", msg.toUtf8().data()); }
723 /* I only care when the check state changes */
724 if (prevState == curState) {
725 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
729 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
730 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
731 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
732 curState = Qt::PartiallyChecked;
734 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
735 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
736 directoryTreeDisconnectedSet(item, Qt::Unchecked);
737 curState = Qt::Unchecked;
739 if (mainWin->m_rtDirICDebug) {
740 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
741 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
742 Pmsg1(000, "%s", msg.toUtf8().data()); }
744 item->setData(1, Qt::UserRole, QVariant(curState));
745 Qt::CheckState childState = curState;
746 if (childState == Qt::Checked)
747 childState = Qt::PartiallyChecked;
748 setCheckofChildren(item, childState);
750 /* Remove items from the exception lists. The multi exception list is my index
751 * of what exceptions can be removed when the directory is known*/
752 QString directory = item->data(0, Qt::UserRole).toString();
753 QStringList fullPathList = m_fileExceptionMulti.values(directory);
754 int fullPathListCount = fullPathList.count();
755 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
756 foreach (QString fullPath, fullPathList) {
757 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
758 * which will match no Qt::xxx values */
759 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
760 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
761 if (hashState == Qt::Unchecked) {
762 fileExceptionRemove(fullPath, directory);
763 m_versionExceptionHash.remove(fullPath);
764 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
766 if (hashState == Qt::Checked) {
767 fileExceptionRemove(fullPath, directory);
768 m_versionExceptionHash.remove(fullPath);
769 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
773 if (item == directoryTree->currentItem()) {
774 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
775 updateFileTableChecks();
776 versionTable->clear();
777 versionTable->setRowCount(0);
778 versionTable->setColumnCount(0);
780 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
784 * When a directory item check state is changed, this function iterates through
785 * all subdirectories and sets all to the passed state, which is either partially
786 * checked or unchecked.
788 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
791 childCount = item->childCount();
792 for (int i=0; i<childCount; i++) {
793 QTreeWidgetItem *child = item->child(i);
794 child->setData(1, Qt::UserRole, QVariant(state));
795 child->setCheckState(0, state);
796 setCheckofChildren(child, state);
801 * When a File Table Item is "changed" check to see if the state of the checkable
802 * item has changed which is stored in m_fileCheckStateList
803 * If changed store in a hash m_fileExceptionHash that whether this file should be
805 * Called as a slot, connected after populated (after directory current changed called)
807 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
809 /* get the previous and current check states */
810 int row = fileTable->row(item);
811 Qt::CheckState prevState;
812 /* prevent a segfault */
813 prevState = m_fileCheckStateList[row];
814 Qt::CheckState curState = item->checkState();
816 /* deterimine the default state from the state of the directory */
817 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
818 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
819 Qt::CheckState defState = Qt::PartiallyChecked;
820 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
822 /* determine if it is already in the m_fileExceptionHash */
823 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
824 QString file = item->text();
825 QString fullPath = directory + file;
826 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
827 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
829 if (mainWin->m_rtFileTabICDebug) {
830 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
831 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
832 Pmsg1(000, "%s", msg.toUtf8().data()); }
834 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
835 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
836 /* it can behave as defaulted so current of unchecked is fine */
837 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
838 fileExceptionRemove(fullPath, directory);
839 m_versionExceptionHash.remove(fullPath);
840 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
841 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
842 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
843 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
844 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
845 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
846 fileExceptionRemove(fullPath, directory);
847 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
848 /* Check dir, check version, attempt uncheck in file
849 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
850 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
851 fileExceptionRemove(fullPath, directory);
852 m_versionExceptionHash.remove(fullPath);
853 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
854 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
855 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
856 } else if (prevState != curState) {
857 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
858 /* A user did not set the check state to Partially checked, ignore if so */
859 if (curState != Qt::PartiallyChecked) {
860 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
861 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
863 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
864 fileExceptionInsert(fullPath, directory, curState);
867 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
868 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
869 m_versionExceptionHash.remove(fullPath);
873 updateFileTableChecks();
874 updateVersionTableChecks();
878 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
880 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
882 m_fileExceptionHash.insert(fullPath, state);
883 m_fileExceptionMulti.insert(direcotry, fullPath);
884 directoryIconStateInsert(fullPath, state);
888 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
890 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
892 m_fileExceptionHash.remove(fullPath);
893 /* pull the list of values in the multi */
894 QStringList fullPathList = m_fileExceptionMulti.values(directory);
895 /* get the index of the fullpath to remove */
896 int index = fullPathList.indexOf(fullPath);
898 /* remove the desired item in the list */
899 fullPathList.removeAt(index);
900 /* remove the entire list from the multi */
901 m_fileExceptionMulti.remove(directory);
902 /* readd the remaining */
903 foreach (QString fp, fullPathList) {
904 m_fileExceptionMulti.insert(directory, fp);
907 directoryIconStateRemove();
911 * Overloaded function to be called from the slot and from other places to set the state
912 * of the check marks in the version table
914 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
916 /* get the previous and current check states */
917 int row = versionTable->row(item);
918 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
919 Qt::CheckState prevState = m_versionCheckStateList[row];
920 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
921 m_versionCheckStateList[row] = curState;
923 /* deterimine the default state from the state of the file */
924 QTableWidgetItem *fileTableItem = fileTable->currentItem();
925 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
927 /* determine the default state */
928 Qt::CheckState defState;
930 defState = Qt::PartiallyChecked;
931 if (fileState == Qt::Unchecked)
932 defState = Qt::Unchecked;
935 defState = Qt::Unchecked;
937 /* determine if it is already in the versionExceptionHash */
938 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
939 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
940 QString file = fileTableItem->text();
941 QString fullPath = directory + file;
942 int thisJobNum = colZeroItem->text().toInt();
943 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
945 if (mainWin->m_rtVerTabICDebug) {
946 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
947 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
948 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
949 Pmsg1(000, "%s", msg.toUtf8().data()); }
950 /* if changed from partially checked to checked, make it unchecked */
951 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
952 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
953 fileTableItem->setCheckState(Qt::Checked);
954 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
955 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
956 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
957 fileExceptionRemove(fullPath, directory);
958 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
959 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
960 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
961 m_versionExceptionHash.remove(fullPath);
962 fileExceptionRemove(fullPath, directory);
963 } else if ((curState == Qt::Checked) && (row == 0)) {
964 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
965 m_versionExceptionHash.remove(fullPath);
966 } else if (prevState != curState) {
967 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
968 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
969 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
970 m_versionExceptionHash.insert(fullPath, thisJobNum);
971 if (fileState != Qt::Checked) {
972 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
973 fileExceptionInsert(fullPath, directory, curState);
976 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
979 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
982 updateFileTableChecks();
983 updateVersionTableChecks();
987 * Simple function to set the check state in the file table by disconnecting the
988 * signal/slot the setting then reconnecting the signal/slot
990 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
992 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
993 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
994 item->setCheckState(state);
995 if (color) item->setBackground(Qt::yellow);
996 else item->setBackground(Qt::white);
997 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
998 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1002 * Simple function to set the check state in the version table by disconnecting the
1003 * signal/slot the setting then reconnecting the signal/slot
1005 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1007 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1008 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1009 item->setCheckState(state);
1010 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1011 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1015 * Simple function to set the check state in the directory tree by disconnecting the
1016 * signal/slot the setting then reconnecting the signal/slot
1018 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1020 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1021 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1022 item->setCheckState(0, state);
1023 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1024 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1028 * Simplify the updating of the check state in the File table by iterating through
1029 * each item in the file table to determine it's appropriate state.
1030 * !! Will probably want to concoct a way to do this without iterating for the possibility
1031 * of the very large directories.
1033 void restoreTree::updateFileTableChecks()
1035 /* deterimine the default state from the state of the directory */
1036 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1037 Qt::CheckState dirState = dirTreeItem->checkState(0);
1039 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1041 /* Update the items in the version table */
1042 int rcnt = fileTable->rowCount();
1043 for (int row=0; row<rcnt; row++) {
1044 QTableWidgetItem* item = fileTable->item(row, 0);
1046 Qt::CheckState curState = item->checkState();
1047 Qt::CheckState newState = Qt::PartiallyChecked;
1048 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1050 /* determine if it is already in the m_fileExceptionHash */
1051 QString file = item->text();
1052 QString fullPath = dirName + file;
1053 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1054 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1056 if (hashState != 3) newState = hashState;
1058 if (mainWin->m_rtUpdateFTDebug) {
1059 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1060 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1061 Pmsg1(000, "%s", msg.toUtf8().data());
1064 bool docolor = false;
1065 if (hashJobNum != 0) docolor = true;
1066 bool isyellow = item->background().color() == QColor(Qt::yellow);
1067 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1068 fileTableDisconnectedSet(item, newState, docolor);
1069 m_fileCheckStateList[row] = newState;
1074 * Simplify the updating of the check state in the Version table by iterating through
1075 * each item in the file table to determine it's appropriate state.
1077 void restoreTree::updateVersionTableChecks()
1079 /* deterimine the default state from the state of the directory */
1080 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1081 Qt::CheckState dirState = dirTreeItem->checkState(0);
1082 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1084 /* deterimine the default state from the state of the file */
1085 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1086 Qt::CheckState fileState = fileTableItem->checkState();
1087 QString file = fileTableItem->text();
1088 QString fullPath = dirName + file;
1089 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1091 /* Update the items in the version table */
1092 int cnt = versionTable->rowCount();
1093 for (int row=0; row<cnt; row++) {
1094 QTableWidgetItem* item = versionTable->item(row, 0);
1096 Qt::CheckState curState = item->checkState();
1097 Qt::CheckState newState = Qt::Unchecked;
1099 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1100 newState = Qt::PartiallyChecked;
1101 /* determine if it is already in the versionExceptionHash */
1103 int thisJobNum = item->text().toInt();
1104 if (thisJobNum == hashJobNum)
1105 newState = Qt::Checked;
1107 if (mainWin->m_rtChecksDebug) {
1108 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1109 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1110 Pmsg1(000, "%s", msg.toUtf8().data());
1112 if (newState != curState)
1113 versionTableDisconnectedSet(item, newState);
1114 m_versionCheckStateList[row] = newState;
1119 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1121 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1125 QString fullPath = fullPath_in;
1126 QString direct, path;
1127 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1128 direct = path = fullPath;
1129 path.replace(index+1, fullPath.length()-index-1, "");
1130 direct.replace(0, index+1, "");
1132 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1133 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1134 Pmsg0(000, msg.toUtf8().data());
1137 subPaths.append(fullPath);
1142 * A Function to set the icon state and insert a record into
1143 * m_directoryIconStateHash when an exception is added by the user
1145 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1148 fullPathtoSubPaths(paths, fullPath);
1149 /* an exception that causes the item in the file table to be "Checked" has occured */
1150 if (excpState == Qt::Checked) {
1151 bool foundAsUnChecked = false;
1152 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1154 if (firstItem->checkState(0) == Qt::Unchecked)
1155 foundAsUnChecked = true;
1157 if (foundAsUnChecked) {
1158 /* as long as directory item is Unchecked, set icon state to "green check" */
1160 QListIterator<QString> siter(paths);
1161 while (siter.hasNext() && !done) {
1162 QString path = siter.next();
1163 QTreeWidgetItem *item = m_dirPaths.value(path);
1165 if (item->checkState(0) != Qt::Unchecked)
1168 directorySetIcon(1, FolderGreenChecked, path, item);
1169 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1174 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1175 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1177 QListIterator<QString> siter(paths);
1178 while (siter.hasNext() && !done) {
1179 QString path = siter.next();
1180 QTreeWidgetItem *item = m_dirPaths.value(path);
1181 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1182 if (item->checkState(0) == Qt::Checked)
1184 directorySetIcon(1, FolderGreenChecked, path, item);
1185 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1190 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1191 if (excpState == Qt::Unchecked) {
1193 QListIterator<QString> siter(paths);
1194 while (siter.hasNext() && !done) {
1195 QString path = siter.next();
1196 QTreeWidgetItem *item = m_dirPaths.value(path);
1197 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1198 if (item->checkState(0) == Qt::Checked)
1200 directorySetIcon(1, FolderWhiteChecked, path, item);
1201 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1208 * A function to set the icon state back to "folder" and to remove a record from
1209 * m_directoryIconStateHash when an exception is removed by a user.
1211 void restoreTree::directoryIconStateRemove()
1213 QHash<QString, int> shouldBeIconStateHash;
1214 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1215 /* Use iterator tera to iterate through m_fileExceptionHash */
1216 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1217 while (tera.hasNext()) {
1219 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1221 QString keyPath = tera.key();
1222 Qt::CheckState state = tera.value();
1225 fullPathtoSubPaths(paths, keyPath);
1226 /* if the state of the item in m_fileExceptionHash is checked
1227 * each of the subpaths should be "Checked Green" */
1228 if (state == Qt::Checked) {
1230 bool foundAsUnChecked = false;
1231 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1233 if (firstItem->checkState(0) == Qt::Unchecked)
1234 foundAsUnChecked = true;
1236 if (foundAsUnChecked) {
1237 /* The right most directory is Unchecked, iterate leftwards
1238 * as long as directory item is Unchecked, set icon state to "green check" */
1240 QListIterator<QString> siter(paths);
1241 while (siter.hasNext() && !done) {
1242 QString path = siter.next();
1243 QTreeWidgetItem *item = m_dirPaths.value(path);
1245 if (item->checkState(0) != Qt::Unchecked)
1248 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1249 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1255 /* The right most directory is Unchecked, iterate leftwards
1256 * until directory item is Checked, set icon state to "green check" */
1258 QListIterator<QString> siter(paths);
1259 while (siter.hasNext() && !done) {
1260 QString path = siter.next();
1261 QTreeWidgetItem *item = m_dirPaths.value(path);
1263 if (item->checkState(0) == Qt::Checked)
1265 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1270 /* if the state of the item in m_fileExceptionHash is UNChecked
1271 * each of the subpaths should be "Checked white" until the tree item
1272 * which represents that path is Qt::Checked */
1273 if (state == Qt::Unchecked) {
1275 QListIterator<QString> siter(paths);
1276 while (siter.hasNext() && !done) {
1277 QString path = siter.next();
1278 QTreeWidgetItem *item = m_dirPaths.value(path);
1280 if (item->checkState(0) == Qt::Checked)
1282 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1287 /* now iterate through m_directoryIconStateHash which are the items that are checked
1288 * and remove all of those that are not in shouldBeIconStateHash */
1289 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1290 while (iter.hasNext()) {
1292 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1294 QString keyPath = iter.key();
1295 if (shouldBeIconStateHash.value(keyPath)) {
1296 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1297 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1298 int newval = shouldBeIconStateHash.value(keyPath);
1300 newval = newval & FolderBothChecked;
1301 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1303 directorySetIcon(0, newval, keyPath, item);
1305 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1306 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1308 directorySetIcon(0, FolderBothChecked, keyPath, item);
1309 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1310 //m_directoryIconStateHash.remove(keyPath);
1315 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1317 /* we are adding a check type white or green */
1318 if (operation > 0) {
1319 /* get the old val and "bitwise OR" with the change */
1320 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1321 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1322 m_directoryIconStateHash.insert(path, newval);
1324 /* we are removing a check type white or green */
1325 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1327 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1328 m_directoryIconStateHash.remove(path);
1331 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1332 m_directoryIconStateHash.insert(path, newval);
1335 if (newval == FolderUnchecked)
1336 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1337 else if (newval == FolderGreenChecked)
1338 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1339 else if (newval == FolderWhiteChecked)
1340 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1341 else if (newval == FolderBothChecked)
1342 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1348 void restoreTree::restoreButtonPushed()
1350 /* Set progress bars and repaint */
1351 prLabel1->setVisible(true);
1352 prLabel1->setText("Task 1 of 3");
1353 prLabel2->setVisible(true);
1354 prLabel2->setText("Processing Checked directories");
1355 prBar1->setVisible(true);
1356 prBar1->setRange(0, 3);
1357 prBar1->setValue(0);
1358 prBar2->setVisible(true);
1359 prBar2->setRange(0, 0);
1361 QMultiHash<int, QString> versionFilesMulti;
1363 QHash <QString, bool> fullPathDone;
1364 QHash <QString, int> fileIndexHash;
1365 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1366 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1367 /* Use a tree widget item iterator to count directories for the progress bar */
1368 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1373 } /* while (*diterc) */
1374 prBar2->setRange(0, ditcount);
1375 prBar2->setValue(0);
1377 /* Use a tree widget item iterator filtering for Checked Items */
1378 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1380 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1381 if (mainWin->m_rtRestore1Debug)
1382 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1383 /* With a checked directory, query for the files in the directory */
1386 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1388 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1390 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1391 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1392 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1393 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1394 " AND Job.Jobid IN (" + m_jobQuery + ")"
1395 " GROUP BY Filename.Name"
1397 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1398 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1399 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1401 " Path.Path='" + directory + "'"
1402 " AND Filename.Name=t1.Filename"
1403 " AND Job.Jobid=t1.JobId"
1404 " ORDER BY Filename";
1406 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1407 QStringList results;
1408 if (m_console->sql_cmd(cmd, results)) {
1409 QStringList fieldlist;
1412 /* Iterate through the record returned from the query */
1413 foreach (QString resultline, results) {
1414 /* Iterate through fields in the record */
1416 QString fullPath = "";
1417 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1418 fieldlist = resultline.split("\t");
1421 foreach (QString field, fieldlist) {
1423 fullPath = directory + field;
1426 version = field.toInt();
1429 fileIndex = field.toInt();
1433 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1435 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1436 if (fileExcpState != Qt::Unchecked) {
1438 if (excpVersion != 0) {
1439 debugtext = QString("*E* version=%1").arg(excpVersion);
1440 version = excpVersion;
1441 fileIndex = queryFileIndex(fullPath, excpVersion);
1443 debugtext = QString("___ version=%1").arg(version);
1444 if (mainWin->m_rtRestore1Debug)
1445 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1446 fullPathDone.insert(fullPath, 1);
1447 fileIndexHash.insert(fullPath, fileIndex);
1448 versionFilesMulti.insert(version, fullPath);
1455 prBar2->setValue(ditcount);
1457 } /* while (*diter) */
1458 prBar1->setValue(1);
1459 prLabel1->setText("Task 2 of 3");
1460 prLabel2->setText("Processing Exceptions");
1461 prBar2->setRange(0, 0);
1464 /* There may be some exceptions not accounted for yet with fullPathDone */
1465 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1466 while (ftera.hasNext()) {
1468 QString fullPath = ftera.key();
1469 Qt::CheckState state = ftera.value();
1471 /* now we don't want the ones already done */
1472 if (fullPathDone.value(fullPath, 0) == 0) {
1473 int version = m_versionExceptionHash.value(fullPath, 0);
1475 QString debugtext = "";
1477 fileIndex = queryFileIndex(fullPath, version);
1478 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1480 version = mostRecentVersionfromFullPath(fullPath);
1482 fileIndex = queryFileIndex(fullPath, version);
1483 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1485 debugtext = QString("Error det vers").arg(version);
1487 if (mainWin->m_rtRestore1Debug)
1488 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1489 versionFilesMulti.insert(version, fullPath);
1491 fileIndexHash.insert(fullPath, fileIndex);
1492 } /* if fullPathDone.value(fullPath, 0) == 0 */
1493 } /* if state != 0 */
1494 } /* while ftera.hasNext */
1495 /* The progress bars for the next step */
1496 prBar1->setValue(2);
1497 prLabel1->setText("Task 3 of 3");
1498 prLabel2->setText("Filling Database Table");
1499 prBar2->setRange(0, vFMCounter);
1501 prBar2->setValue(vFMCounter);
1504 /* now for the final spit out of the versions and lists of files for each version */
1505 QHash<int, int> doneKeys;
1506 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1507 QString tempTable = "";
1509 while (vFMiter.hasNext()) {
1511 int fversion = vFMiter.key();
1512 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1513 if (doneKeys.value(fversion, 0) == 0) {
1514 if (tempTable == "") {
1515 QSettings settings("www.bacula.org", "bat");
1516 settings.beginGroup("Restore");
1517 int counter = settings.value("Counter", 1).toInt();
1518 settings.setValue("Counter", counter+1);
1519 settings.endGroup();
1520 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1521 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1522 if (mainWin->m_sqlDebug)
1523 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1524 QStringList results;
1525 if (!m_console->sql_cmd(sqlcmd, results))
1526 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1529 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1530 QStringList fullPathList = versionFilesMulti.values(fversion);
1531 /* create the command to perform the restore */
1532 foreach(QString ffullPath, fullPathList) {
1533 int fileIndex = fileIndexHash.value(ffullPath);
1534 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1535 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1536 if (mainWin->m_rtRestore3Debug)
1537 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1538 QStringList results;
1539 if (!m_console->sql_cmd(sqlcmd, results))
1540 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1541 prBar2->setValue(++vFMCounter);
1542 } /* foreach fullPathList */
1543 doneKeys.insert(fversion,1);
1544 jobList.append(fversion);
1545 } /* if (doneKeys.value(fversion, 0) == 0) */
1546 } /* while (vFMiter.hasNext()) */
1547 if (tempTable != "") {
1548 /* a table was made, lets run the job */
1549 QString jobOption = " jobid=\"";
1551 /* create a list of jobs comma separated */
1552 foreach (int job, jobList) {
1553 if (first) first = false;
1554 else jobOption += ",";
1555 jobOption += QString("%1").arg(job);
1558 QString cmd = QString("restore");
1560 " file=\"?" + tempTable + "\" done";
1561 if (mainWin->m_commandDebug)
1562 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1563 consoleCommand(cmd);
1565 /* turn off the progress widgets */
1566 prBar1->setVisible(false);
1567 prBar2->setVisible(false);
1568 prLabel1->setVisible(false);
1569 prLabel2->setVisible(false);
1572 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1575 QString directory, fileName;
1576 int index = m_slashregex.lastIndexIn(fullPath, -2);
1578 directory = fileName = fullPath;
1579 directory.replace(index+1, fullPath.length()-index-1, "");
1580 fileName.replace(0, index+1, "");
1582 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1583 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1584 Pmsg0(000, msg.toUtf8().data());
1586 /* so now we need the latest version from the database */
1588 "SELECT MAX(Job.JobId)"
1590 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1591 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1592 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1593 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1594 " AND Job.Jobid IN (" + m_jobQuery + ")"
1595 " AND Filename.Name='" + fileName + "'"
1596 " GROUP BY Filename.Name";
1598 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1599 QStringList results;
1600 if (m_console->sql_cmd(cmd, results)) {
1601 QStringList fieldlist;
1603 /* Iterate through the record returned from the query */
1604 foreach (QString resultline, results) {
1605 /* Iterate through fields in the record */
1607 fieldlist = resultline.split("\t");
1608 foreach (QString field, fieldlist) {
1610 qversion = field.toInt();
1617 } /* if (index != -1) */
1622 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1625 QString directory, fileName;
1626 int index = m_slashregex.lastIndexIn(fullPath, -2);
1628 directory = fileName = fullPath;
1629 directory.replace(index+1, fullPath.length()-index-1, "");
1630 fileName.replace(0, index+1, "");
1632 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1633 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1634 Pmsg0(000, msg.toUtf8().data());
1636 /* so now we need the latest version from the database */
1641 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1642 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1643 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1645 " Path.Path='" + directory + "'"
1646 " AND Filename.Name='" + fileName + "'"
1647 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1648 " GROUP BY File.FileIndex";
1650 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1651 QStringList results;
1652 if (m_console->sql_cmd(cmd, results)) {
1653 QStringList fieldlist;
1655 /* Iterate through the record returned from the query */
1656 foreach (QString resultline, results) {
1657 /* Iterate through fields in the record */
1659 fieldlist = resultline.split("\t");
1660 foreach (QString field, fieldlist) {
1662 qfileIndex = field.toInt();
1669 } /* if (index != -1) */