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("/");
60 /* progress widgets */
61 prBar1->setVisible(false);
62 prBar2->setVisible(false);
63 prLabel1->setVisible(false);
64 prLabel2->setVisible(false);
67 restoreTree::~restoreTree()
73 * Called from the constructor to set up the page widgets and connections.
75 void restoreTree::setupPage()
77 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
78 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
79 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
80 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
81 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
82 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
83 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
84 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
85 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
86 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
87 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
89 QStringList titles = QStringList() << "Directories";
90 directoryTree->setHeaderLabels(titles);
91 clientCombo->addItems(m_console->client_list);
92 fileSetCombo->addItem("Any");
93 fileSetCombo->addItems(m_console->fileset_list);
94 jobCombo->addItems(m_console->job_list);
96 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
100 * When refresh button is pushed, perform a query getting the directories and
101 * use parseDirectory and addDirectory to populate the directory tree with items.
103 void restoreTree::populateDirectoryTree()
107 directoryTree->clear();
109 fileTable->setRowCount(0);
110 fileTable->setColumnCount(0);
111 versionTable->clear();
112 versionTable->setRowCount(0);
113 versionTable->setColumnCount(0);
114 m_fileExceptionHash.clear();
115 m_fileExceptionMulti.clear();
116 m_versionExceptionHash.clear();
117 m_directoryIconStateHash.clear();
119 int clientIndex = clientCombo->currentIndex();
120 int fileSetIndex = fileSetCombo->currentIndex();
121 QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
122 QString clientComboText = clientCombo->itemText(clientIndex);
123 QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
124 bool dropdownChanged = (m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText);
125 int taskcount = 2, ontask = 1;
126 if (dropdownChanged) taskcount += 1;
127 // QString taskCountString = QString("%1").arg(taskcount);
129 /* Set progress bars and repaint */
130 prBar1->setVisible(true);
131 prBar1->setRange(0,taskcount);
133 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
134 prLabel1->setVisible(true);
135 prBar2->setVisible(true);
136 prBar2->setRange(0,0);
137 prLabel2->setText("Querying Database");
138 prLabel2->setVisible(true);
141 if (dropdownChanged) {
142 m_prevJobCombo = jobComboText;
143 m_prevClientCombo = clientComboText;
144 m_prevFileSetCombo = fileSetComboText;
145 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
147 m_condition = " Job.name = '" + jobCombo->itemText(jobCombo->currentIndex()) + "'";
148 if ((clientIndex >= 0) && (clientCombo->itemText(clientIndex) != "Any")) {
149 m_condition.append(" AND Client.Name='" + clientCombo->itemText(clientIndex) + "'");
151 if ((fileSetIndex >= 0) && (fileSetCombo->itemText(fileSetIndex) != "Any")) {
152 m_condition.append(" AND FileSet.FileSet='" + fileSetCombo->itemText(fileSetIndex) + "'");
155 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
156 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
157 " WHERE" + m_condition +
158 " AND Job.purgedfiles=0";
161 " From Job" + m_jobQueryPart;
162 if (mainWin->m_sqlDebug) {
163 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
165 prBar1->setValue(ontask++);
166 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
168 prBar2->setRange(0,0);
169 prLabel2->setText("Querying Jobs");
172 setJobsCheckedList();
174 setJobsCheckedList();
178 "SELECT DISTINCT Path.Path AS Path"
180 " INNER JOIN File ON (File.PathId=Path.PathId)"
181 " INNER JOIN Job ON (File.JobId=Job.JobId)"
182 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
184 if (mainWin->m_sqlDebug) {
185 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
187 prBar1->setValue(ontask++);
188 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
190 prLabel2->setText("Processing Directories");
191 QStringList directories;
192 if (m_console->sql_cmd(cmd, directories)) {
193 if (mainWin->m_miscDebug) {
194 Pmsg1(000, "Done with query %i directories\n", directories.count());
196 prBar2->setRange(0,directories.count());
198 foreach(QString directory, directories) {
200 prBar2->setValue(m_debugCnt);
201 parseDirectory(directory);
204 prBar1->setVisible(false);
205 prBar2->setVisible(false);
206 prLabel1->setVisible(false);
207 prLabel2->setVisible(false);
211 * Function to set m_jobQuery from the jobs that are checked in the table
214 void restoreTree::setJobsCheckedList()
216 m_JobsCheckedList = "";
218 /* Update the items in the version table */
219 int cnt = jobTable->rowCount();
220 for (int row=0; row<cnt; row++) {
221 QTableWidgetItem* jobItem = jobTable->item(row, 0);
222 if (jobItem->checkState() == Qt::Checked) {
224 m_JobsCheckedList += ",";
225 m_JobsCheckedList += jobItem->text();
227 jobItem->setBackground(Qt::green);
229 jobItem->setBackground(Qt::gray);
231 m_jobQuery = m_JobsCheckedList;
235 * Function to parse a directory into all possible subdirectories, then add to
238 void restoreTree::parseDirectory(QString &dir_in)
240 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
241 * instead of printing out what could potentially a whole bunch */
244 /* Clean up the directory string remove some funny char after last '/' */
245 QRegExp rgx("[^/]$");
246 int lastslash = rgx.indexIn(dir_in);
247 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
248 if ((mainWin->m_miscDebug) && (m_debugTrap))
249 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
251 /* split and add if not in yet */
252 QString direct, path;
255 QStringList pathAfter, dirAfter;
256 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
257 * if not added into tree, then try /etc/ and somedir/ if not added, then try
258 * / and etc/ . That should succeed, then add the ones that failed in reverse */
259 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
260 direct = path = dir_in;
261 path.replace(index+1, dir_in.length()-index-1,"");
262 direct.replace(0, index+1, "");
263 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
264 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
265 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
266 Pmsg0(000, msg.toUtf8().data());
268 if (addDirectory(path, direct)) done = true;
270 if ((mainWin->m_miscDebug) && (m_debugTrap))
271 Pmsg0(000, "Saving for later\n");
272 pathAfter.prepend(path);
273 dirAfter.prepend(direct);
278 for (int k=0; k<pathAfter.count(); k++) {
279 if (addDirectory(pathAfter[k], dirAfter[k]))
280 if ((mainWin->m_miscDebug) && (m_debugTrap))
281 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
283 if ((mainWin->m_miscDebug) && (m_debugTrap))
284 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
289 * Function called from fill directory when a directory is found to see if this
290 * directory exists in the directory pane and then add it to the directory pane
292 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
294 QString newdir = newdirr;
295 QString fullPath = m_cwd + newdirr;
296 bool ok = true, added = false;
298 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
299 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
302 Pmsg0(000, msg.toUtf8().data());
306 /* add unix '/' directory first */
307 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
309 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
311 item->setText(0, text.toUtf8().data());
312 item->setData(0, Qt::UserRole, QVariant(text));
313 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
314 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
315 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
316 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
318 m_dirPaths.insert(text, item);
320 /* no need to check for windows drive if unix */
321 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
322 /* this is a windows drive add the base widget */
323 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
324 item->setText(0, m_cwd);
325 item->setData(0, Qt::UserRole, QVariant(fullPath));
326 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
327 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
328 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
329 Pmsg0(000, "Added Base \"letter\":/\n");
331 m_dirPaths.insert(m_cwd, item);
335 /* is it already existent ?? */
336 if (!m_dirPaths.contains(fullPath)) {
337 QTreeWidgetItem *item = NULL;
338 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
340 /* new directories to add */
341 item = new QTreeWidgetItem(parent);
342 item->setText(0, newdir.toUtf8().data());
343 item->setData(0, Qt::UserRole, QVariant(fullPath));
344 item->setCheckState(0, Qt::Unchecked);
345 /* Store the current state of the check status in column 1, which at
346 * this point has no text*/
347 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
350 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
351 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
354 Pmsg0(000, msg.toUtf8().data());
357 /* insert into hash */
359 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
360 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
362 m_dirPaths.insert(fullPath, item);
370 * Virtual function which is called when this page is visible on the stack
372 void restoreTree::currentStackItem()
375 if (!m_console->preventInUseConnect())
383 * Populate the tree when refresh button pushed.
385 void restoreTree::refreshButtonPushed()
387 populateDirectoryTree();
391 * Set the values of non-job combo boxes to the job defaults
393 void restoreTree::jobComboChanged(int)
395 job_defaults job_defs;
398 job_defs.job_name = jobCombo->currentText();
399 if (m_console->get_job_defaults(job_defs)) {
400 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
401 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
406 * Function to populate the file list table
408 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
413 m_fileCheckStateList.clear();
414 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
415 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
416 QBrush blackBrush(Qt::black);
417 QString directory = item->data(0, Qt::UserRole).toString();
418 directoryLabel->setText("Present Working Directory : " + directory);
420 "SELECT DISTINCT Filename.Name AS FileName"
422 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
423 " INNER JOIN Path ON (Path.PathId=File.PathId)"
424 " INNER JOIN Job ON (File.JobId=Job.JobId)"
425 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
426 " AND Job.Jobid IN (" + m_jobQuery + ")"
427 " ORDER BY FileName";
429 QStringList headerlist = (QStringList() << "File Name");
431 /* Also clear the version table here */
432 versionTable->clear();
433 versionFileLabel->setText("");
434 versionTable->setRowCount(0);
435 versionTable->setColumnCount(0);
436 fileTable->setColumnCount(headerlist.size());
437 fileTable->setHorizontalHeaderLabels(headerlist);
439 if (mainWin->m_sqlDebug) {
440 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
443 if (m_console->sql_cmd(cmd, results)) {
445 QTableWidgetItem* tableItem;
447 QStringList fieldlist;
448 fileTable->setRowCount(results.size());
451 /* Iterate through the record returned from the query */
452 foreach (QString resultline, results) {
453 /* Iterate through fields in the record */
455 fieldlist = resultline.split("\t");
456 foreach (field, fieldlist) {
457 field = field.trimmed(); /* strip leading & trailing spaces */
458 tableItem = new QTableWidgetItem(field, 1);
459 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
460 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
461 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
462 tableItem->setForeground(blackBrush);
463 /* Just in case a column ever gets added */
465 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
466 tableItem->setFlags(flag);
467 tableItem->setData(Qt::UserRole, QVariant(directory));
468 fileTable->setItem(row, column, tableItem);
469 m_fileCheckStateList.append(Qt::Unchecked);
470 tableItem->setCheckState(Qt::Unchecked);
476 fileTable->setRowCount(row);
478 fileTable->resizeColumnsToContents();
479 fileTable->resizeRowsToContents();
480 fileTable->verticalHeader()->hide();
481 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
482 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
483 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
484 updateFileTableChecks();
488 * Function to populate the version table
490 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
492 if (fileTableItem == NULL)
495 m_versionCheckStateList.clear();
496 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
497 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
499 QString file = fileTableItem->text();
500 versionFileLabel->setText(file);
501 QString directory = fileTableItem->data(Qt::UserRole).toString();
503 QBrush blackBrush(Qt::black);
505 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
507 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
508 " INNER JOIN Path ON (Path.PathId=File.PathId)"
509 " INNER JOIN Job ON (File.JobId=Job.JobId)"
510 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
511 " AND Job.Jobid IN (" + m_jobQuery + ")"
512 " ORDER BY Job.EndTime DESC";
514 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
515 versionTable->clear();
516 versionTable->setColumnCount(headerlist.size());
517 versionTable->setHorizontalHeaderLabels(headerlist);
519 if (mainWin->m_sqlDebug) {
520 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
523 if (m_console->sql_cmd(cmd, results)) {
525 QTableWidgetItem* tableItem;
527 QStringList fieldlist;
528 versionTable->setRowCount(results.size());
531 /* Iterate through the record returned from the query */
532 foreach (QString resultline, results) {
533 fieldlist = resultline.split("\t");
535 /* remove directory */
536 if (fieldlist[0].trimmed() != "") {
537 /* Iterate through fields in the record */
538 foreach (field, fieldlist) {
539 field = field.trimmed(); /* strip leading & trailing spaces */
540 tableItem = new QTableWidgetItem(field, 1);
541 tableItem->setFlags(0);
542 tableItem->setForeground(blackBrush);
543 tableItem->setData(Qt::UserRole, QVariant(directory));
544 versionTable->setItem(row, column, tableItem);
547 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
548 tableItem->setFlags(flag);
549 m_versionCheckStateList.append(Qt::Unchecked);
550 tableItem->setCheckState(Qt::Unchecked);
558 versionTable->resizeColumnsToContents();
559 versionTable->resizeRowsToContents();
560 versionTable->verticalHeader()->hide();
561 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
562 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
563 updateVersionTableChecks();
567 * Save user settings associated with this page
569 void restoreTree::writeSettings()
571 QSettings settings(m_console->m_dir->name(), "bat");
572 settings.beginGroup("RestoreTree");
573 settings.setValue("splitterSizes", splitter->saveState());
578 * Read and restore user settings associated with this page
580 void restoreTree::readSettings()
582 QSettings settings(m_console->m_dir->name(), "bat");
583 settings.beginGroup("RestoreTree");
584 splitter->restoreState(settings.value("splitterSizes").toByteArray());
589 * This is a funcion to accomplish the one thing I struggled to figure out what
590 * was taking so long. It add the icons, but after the tree is made. Seemed to
591 * work fast after changing from svg to png file for graphic.
593 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
595 int childCount = item->childCount();
596 for (int i=0; i<childCount; i++) {
597 QTreeWidgetItem *child = item->child(i);
598 if (child->icon(0).isNull())
599 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
604 * I wanted a table to show what jobs meet the criterion and are being used to
605 * populate the directory tree and file and version tables.
607 void restoreTree::populateJobTable()
609 QBrush blackBrush(Qt::black);
610 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
612 jobTable->setColumnCount(headerlist.size());
613 jobTable->setHorizontalHeaderLabels(headerlist);
615 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
616 " FROM Job" + m_jobQueryPart +
617 " ORDER BY Job.EndTime DESC";
618 if (mainWin->m_sqlDebug) {
619 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
623 if (m_console->sql_cmd(jobQuery, results)) {
625 QTableWidgetItem* tableItem;
627 QStringList fieldlist;
628 jobTable->setRowCount(results.size());
631 /* Iterate through the record returned from the query */
632 foreach (QString resultline, results) {
633 fieldlist = resultline.split("\t");
635 /* remove directory */
636 if (fieldlist[0].trimmed() != "") {
637 /* Iterate through fields in the record */
638 foreach (field, fieldlist) {
639 field = field.trimmed(); /* strip leading & trailing spaces */
640 tableItem = new QTableWidgetItem(field, 1);
641 tableItem->setFlags(0);
642 tableItem->setForeground(blackBrush);
643 jobTable->setItem(row, column, tableItem);
645 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
646 tableItem->setFlags(flag);
647 tableItem->setCheckState(Qt::Checked);
648 tableItem->setBackground(Qt::green);
656 jobTable->resizeColumnsToContents();
657 jobTable->resizeRowsToContents();
658 jobTable->verticalHeader()->hide();
662 * When a directory item is "changed" check the state of the checkable item
663 * to see if it is different than what it was which is stored in Qt::UserRole
664 * of the 2nd column, column 1, of the tree widget.
666 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
668 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
669 Qt::CheckState curState = item->checkState(0);
670 QTreeWidgetItem* parent = item->parent();
671 Qt::CheckState parState;
672 if (parent) parState = parent->checkState(0);
673 else parState = (Qt::CheckState)3;
674 if (mainWin->m_rtDirICDebug) {
675 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
676 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
677 Pmsg1(000, "%s", msg.toUtf8().data()); }
678 /* I only care when the check state changes */
679 if (prevState == curState) {
680 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
684 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
685 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
686 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
687 curState = Qt::PartiallyChecked;
689 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
690 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
691 directoryTreeDisconnectedSet(item, Qt::Unchecked);
692 curState = Qt::Unchecked;
694 if (mainWin->m_rtDirICDebug) {
695 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
696 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
697 Pmsg1(000, "%s", msg.toUtf8().data()); }
699 item->setData(1, Qt::UserRole, QVariant(curState));
700 Qt::CheckState childState = curState;
701 if (childState == Qt::Checked)
702 childState = Qt::PartiallyChecked;
703 setCheckofChildren(item, childState);
705 /* Remove items from the exception lists. The multi exception list is my index
706 * of what exceptions can be removed when the directory is known*/
707 QString directory = item->data(0, Qt::UserRole).toString();
708 QStringList fullPathList = m_fileExceptionMulti.values(directory);
709 int fullPathListCount = fullPathList.count();
710 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
711 foreach (QString fullPath, fullPathList) {
712 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
713 * which will match no Qt::xxx values */
714 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
715 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
716 if (hashState == Qt::Unchecked) {
717 fileExceptionRemove(fullPath, directory);
718 m_versionExceptionHash.remove(fullPath);
719 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
721 if (hashState == Qt::Checked) {
722 fileExceptionRemove(fullPath, directory);
723 m_versionExceptionHash.remove(fullPath);
724 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
728 if (item == directoryTree->currentItem()) {
729 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
730 updateFileTableChecks();
731 versionTable->clear();
732 versionTable->setRowCount(0);
733 versionTable->setColumnCount(0);
735 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
739 * When a directory item check state is changed, this function iterates through
740 * all subdirectories and sets all to the passed state, which is either partially
741 * checked or unchecked.
743 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
746 childCount = item->childCount();
747 for (int i=0; i<childCount; i++) {
748 QTreeWidgetItem *child = item->child(i);
749 child->setData(1, Qt::UserRole, QVariant(state));
750 child->setCheckState(0, state);
751 setCheckofChildren(child, state);
756 * When a File Table Item is "changed" check to see if the state of the checkable
757 * item has changed which is stored in m_fileCheckStateList
758 * If changed store in a hash m_fileExceptionHash that whether this file should be
760 * Called as a slot, connected after populated (after directory current changed called)
762 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
764 /* get the previous and current check states */
765 int row = fileTable->row(item);
766 Qt::CheckState prevState;
767 /* prevent a segfault */
768 prevState = m_fileCheckStateList[row];
769 Qt::CheckState curState = item->checkState();
771 /* deterimine the default state from the state of the directory */
772 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
773 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
774 Qt::CheckState defState = Qt::PartiallyChecked;
775 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
777 /* determine if it is already in the m_fileExceptionHash */
778 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
779 QString file = item->text();
780 QString fullPath = directory + file;
781 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
782 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
784 if (mainWin->m_rtFileTabICDebug) {
785 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
786 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
787 Pmsg1(000, "%s", msg.toUtf8().data()); }
789 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
790 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
791 /* it can behave as defaulted so current of unchecked is fine */
792 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
793 fileExceptionRemove(fullPath, directory);
794 m_versionExceptionHash.remove(fullPath);
795 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
796 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
797 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
798 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
799 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
800 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
801 fileExceptionRemove(fullPath, directory);
802 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
803 /* Check dir, check version, attempt uncheck in file
804 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
805 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
806 fileExceptionRemove(fullPath, directory);
807 m_versionExceptionHash.remove(fullPath);
808 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
809 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
810 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
811 } else if (prevState != curState) {
812 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
813 /* A user did not set the check state to Partially checked, ignore if so */
814 if (curState != Qt::PartiallyChecked) {
815 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
816 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
818 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
819 fileExceptionInsert(fullPath, directory, curState);
822 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
823 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
824 m_versionExceptionHash.remove(fullPath);
828 updateFileTableChecks();
829 updateVersionTableChecks();
833 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
835 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
837 m_fileExceptionHash.insert(fullPath, state);
838 m_fileExceptionMulti.insert(direcotry, fullPath);
839 directoryIconStateInsert(fullPath, state);
843 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
845 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
847 m_fileExceptionHash.remove(fullPath);
848 /* pull the list of values in the multi */
849 QStringList fullPathList = m_fileExceptionMulti.values(directory);
850 /* get the index of the fullpath to remove */
851 int index = fullPathList.indexOf(fullPath);
853 /* remove the desired item in the list */
854 fullPathList.removeAt(index);
855 /* remove the entire list from the multi */
856 m_fileExceptionMulti.remove(directory);
857 /* readd the remaining */
858 foreach (QString fp, fullPathList) {
859 m_fileExceptionMulti.insert(directory, fp);
862 directoryIconStateRemove();
866 * Overloaded function to be called from the slot and from other places to set the state
867 * of the check marks in the version table
869 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
871 /* get the previous and current check states */
872 int row = versionTable->row(item);
873 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
874 Qt::CheckState prevState = m_versionCheckStateList[row];
875 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
876 m_versionCheckStateList[row] = curState;
878 /* deterimine the default state from the state of the file */
879 QTableWidgetItem *fileTableItem = fileTable->currentItem();
880 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
882 /* determine the default state */
883 Qt::CheckState defState;
885 defState = Qt::PartiallyChecked;
886 if (fileState == Qt::Unchecked)
887 defState = Qt::Unchecked;
890 defState = Qt::Unchecked;
892 /* determine if it is already in the versionExceptionHash */
893 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
894 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
895 QString file = fileTableItem->text();
896 QString fullPath = directory + file;
897 int thisJobNum = colZeroItem->text().toInt();
898 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
900 if (mainWin->m_rtVerTabICDebug) {
901 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
902 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
903 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
904 Pmsg1(000, "%s", msg.toUtf8().data()); }
905 /* if changed from partially checked to checked, make it unchecked */
906 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
907 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
908 fileTableItem->setCheckState(Qt::Checked);
909 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
910 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
911 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
912 fileExceptionRemove(fullPath, directory);
913 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
914 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
915 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
916 m_versionExceptionHash.remove(fullPath);
917 fileExceptionRemove(fullPath, directory);
918 } else if ((curState == Qt::Checked) && (row == 0)) {
919 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
920 m_versionExceptionHash.remove(fullPath);
921 } else if (prevState != curState) {
922 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
923 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
924 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
925 m_versionExceptionHash.insert(fullPath, thisJobNum);
926 if (fileState != Qt::Checked) {
927 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
928 fileExceptionInsert(fullPath, directory, curState);
931 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
934 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
937 updateFileTableChecks();
938 updateVersionTableChecks();
942 * Simple function to set the check state in the file table by disconnecting the
943 * signal/slot the setting then reconnecting the signal/slot
945 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
947 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
948 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
949 item->setCheckState(state);
950 if (color) item->setBackground(Qt::yellow);
951 else item->setBackground(Qt::white);
952 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
953 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
957 * Simple function to set the check state in the version table by disconnecting the
958 * signal/slot the setting then reconnecting the signal/slot
960 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
962 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
963 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
964 item->setCheckState(state);
965 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
966 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
970 * Simple function to set the check state in the directory tree by disconnecting the
971 * signal/slot the setting then reconnecting the signal/slot
973 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
975 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
976 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
977 item->setCheckState(0, state);
978 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
979 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
983 * Simplify the updating of the check state in the File table by iterating through
984 * each item in the file table to determine it's appropriate state.
985 * !! Will probably want to concoct a way to do this without iterating for the possibility
986 * of the very large directories.
988 void restoreTree::updateFileTableChecks()
990 /* deterimine the default state from the state of the directory */
991 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
992 Qt::CheckState dirState = dirTreeItem->checkState(0);
994 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
996 /* Update the items in the version table */
997 int rcnt = fileTable->rowCount();
998 for (int row=0; row<rcnt; row++) {
999 QTableWidgetItem* item = fileTable->item(row, 0);
1001 Qt::CheckState curState = item->checkState();
1002 Qt::CheckState newState = Qt::PartiallyChecked;
1003 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1005 /* determine if it is already in the m_fileExceptionHash */
1006 QString file = item->text();
1007 QString fullPath = dirName + file;
1008 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1009 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1011 if (hashState != 3) newState = hashState;
1013 if (mainWin->m_rtUpdateFTDebug) {
1014 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1015 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1016 Pmsg1(000, "%s", msg.toUtf8().data());
1019 bool docolor = false;
1020 if (hashJobNum != 0) docolor = true;
1021 bool isyellow = item->background().color() == QColor(Qt::yellow);
1022 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1023 fileTableDisconnectedSet(item, newState, docolor);
1024 m_fileCheckStateList[row] = newState;
1029 * Simplify the updating of the check state in the Version table by iterating through
1030 * each item in the file table to determine it's appropriate state.
1032 void restoreTree::updateVersionTableChecks()
1034 /* deterimine the default state from the state of the directory */
1035 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1036 Qt::CheckState dirState = dirTreeItem->checkState(0);
1037 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1039 /* deterimine the default state from the state of the file */
1040 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1041 Qt::CheckState fileState = fileTableItem->checkState();
1042 QString file = fileTableItem->text();
1043 QString fullPath = dirName + file;
1044 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1046 /* Update the items in the version table */
1047 int cnt = versionTable->rowCount();
1048 for (int row=0; row<cnt; row++) {
1049 QTableWidgetItem* item = versionTable->item(row, 0);
1051 Qt::CheckState curState = item->checkState();
1052 Qt::CheckState newState = Qt::Unchecked;
1054 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1055 newState = Qt::PartiallyChecked;
1056 /* determine if it is already in the versionExceptionHash */
1058 int thisJobNum = item->text().toInt();
1059 if (thisJobNum == hashJobNum)
1060 newState = Qt::Checked;
1062 if (mainWin->m_rtChecksDebug) {
1063 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1064 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1065 Pmsg1(000, "%s", msg.toUtf8().data());
1067 if (newState != curState)
1068 versionTableDisconnectedSet(item, newState);
1069 m_versionCheckStateList[row] = newState;
1074 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1076 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1080 QString fullPath = fullPath_in;
1081 QString direct, path;
1082 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1083 direct = path = fullPath;
1084 path.replace(index+1, fullPath.length()-index-1, "");
1085 direct.replace(0, index+1, "");
1087 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1088 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1089 Pmsg0(000, msg.toUtf8().data());
1092 subPaths.append(fullPath);
1097 * A Function to set the icon state and insert a record into
1098 * m_directoryIconStateHash when an exception is added by the user
1100 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1103 fullPathtoSubPaths(paths, fullPath);
1104 /* an exception that causes the item in the file table to be "Checked" has occured */
1105 if (excpState == Qt::Checked) {
1106 bool foundAsUnChecked = false;
1107 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1109 if (firstItem->checkState(0) == Qt::Unchecked)
1110 foundAsUnChecked = true;
1112 if (foundAsUnChecked) {
1113 /* as long as directory item is Unchecked, set icon state to "green check" */
1115 QListIterator<QString> siter(paths);
1116 while (siter.hasNext() && !done) {
1117 QString path = siter.next();
1118 QTreeWidgetItem *item = m_dirPaths.value(path);
1120 if (item->checkState(0) != Qt::Unchecked)
1123 directorySetIcon(1, FolderGreenChecked, path, item);
1124 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1129 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1130 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1132 QListIterator<QString> siter(paths);
1133 while (siter.hasNext() && !done) {
1134 QString path = siter.next();
1135 QTreeWidgetItem *item = m_dirPaths.value(path);
1136 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1137 if (item->checkState(0) == Qt::Checked)
1139 directorySetIcon(1, FolderGreenChecked, path, item);
1140 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1145 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1146 if (excpState == Qt::Unchecked) {
1148 QListIterator<QString> siter(paths);
1149 while (siter.hasNext() && !done) {
1150 QString path = siter.next();
1151 QTreeWidgetItem *item = m_dirPaths.value(path);
1152 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1153 if (item->checkState(0) == Qt::Checked)
1155 directorySetIcon(1, FolderWhiteChecked, path, item);
1156 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1163 * A function to set the icon state back to "folder" and to remove a record from
1164 * m_directoryIconStateHash when an exception is removed by a user.
1166 void restoreTree::directoryIconStateRemove()
1168 QHash<QString, int> shouldBeIconStateHash;
1169 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1170 /* Use iterator tera to iterate through m_fileExceptionHash */
1171 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1172 while (tera.hasNext()) {
1174 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1176 QString keyPath = tera.key();
1177 Qt::CheckState state = tera.value();
1180 fullPathtoSubPaths(paths, keyPath);
1181 /* if the state of the item in m_fileExceptionHash is checked
1182 * each of the subpaths should be "Checked Green" */
1183 if (state == Qt::Checked) {
1185 bool foundAsUnChecked = false;
1186 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1188 if (firstItem->checkState(0) == Qt::Unchecked)
1189 foundAsUnChecked = true;
1191 if (foundAsUnChecked) {
1192 /* The right most directory is Unchecked, iterate leftwards
1193 * as long as directory item is Unchecked, set icon state to "green check" */
1195 QListIterator<QString> siter(paths);
1196 while (siter.hasNext() && !done) {
1197 QString path = siter.next();
1198 QTreeWidgetItem *item = m_dirPaths.value(path);
1200 if (item->checkState(0) != Qt::Unchecked)
1203 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1204 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1210 /* The right most directory is Unchecked, iterate leftwards
1211 * until directory item is Checked, set icon state to "green check" */
1213 QListIterator<QString> siter(paths);
1214 while (siter.hasNext() && !done) {
1215 QString path = siter.next();
1216 QTreeWidgetItem *item = m_dirPaths.value(path);
1218 if (item->checkState(0) == Qt::Checked)
1220 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1225 /* if the state of the item in m_fileExceptionHash is UNChecked
1226 * each of the subpaths should be "Checked white" until the tree item
1227 * which represents that path is Qt::Checked */
1228 if (state == Qt::Unchecked) {
1230 QListIterator<QString> siter(paths);
1231 while (siter.hasNext() && !done) {
1232 QString path = siter.next();
1233 QTreeWidgetItem *item = m_dirPaths.value(path);
1235 if (item->checkState(0) == Qt::Checked)
1237 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1242 /* now iterate through m_directoryIconStateHash which are the items that are checked
1243 * and remove all of those that are not in shouldBeIconStateHash */
1244 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1245 while (iter.hasNext()) {
1247 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1249 QString keyPath = iter.key();
1250 if (shouldBeIconStateHash.value(keyPath)) {
1251 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1252 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1253 int newval = shouldBeIconStateHash.value(keyPath);
1255 newval = newval & FolderBothChecked;
1256 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1258 directorySetIcon(0, newval, keyPath, item);
1260 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1261 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1263 directorySetIcon(0, FolderBothChecked, keyPath, item);
1264 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1265 //m_directoryIconStateHash.remove(keyPath);
1270 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1272 /* we are adding a check type white or green */
1273 if (operation > 0) {
1274 /* get the old val and "bitwise OR" with the change */
1275 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1276 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1277 m_directoryIconStateHash.insert(path, newval);
1279 /* we are removing a check type white or green */
1280 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1282 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1283 m_directoryIconStateHash.remove(path);
1286 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1287 m_directoryIconStateHash.insert(path, newval);
1290 if (newval == FolderUnchecked)
1291 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1292 else if (newval == FolderGreenChecked)
1293 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1294 else if (newval == FolderWhiteChecked)
1295 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1296 else if (newval == FolderBothChecked)
1297 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1303 void restoreTree::restoreButtonPushed()
1305 /* Set progress bars and repaint */
1306 prLabel1->setVisible(true);
1307 prLabel1->setText("Task 1 of 3");
1308 prLabel2->setVisible(true);
1309 prLabel2->setText("Processing Checked directories");
1310 prBar1->setVisible(true);
1311 prBar1->setRange(0, 3);
1312 prBar1->setValue(0);
1313 prBar2->setVisible(true);
1314 prBar2->setRange(0, 0);
1316 QMultiHash<int, QString> versionFilesMulti;
1318 QHash <QString, bool> fullPathDone;
1319 QHash <QString, int> fileIndexHash;
1320 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1321 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1322 /* Use a tree widget item iterator to count directories for the progress bar */
1323 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1328 } /* while (*diterc) */
1329 prBar2->setRange(0, ditcount);
1330 prBar2->setValue(0);
1332 /* Use a tree widget item iterator filtering for Checked Items */
1333 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1335 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1336 if (mainWin->m_rtRestore1Debug)
1337 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1338 /* With a checked directory, query for the files in the directory */
1341 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1343 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1345 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1346 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1347 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1348 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1349 " AND Job.Jobid IN (" + m_jobQuery + ")"
1350 " GROUP BY Filename.Name"
1352 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1353 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1354 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1356 " Path.Path='" + directory + "'"
1357 " AND Filename.Name=t1.Filename"
1358 " AND Job.Jobid=t1.JobId"
1359 " ORDER BY Filename";
1361 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1362 QStringList results;
1363 if (m_console->sql_cmd(cmd, results)) {
1364 QStringList fieldlist;
1367 /* Iterate through the record returned from the query */
1368 foreach (QString resultline, results) {
1369 /* Iterate through fields in the record */
1371 QString fullPath = "";
1372 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1373 fieldlist = resultline.split("\t");
1376 foreach (QString field, fieldlist) {
1378 fullPath = directory + field;
1381 version = field.toInt();
1384 fileIndex = field.toInt();
1388 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1390 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1391 if (fileExcpState != Qt::Unchecked) {
1393 if (excpVersion != 0) {
1394 debugtext = QString("*E* version=%1").arg(excpVersion);
1395 version = excpVersion;
1396 fileIndex = queryFileIndex(fullPath, excpVersion);
1398 debugtext = QString("___ version=%1").arg(version);
1399 if (mainWin->m_rtRestore1Debug)
1400 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1401 fullPathDone.insert(fullPath, 1);
1402 fileIndexHash.insert(fullPath, fileIndex);
1403 versionFilesMulti.insert(version, fullPath);
1410 prBar2->setValue(ditcount);
1412 } /* while (*diter) */
1413 prBar1->setValue(1);
1414 prLabel1->setText("Task 2 of 3");
1415 prLabel2->setText("Processing Exceptions");
1416 prBar2->setRange(0, 0);
1419 /* There may be some exceptions not accounted for yet with fullPathDone */
1420 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1421 while (ftera.hasNext()) {
1423 QString fullPath = ftera.key();
1424 Qt::CheckState state = ftera.value();
1426 /* now we don't want the ones already done */
1427 if (fullPathDone.value(fullPath, 0) == 0) {
1428 int version = m_versionExceptionHash.value(fullPath, 0);
1430 QString debugtext = "";
1432 fileIndex = queryFileIndex(fullPath, version);
1433 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1435 version = mostRecentVersionfromFullPath(fullPath);
1437 fileIndex = queryFileIndex(fullPath, version);
1438 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1440 debugtext = QString("Error det vers").arg(version);
1442 if (mainWin->m_rtRestore1Debug)
1443 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1444 versionFilesMulti.insert(version, fullPath);
1446 fileIndexHash.insert(fullPath, fileIndex);
1447 } /* if fullPathDone.value(fullPath, 0) == 0 */
1448 } /* if state != 0 */
1449 } /* while ftera.hasNext */
1450 /* The progress bars for the next step */
1451 prBar1->setValue(2);
1452 prLabel1->setText("Task 3 of 3");
1453 prLabel2->setText("Filling Database Table");
1454 prBar2->setRange(0, vFMCounter);
1456 prBar2->setValue(vFMCounter);
1459 /* now for the final spit out of the versions and lists of files for each version */
1460 QHash<int, int> doneKeys;
1461 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1462 QString tempTable = "";
1464 while (vFMiter.hasNext()) {
1466 int fversion = vFMiter.key();
1467 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1468 if (doneKeys.value(fversion, 0) == 0) {
1469 if (tempTable == "") {
1470 QSettings settings("www.bacula.org", "bat");
1471 settings.beginGroup("Restore");
1472 int counter = settings.value("Counter", 1).toInt();
1473 settings.setValue("Counter", counter+1);
1474 settings.endGroup();
1475 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1476 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1477 if (mainWin->m_sqlDebug)
1478 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1479 QStringList results;
1480 if (!m_console->sql_cmd(sqlcmd, results))
1481 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1484 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1485 QStringList fullPathList = versionFilesMulti.values(fversion);
1486 /* create the command to perform the restore */
1487 foreach(QString ffullPath, fullPathList) {
1488 int fileIndex = fileIndexHash.value(ffullPath);
1489 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1490 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1491 if (mainWin->m_rtRestore3Debug)
1492 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1493 QStringList results;
1494 if (!m_console->sql_cmd(sqlcmd, results))
1495 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1496 prBar2->setValue(++vFMCounter);
1497 } /* foreach fullPathList */
1498 doneKeys.insert(fversion,1);
1499 jobList.append(fversion);
1500 } /* if (doneKeys.value(fversion, 0) == 0) */
1501 } /* while (vFMiter.hasNext()) */
1502 if (tempTable != "") {
1503 /* a table was made, lets run the job */
1504 QString jobOption = " jobid=\"";
1506 /* create a list of jobs comma separated */
1507 foreach (int job, jobList) {
1508 if (first) first = false;
1509 else jobOption += ",";
1510 jobOption += QString("%1").arg(job);
1513 QString cmd = QString("restore");
1515 " file=\"?" + tempTable + "\" done";
1516 if (mainWin->m_commandDebug)
1517 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1518 consoleCommand(cmd);
1520 /* turn off the progress widgets */
1521 prBar1->setVisible(false);
1522 prBar2->setVisible(false);
1523 prLabel1->setVisible(false);
1524 prLabel2->setVisible(false);
1527 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1530 QString directory, fileName;
1531 int index = m_slashregex.lastIndexIn(fullPath, -2);
1533 directory = fileName = fullPath;
1534 directory.replace(index+1, fullPath.length()-index-1, "");
1535 fileName.replace(0, index+1, "");
1537 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1538 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1539 Pmsg0(000, msg.toUtf8().data());
1541 /* so now we need the latest version from the database */
1543 "SELECT MAX(Job.JobId)"
1545 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1546 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1547 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1548 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1549 " AND Job.Jobid IN (" + m_jobQuery + ")"
1550 " AND Filename.Name='" + fileName + "'"
1551 " GROUP BY Filename.Name";
1553 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1554 QStringList results;
1555 if (m_console->sql_cmd(cmd, results)) {
1556 QStringList fieldlist;
1558 /* Iterate through the record returned from the query */
1559 foreach (QString resultline, results) {
1560 /* Iterate through fields in the record */
1562 fieldlist = resultline.split("\t");
1563 foreach (QString field, fieldlist) {
1565 qversion = field.toInt();
1572 } /* if (index != -1) */
1577 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1580 QString directory, fileName;
1581 int index = m_slashregex.lastIndexIn(fullPath, -2);
1583 directory = fileName = fullPath;
1584 directory.replace(index+1, fullPath.length()-index-1, "");
1585 fileName.replace(0, index+1, "");
1587 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1588 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1589 Pmsg0(000, msg.toUtf8().data());
1591 /* so now we need the latest version from the database */
1596 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1597 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1598 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1600 " Path.Path='" + directory + "'"
1601 " AND Filename.Name='" + fileName + "'"
1602 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1603 " GROUP BY File.FileIndex";
1605 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1606 QStringList results;
1607 if (m_console->sql_cmd(cmd, results)) {
1608 QStringList fieldlist;
1610 /* Iterate through the record returned from the query */
1611 foreach (QString resultline, results) {
1612 /* Iterate through fields in the record */
1614 fieldlist = resultline.split("\t");
1615 foreach (QString field, fieldlist) {
1617 qfileIndex = field.toInt();
1624 } /* if (index != -1) */