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.
30 * Version $Id: restore.cpp 4945 2007-05-31 01:24:28Z bartleyd2 $
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("/");
62 restoreTree::~restoreTree()
68 * Called from the constructor to set up the page widgets and connections.
70 void restoreTree::setupPage()
72 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
73 connect(testButton, SIGNAL(pressed()), this, SLOT(testButtonPushed()));
74 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
75 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
76 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
77 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
78 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
79 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
80 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
81 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
82 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
84 QStringList titles = QStringList() << "Directories";
85 directoryTree->setHeaderLabels(titles);
86 clientCombo->addItems(m_console->client_list);
87 fileSetCombo->addItem("Any");
88 fileSetCombo->addItems(m_console->fileset_list);
89 jobCombo->addItems(m_console->job_list);
91 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
95 * When refresh button is pushed, perform a query getting the directories and
96 * use parseDirectory and addDirectory to populate the directory tree with items.
98 void restoreTree::populateDirectoryTree()
102 directoryTree->clear();
104 fileTable->setRowCount(0);
105 fileTable->setColumnCount(0);
106 versionTable->clear();
107 versionTable->setRowCount(0);
108 versionTable->setColumnCount(0);
109 m_fileExceptionHash.clear();
110 m_fileExceptionMulti.clear();
111 m_versionExceptionHash.clear();
112 m_directoryIconStateHash.clear();
115 int clientIndex = clientCombo->currentIndex();
116 int fileSetIndex = fileSetCombo->currentIndex();
117 QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
118 QString clientComboText = clientCombo->itemText(clientIndex);
119 QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
120 if ((m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText)) {
121 m_prevJobCombo = jobComboText;
122 m_prevClientCombo = clientComboText;
123 m_prevFileSetCombo = fileSetComboText;
124 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
126 m_condition = " Job.name = '" + jobCombo->itemText(jobCombo->currentIndex()) + "'";
127 if ((clientIndex >= 0) && (clientCombo->itemText(clientIndex) != "Any")) {
128 m_condition.append(" AND Client.Name='" + clientCombo->itemText(clientIndex) + "'");
130 if ((fileSetIndex >= 0) && (fileSetCombo->itemText(fileSetIndex) != "Any")) {
131 m_condition.append(" AND FileSet.FileSet='" + fileSetCombo->itemText(fileSetIndex) + "'");
134 " LEFT OUTER JOIN Client ON (Job.ClientId=Client.ClientId)"
135 " LEFT OUTER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
136 " WHERE" + m_condition +
137 " AND Job.purgedfiles=0";
140 " From Job" + m_jobQueryPart;
141 if (mainWin->m_sqlDebug) {
142 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
145 setJobsCheckedList();
147 setJobsCheckedList();
151 "SELECT DISTINCT Path.Path AS Path"
153 " LEFT OUTER JOIN File ON (File.PathId=Path.PathId)"
154 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
155 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
157 if (mainWin->m_sqlDebug) {
158 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
160 QStringList directories;
161 if (m_console->sql_cmd(cmd, directories)) {
162 if (mainWin->m_miscDebug) {
163 Pmsg1(000, "Done with query %i directories\n", directories.count());
165 foreach(QString directory, directories) {
167 parseDirectory(directory);
173 * Function to set m_jobQuery from the jobs that are checked in the table
176 void restoreTree::setJobsCheckedList()
178 m_JobsCheckedList = "";
180 /* Update the items in the version table */
181 int cnt = jobTable->rowCount();
182 for (int row=0; row<cnt; row++) {
183 QTableWidgetItem* jobItem = jobTable->item(row, 0);
184 if (jobItem->checkState() == Qt::Checked) {
186 m_JobsCheckedList += ",";
187 m_JobsCheckedList += jobItem->text();
189 jobItem->setBackground(Qt::green);
191 jobItem->setBackground(Qt::gray);
193 m_jobQuery = m_JobsCheckedList;
197 * Function to parse a directory into all possible subdirectories, then add to
200 void restoreTree::parseDirectory(QString &dir_in)
202 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
203 * instead of printing out what could potentially a whole bunch */
206 /* Clean up the directory string remove some funny char after last '/' */
207 QRegExp rgx("[^/]$");
208 int lastslash = rgx.indexIn(dir_in);
209 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
210 if ((mainWin->m_miscDebug) && (m_debugTrap))
211 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
213 /* split and add if not in yet */
214 QString direct, path;
217 QStringList pathAfter, dirAfter;
218 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
219 * if not added into tree, then try /etc/ and somedir/ if not added, then try
220 * / and etc/ . That should succeed, then add the ones that failed in reverse */
221 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
222 direct = path = dir_in;
223 path.replace(index+1, dir_in.length()-index-1,"");
224 direct.replace(0, index+1, "");
225 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
226 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
227 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
228 Pmsg0(000, msg.toUtf8().data());
230 if (addDirectory(path, direct)) done = true;
232 if ((mainWin->m_miscDebug) && (m_debugTrap))
233 Pmsg0(000, "Saving for later\n");
234 pathAfter.prepend(path);
235 dirAfter.prepend(direct);
240 for (int k=0; k<pathAfter.count(); k++) {
241 if (addDirectory(pathAfter[k], dirAfter[k]))
242 if ((mainWin->m_miscDebug) && (m_debugTrap))
243 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
245 if ((mainWin->m_miscDebug) && (m_debugTrap))
246 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
251 * Function called from fill directory when a directory is found to see if this
252 * directory exists in the directory pane and then add it to the directory pane
254 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
256 QString newdir = newdirr;
257 QString fullPath = m_cwd + newdirr;
258 bool ok = true, added = false;
260 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
261 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
264 Pmsg0(000, msg.toUtf8().data());
268 /* add unix '/' directory first */
269 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
271 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
273 item->setText(0, text.toUtf8().data());
274 item->setData(0, Qt::UserRole, QVariant(text));
275 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
276 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
277 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
278 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
280 m_dirPaths.insert(text, item);
282 /* no need to check for windows drive if unix */
283 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
284 /* this is a windows drive add the base widget */
285 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
286 item->setText(0, m_cwd);
287 item->setData(0, Qt::UserRole, QVariant(fullPath));
288 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
289 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
290 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
291 Pmsg0(000, "Added Base \"letter\":/\n");
293 m_dirPaths.insert(m_cwd, item);
297 /* is it already existent ?? */
298 if (!m_dirPaths.contains(fullPath)) {
299 QTreeWidgetItem *item = NULL;
300 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
302 /* new directories to add */
303 item = new QTreeWidgetItem(parent);
304 item->setText(0, newdir.toUtf8().data());
305 item->setData(0, Qt::UserRole, QVariant(fullPath));
306 item->setCheckState(0, Qt::Unchecked);
307 /* Store the current state of the check status in column 1, which at
308 * this point has no text*/
309 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
312 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
313 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
316 Pmsg0(000, msg.toUtf8().data());
319 /* insert into hash */
321 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
322 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
324 m_dirPaths.insert(fullPath, item);
332 * Virtual function which is called when this page is visible on the stack
334 void restoreTree::currentStackItem()
337 if (!m_console->preventInUseConnect())
345 * Populate the tree when refresh button pushed.
347 void restoreTree::refreshButtonPushed()
349 populateDirectoryTree();
353 * Set the values of non-job combo boxes to the job defaults
355 void restoreTree::jobComboChanged(int)
357 job_defaults job_defs;
360 job_defs.job_name = jobCombo->currentText();
361 if (m_console->get_job_defaults(job_defs)) {
362 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
363 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
368 * Function to populate the file list table
370 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
375 m_fileCheckStateList.clear();
376 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
377 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
378 QBrush blackBrush(Qt::black);
379 QString directory = item->data(0, Qt::UserRole).toString();
380 directoryLabel->setText("Present Working Directory : " + directory);
382 "SELECT DISTINCT Filename.Name"
384 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
385 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
386 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
387 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
388 " AND Job.Jobid IN (" + m_jobQuery + ")";
390 QStringList headerlist = (QStringList() << "File Name");
392 /* Also clear the version table here */
393 versionTable->clear();
394 versionFileLabel->setText("");
395 versionTable->setRowCount(0);
396 versionTable->setColumnCount(0);
397 fileTable->setColumnCount(headerlist.size());
398 fileTable->setHorizontalHeaderLabels(headerlist);
400 if (mainWin->m_sqlDebug) {
401 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
404 if (m_console->sql_cmd(cmd, results)) {
406 QTableWidgetItem* tableItem;
408 QStringList fieldlist;
409 fileTable->setRowCount(results.size());
412 /* Iterate through the record returned from the query */
413 foreach (QString resultline, results) {
414 /* Iterate through fields in the record */
416 fieldlist = resultline.split("\t");
417 foreach (field, fieldlist) {
418 field = field.trimmed(); /* strip leading & trailing spaces */
419 tableItem = new QTableWidgetItem(field, 1);
420 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
421 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
422 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
423 tableItem->setForeground(blackBrush);
424 /* Just in case a column ever gets added */
426 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
427 tableItem->setFlags(flag);
428 tableItem->setData(Qt::UserRole, QVariant(directory));
429 fileTable->setItem(row, column, tableItem);
430 m_fileCheckStateList.append(Qt::Unchecked);
431 tableItem->setCheckState(Qt::Unchecked);
437 fileTable->setRowCount(row);
439 fileTable->resizeColumnsToContents();
440 fileTable->resizeRowsToContents();
441 fileTable->verticalHeader()->hide();
442 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
443 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
444 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
445 updateFileTableChecks();
449 * Function to populate the version table
451 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
453 if (fileTableItem == NULL)
456 m_versionCheckStateList.clear();
457 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
458 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
460 QString file = fileTableItem->text();
461 versionFileLabel->setText(file);
462 QString directory = fileTableItem->data(Qt::UserRole).toString();
464 QBrush blackBrush(Qt::black);
466 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
468 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
469 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
470 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
471 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
472 " AND Job.Jobid IN (" + m_jobQuery + ")"
473 " ORDER BY Job.EndTime DESC";
475 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
476 versionTable->clear();
477 versionTable->setColumnCount(headerlist.size());
478 versionTable->setHorizontalHeaderLabels(headerlist);
480 if (mainWin->m_sqlDebug) {
481 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
484 if (m_console->sql_cmd(cmd, results)) {
486 QTableWidgetItem* tableItem;
488 QStringList fieldlist;
489 versionTable->setRowCount(results.size());
492 /* Iterate through the record returned from the query */
493 foreach (QString resultline, results) {
494 fieldlist = resultline.split("\t");
496 /* remove directory */
497 if (fieldlist[0].trimmed() != "") {
498 /* Iterate through fields in the record */
499 foreach (field, fieldlist) {
500 field = field.trimmed(); /* strip leading & trailing spaces */
501 tableItem = new QTableWidgetItem(field, 1);
502 tableItem->setFlags(0);
503 tableItem->setForeground(blackBrush);
504 tableItem->setData(Qt::UserRole, QVariant(directory));
505 versionTable->setItem(row, column, tableItem);
508 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
509 tableItem->setFlags(flag);
510 m_versionCheckStateList.append(Qt::Unchecked);
511 tableItem->setCheckState(Qt::Unchecked);
519 versionTable->resizeColumnsToContents();
520 versionTable->resizeRowsToContents();
521 versionTable->verticalHeader()->hide();
522 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
523 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
524 updateVersionTableChecks();
528 * Save user settings associated with this page
530 void restoreTree::writeSettings()
532 QSettings settings(m_console->m_dir->name(), "bat");
533 settings.beginGroup("RestoreTree");
534 settings.setValue("splitterSizes", splitter->saveState());
539 * Read and restore user settings associated with this page
541 void restoreTree::readSettings()
543 QSettings settings(m_console->m_dir->name(), "bat");
544 settings.beginGroup("RestoreTree");
545 splitter->restoreState(settings.value("splitterSizes").toByteArray());
550 * This is a funcion to accomplish the one thing I struggled to figure out what
551 * was taking so long. It add the icons, but after the tree is made. Seemed to
552 * work fast after changing from svg to png file for graphic.
554 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
556 int childCount = item->childCount();
557 for (int i=0; i<childCount; i++) {
558 QTreeWidgetItem *child = item->child(i);
559 if (child->icon(0).isNull())
560 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
565 * I wanted a table to show what jobs meet the criterion and are being used to
566 * populate the directory tree and file and version tables.
568 void restoreTree::populateJobTable()
570 QBrush blackBrush(Qt::black);
571 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
573 jobTable->setColumnCount(headerlist.size());
574 jobTable->setHorizontalHeaderLabels(headerlist);
576 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
577 " FROM Job" + m_jobQueryPart +
578 " ORDER BY Job.EndTime DESC";
579 if (mainWin->m_sqlDebug) {
580 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
584 if (m_console->sql_cmd(jobQuery, results)) {
586 QTableWidgetItem* tableItem;
588 QStringList fieldlist;
589 jobTable->setRowCount(results.size());
592 /* Iterate through the record returned from the query */
593 foreach (QString resultline, results) {
594 fieldlist = resultline.split("\t");
596 /* remove directory */
597 if (fieldlist[0].trimmed() != "") {
598 /* Iterate through fields in the record */
599 foreach (field, fieldlist) {
600 field = field.trimmed(); /* strip leading & trailing spaces */
601 tableItem = new QTableWidgetItem(field, 1);
602 tableItem->setFlags(0);
603 tableItem->setForeground(blackBrush);
604 jobTable->setItem(row, column, tableItem);
606 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
607 tableItem->setFlags(flag);
608 tableItem->setCheckState(Qt::Checked);
609 tableItem->setBackground(Qt::green);
617 jobTable->resizeColumnsToContents();
618 jobTable->resizeRowsToContents();
619 jobTable->verticalHeader()->hide();
623 * When a directory item is "changed" check the state of the checkable item
624 * to see if it is different than what it was which is stored in Qt::UserRole
625 * of the 2nd column, column 1, of the tree widget.
627 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
629 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
630 Qt::CheckState curState = item->checkState(0);
631 QTreeWidgetItem* parent = item->parent();
632 Qt::CheckState parState;
633 if (parent) parState = parent->checkState(0);
634 else parState = (Qt::CheckState)3;
635 if (mainWin->m_rtDirICDebug) {
636 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
637 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
638 Pmsg1(000, "%s", msg.toUtf8().data()); }
639 /* I only care when the check state changes */
640 if (prevState == curState) {
641 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
645 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
646 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
647 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
648 curState = Qt::PartiallyChecked;
650 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
651 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
652 directoryTreeDisconnectedSet(item, Qt::Unchecked);
653 curState = Qt::Unchecked;
655 if (mainWin->m_rtDirICDebug) {
656 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
657 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
658 Pmsg1(000, "%s", msg.toUtf8().data()); }
660 item->setData(1, Qt::UserRole, QVariant(curState));
661 Qt::CheckState childState = curState;
662 if (childState == Qt::Checked)
663 childState = Qt::PartiallyChecked;
664 setCheckofChildren(item, childState);
666 /* Remove items from the exception lists. The multi exception list is my index
667 * of what exceptions can be removed when the directory is known*/
668 QString directory = item->data(0, Qt::UserRole).toString();
669 QStringList fullPathList = m_fileExceptionMulti.values(directory);
670 int fullPathListCount = fullPathList.count();
671 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
672 foreach (QString fullPath, fullPathList) {
673 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
674 * which will match no Qt::xxx values */
675 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
676 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
677 if (hashState == Qt::Unchecked) {
678 fileExceptionRemove(fullPath, directory);
679 m_versionExceptionHash.remove(fullPath);
680 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
682 if (hashState == Qt::Checked) {
683 fileExceptionRemove(fullPath, directory);
684 m_versionExceptionHash.remove(fullPath);
685 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
689 if (item == directoryTree->currentItem()) {
690 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
691 updateFileTableChecks();
692 versionTable->clear();
693 versionTable->setRowCount(0);
694 versionTable->setColumnCount(0);
696 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
700 * When a directory item check state is changed, this function iterates through
701 * all subdirectories and sets all to the passed state, which is either partially
702 * checked or unchecked.
704 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
707 childCount = item->childCount();
708 for (int i=0; i<childCount; i++) {
709 QTreeWidgetItem *child = item->child(i);
710 child->setData(1, Qt::UserRole, QVariant(state));
711 child->setCheckState(0, state);
712 setCheckofChildren(child, state);
717 * When a File Table Item is "changed" check to see if the state of the checkable
718 * item has changed which is stored in m_fileCheckStateList
719 * If changed store in a hash m_fileExceptionHash that whether this file should be
721 * Called as a slot, connected after populated (after directory current changed called)
723 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
725 /* get the previous and current check states */
726 int row = fileTable->row(item);
727 Qt::CheckState prevState;
728 /* prevent a segfault */
729 prevState = m_fileCheckStateList[row];
730 Qt::CheckState curState = item->checkState();
732 /* deterimine the default state from the state of the directory */
733 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
734 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
735 Qt::CheckState defState = Qt::PartiallyChecked;
736 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
738 /* determine if it is already in the m_fileExceptionHash */
739 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
740 QString file = item->text();
741 QString fullPath = directory + file;
742 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
743 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
745 if (mainWin->m_rtFileTabICDebug) {
746 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
747 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
748 Pmsg1(000, "%s", msg.toUtf8().data()); }
750 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
751 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
752 /* it can behave as defaulted so current of unchecked is fine */
753 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
754 fileExceptionRemove(fullPath, directory);
755 m_versionExceptionHash.remove(fullPath);
756 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
757 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
758 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
759 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
760 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
761 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
762 fileExceptionRemove(fullPath, directory);
763 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
764 /* Check dir, check version, attempt uncheck in file
765 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
766 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
767 fileExceptionRemove(fullPath, directory);
768 m_versionExceptionHash.remove(fullPath);
769 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
770 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
771 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
772 } else if (prevState != curState) {
773 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
774 /* A user did not set the check state to Partially checked, ignore if so */
775 if (curState != Qt::PartiallyChecked) {
776 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
777 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
779 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
780 fileExceptionInsert(fullPath, directory, curState);
783 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
784 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
785 m_versionExceptionHash.remove(fullPath);
789 updateFileTableChecks();
790 updateVersionTableChecks();
794 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
796 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
798 m_fileExceptionHash.insert(fullPath, state);
799 m_fileExceptionMulti.insert(direcotry, fullPath);
800 directoryIconStateInsert(fullPath, state);
804 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
806 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
808 m_fileExceptionHash.remove(fullPath);
809 /* pull the list of values in the multi */
810 QStringList fullPathList = m_fileExceptionMulti.values(directory);
811 /* get the index of the fullpath to remove */
812 int index = fullPathList.indexOf(fullPath);
814 /* remove the desired item in the list */
815 fullPathList.removeAt(index);
816 /* remove the entire list from the multi */
817 m_fileExceptionMulti.remove(directory);
818 /* readd the remaining */
819 foreach (QString fp, fullPathList) {
820 m_fileExceptionMulti.insert(directory, fp);
823 directoryIconStateRemove();
827 * Overloaded function to be called from the slot and from other places to set the state
828 * of the check marks in the version table
830 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
832 /* get the previous and current check states */
833 int row = versionTable->row(item);
834 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
835 Qt::CheckState prevState = m_versionCheckStateList[row];
836 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
837 m_versionCheckStateList[row] = curState;
839 /* deterimine the default state from the state of the file */
840 QTableWidgetItem *fileTableItem = fileTable->currentItem();
841 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
843 /* determine the default state */
844 Qt::CheckState defState;
846 defState = Qt::PartiallyChecked;
847 if (fileState == Qt::Unchecked)
848 defState = Qt::Unchecked;
851 defState = Qt::Unchecked;
853 /* determine if it is already in the versionExceptionHash */
854 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
855 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
856 QString file = fileTableItem->text();
857 QString fullPath = directory + file;
858 int thisJobNum = colZeroItem->text().toInt();
859 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
861 if (mainWin->m_rtVerTabICDebug) {
862 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
863 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
864 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
865 Pmsg1(000, "%s", msg.toUtf8().data()); }
866 /* if changed from partially checked to checked, make it unchecked */
867 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
868 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
869 fileTableItem->setCheckState(Qt::Checked);
870 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
871 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
872 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
873 fileExceptionRemove(fullPath, directory);
874 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
875 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
876 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
877 m_versionExceptionHash.remove(fullPath);
878 fileExceptionRemove(fullPath, directory);
879 } else if ((curState == Qt::Checked) && (row == 0)) {
880 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
881 m_versionExceptionHash.remove(fullPath);
882 } else if (prevState != curState) {
883 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
884 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
885 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
886 m_versionExceptionHash.insert(fullPath, thisJobNum);
887 if (fileState != Qt::Checked) {
888 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
889 fileExceptionInsert(fullPath, directory, curState);
892 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
895 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
898 updateFileTableChecks();
899 updateVersionTableChecks();
903 * Simple function to set the check state in the file table by disconnecting the
904 * signal/slot the setting then reconnecting the signal/slot
906 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
908 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
909 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
910 item->setCheckState(state);
911 if (color) item->setBackground(Qt::yellow);
912 else item->setBackground(Qt::white);
913 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
914 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
918 * Simple function to set the check state in the version table by disconnecting the
919 * signal/slot the setting then reconnecting the signal/slot
921 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
923 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
924 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
925 item->setCheckState(state);
926 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
927 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
931 * Simple function to set the check state in the directory tree by disconnecting the
932 * signal/slot the setting then reconnecting the signal/slot
934 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
936 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
937 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
938 item->setCheckState(0, state);
939 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
940 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
944 * Simplify the updating of the check state in the File table by iterating through
945 * each item in the file table to determine it's appropriate state.
946 * !! Will probably want to concoct a way to do this without iterating for the possibility
947 * of the very large directories.
949 void restoreTree::updateFileTableChecks()
951 /* deterimine the default state from the state of the directory */
952 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
953 Qt::CheckState dirState = dirTreeItem->checkState(0);
955 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
957 /* Update the items in the version table */
958 int rcnt = fileTable->rowCount();
959 for (int row=0; row<rcnt; row++) {
960 QTableWidgetItem* item = fileTable->item(row, 0);
962 Qt::CheckState curState = item->checkState();
963 Qt::CheckState newState = Qt::PartiallyChecked;
964 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
966 /* determine if it is already in the m_fileExceptionHash */
967 QString file = item->text();
968 QString fullPath = dirName + file;
969 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
970 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
972 if (hashState != 3) newState = hashState;
974 if (mainWin->m_rtUpdateFTDebug) {
975 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
976 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
977 Pmsg1(000, "%s", msg.toUtf8().data());
980 bool docolor = false;
981 if (hashJobNum != 0) docolor = true;
982 bool isyellow = item->background().color() == QColor(Qt::yellow);
983 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
984 fileTableDisconnectedSet(item, newState, docolor);
985 m_fileCheckStateList[row] = newState;
990 * Simplify the updating of the check state in the Version table by iterating through
991 * each item in the file table to determine it's appropriate state.
993 void restoreTree::updateVersionTableChecks()
995 /* deterimine the default state from the state of the directory */
996 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
997 Qt::CheckState dirState = dirTreeItem->checkState(0);
998 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1000 /* deterimine the default state from the state of the file */
1001 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1002 Qt::CheckState fileState = fileTableItem->checkState();
1003 QString file = fileTableItem->text();
1004 QString fullPath = dirName + file;
1005 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1007 /* Update the items in the version table */
1008 int cnt = versionTable->rowCount();
1009 for (int row=0; row<cnt; row++) {
1010 QTableWidgetItem* item = versionTable->item(row, 0);
1012 Qt::CheckState curState = item->checkState();
1013 Qt::CheckState newState = Qt::Unchecked;
1015 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1016 newState = Qt::PartiallyChecked;
1017 /* determine if it is already in the versionExceptionHash */
1019 int thisJobNum = item->text().toInt();
1020 if (thisJobNum == hashJobNum)
1021 newState = Qt::Checked;
1023 if (mainWin->m_rtChecksDebug) {
1024 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1025 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1026 Pmsg1(000, "%s", msg.toUtf8().data());
1028 if (newState != curState)
1029 versionTableDisconnectedSet(item, newState);
1030 m_versionCheckStateList[row] = newState;
1035 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1037 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1041 QString fullPath = fullPath_in;
1042 QString direct, path;
1043 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1044 direct = path = fullPath;
1045 path.replace(index+1, fullPath.length()-index-1, "");
1046 direct.replace(0, index+1, "");
1048 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1049 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1050 Pmsg0(000, msg.toUtf8().data());
1053 subPaths.append(fullPath);
1058 * A Function to set the icon state and insert a record into
1059 * m_directoryIconStateHash when an exception is added by the user
1061 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1064 fullPathtoSubPaths(paths, fullPath);
1065 /* an exception that causes the item in the file table to be "Checked" has occured */
1066 if (excpState == Qt::Checked) {
1067 bool foundAsUnChecked = false;
1068 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1070 if (firstItem->checkState(0) == Qt::Unchecked)
1071 foundAsUnChecked = true;
1073 if (foundAsUnChecked) {
1074 /* as long as directory item is Unchecked, set icon state to "green check" */
1076 QListIterator<QString> siter(paths);
1077 while (siter.hasNext() && !done) {
1078 QString path = siter.next();
1079 QTreeWidgetItem *item = m_dirPaths.value(path);
1081 if (item->checkState(0) != Qt::Unchecked)
1084 directorySetIcon(1, FolderGreenChecked, path, item);
1085 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1090 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1091 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1093 QListIterator<QString> siter(paths);
1094 while (siter.hasNext() && !done) {
1095 QString path = siter.next();
1096 QTreeWidgetItem *item = m_dirPaths.value(path);
1097 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1098 if (item->checkState(0) == Qt::Checked)
1100 directorySetIcon(1, FolderGreenChecked, path, item);
1101 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1106 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1107 if (excpState == Qt::Unchecked) {
1109 QListIterator<QString> siter(paths);
1110 while (siter.hasNext() && !done) {
1111 QString path = siter.next();
1112 QTreeWidgetItem *item = m_dirPaths.value(path);
1113 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1114 if (item->checkState(0) == Qt::Checked)
1116 directorySetIcon(1, FolderWhiteChecked, path, item);
1117 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1124 * A function to set the icon state back to "folder" and to remove a record from
1125 * m_directoryIconStateHash when an exception is removed by a user.
1127 void restoreTree::directoryIconStateRemove()
1129 QHash<QString, int> shouldBeIconStateHash;
1130 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1131 /* Use iterator tera to iterate through m_fileExceptionHash */
1132 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1133 while (tera.hasNext()) {
1135 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1137 QString keyPath = tera.key();
1138 Qt::CheckState state = tera.value();
1141 fullPathtoSubPaths(paths, keyPath);
1142 /* if the state of the item in m_fileExceptionHash is checked
1143 * each of the subpaths should be "Checked Green" */
1144 if (state == Qt::Checked) {
1146 bool foundAsUnChecked = false;
1147 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1149 if (firstItem->checkState(0) == Qt::Unchecked)
1150 foundAsUnChecked = true;
1152 if (foundAsUnChecked) {
1153 /* The right most directory is Unchecked, iterate leftwards
1154 * as long as directory item is Unchecked, set icon state to "green check" */
1156 QListIterator<QString> siter(paths);
1157 while (siter.hasNext() && !done) {
1158 QString path = siter.next();
1159 QTreeWidgetItem *item = m_dirPaths.value(path);
1161 if (item->checkState(0) != Qt::Unchecked)
1164 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1165 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1171 /* The right most directory is Unchecked, iterate leftwards
1172 * until directory item is Checked, set icon state to "green check" */
1174 QListIterator<QString> siter(paths);
1175 while (siter.hasNext() && !done) {
1176 QString path = siter.next();
1177 QTreeWidgetItem *item = m_dirPaths.value(path);
1179 if (item->checkState(0) == Qt::Checked)
1181 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1186 /* if the state of the item in m_fileExceptionHash is UNChecked
1187 * each of the subpaths should be "Checked white" until the tree item
1188 * which represents that path is Qt::Checked */
1189 if (state == Qt::Unchecked) {
1191 QListIterator<QString> siter(paths);
1192 while (siter.hasNext() && !done) {
1193 QString path = siter.next();
1194 QTreeWidgetItem *item = m_dirPaths.value(path);
1196 if (item->checkState(0) == Qt::Checked)
1198 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1203 /* now iterate through m_directoryIconStateHash which are the items that are checked
1204 * and remove all of those that are not in shouldBeIconStateHash */
1205 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1206 while (iter.hasNext()) {
1208 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1210 QString keyPath = iter.key();
1211 if (shouldBeIconStateHash.value(keyPath)) {
1212 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1213 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1214 int newval = shouldBeIconStateHash.value(keyPath);
1216 newval = newval & FolderBothChecked;
1217 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1219 directorySetIcon(0, newval, keyPath, item);
1221 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1222 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1224 directorySetIcon(0, FolderBothChecked, keyPath, item);
1225 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1226 //m_directoryIconStateHash.remove(keyPath);
1231 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1233 /* we are adding a check type white or green */
1234 if (operation > 0) {
1235 /* get the old val and "bitwise OR" with the change */
1236 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1237 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1238 m_directoryIconStateHash.insert(path, newval);
1240 /* we are removing a check type white or green */
1241 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1243 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1244 m_directoryIconStateHash.remove(path);
1247 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1248 m_directoryIconStateHash.insert(path, newval);
1251 if (newval == FolderUnchecked)
1252 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1253 else if (newval == FolderGreenChecked)
1254 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1255 else if (newval == FolderWhiteChecked)
1256 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1257 else if (newval == FolderBothChecked)
1258 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1264 void restoreTree::testButtonPushed()
1266 QMultiHash<int, QString> versionFilesMulti;
1267 QHash <QString, bool> fullPathDone;
1268 QHash <QString, int> fileIndexHash;
1269 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1270 Pmsg0(000, "In restoreTree::testButtonPushed\n");
1271 /* Use a tree widget item iterator filtering for Checked Items */
1272 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1274 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1275 if (mainWin->m_rtRestore1Debug)
1276 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1277 /* With a checked directory, query for the files in the directory */
1280 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1282 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1284 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1285 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1286 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1287 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1288 " AND Job.Jobid IN (" + m_jobQuery + ")"
1289 " GROUP BY Filename.Name"
1291 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1292 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1293 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1295 " Path.Path='" + directory + "'"
1296 " AND Filename.Name=t1.Filename"
1297 " AND Job.Jobid=t1.JobId"
1298 " ORDER BY Filename";
1300 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1301 QStringList results;
1302 if (m_console->sql_cmd(cmd, results)) {
1304 QStringList fieldlist;
1307 /* Iterate through the record returned from the query */
1308 foreach (QString resultline, results) {
1309 /* Iterate through fields in the record */
1311 QString fullPath = "";
1312 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1313 fieldlist = resultline.split("\t");
1316 foreach (QString field, fieldlist) {
1318 fullPath = directory + field;
1321 version = field.toInt();
1324 fileIndex = field.toInt();
1328 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1330 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1331 if (fileExcpState != Qt::Unchecked) {
1333 if (excpVersion != 0) {
1334 debugtext = QString("*E* version=%1").arg(excpVersion);
1335 version = excpVersion;
1336 fileIndex = queryFileIndex(fullPath, excpVersion);
1338 debugtext = QString("___ version=%1").arg(version);
1339 if (mainWin->m_rtRestore1Debug)
1340 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1341 fullPathDone.insert(fullPath, 1);
1342 fileIndexHash.insert(fullPath, fileIndex);
1343 versionFilesMulti.insert(version, fullPath);
1349 } /* while (*diter) */
1351 /* There may be some exceptions not accounted for yet with fullPathDone */
1352 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1353 while (ftera.hasNext()) {
1355 QString fullPath = ftera.key();
1356 Qt::CheckState state = ftera.value();
1358 /* now we don't want the ones already done */
1359 if (fullPathDone.value(fullPath, 0) == 0) {
1360 int version = m_versionExceptionHash.value(fullPath, 0);
1362 QString debugtext = "";
1364 fileIndex = queryFileIndex(fullPath, version);
1365 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1367 version = mostRecentVersionfromFullPath(fullPath);
1369 fileIndex = queryFileIndex(fullPath, version);
1370 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1372 debugtext = QString("Error det vers").arg(version);
1374 if (mainWin->m_rtRestore1Debug)
1375 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1376 versionFilesMulti.insert(version, fullPath);
1377 fileIndexHash.insert(fullPath, fileIndex);
1378 } /* if fullPathDone.value(fullPath, 0) == 0 */
1379 } /* if state != 0 */
1380 } /* while ftera.hasNext */
1382 /* now for the final spit out of the versions and lists of files for each version */
1383 QHash<int, int> doneKeys;
1384 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1385 QString tempTable = "";
1387 while (vFMiter.hasNext()) {
1389 int fversion = vFMiter.key();
1390 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1391 if (doneKeys.value(fversion, 0) == 0) {
1392 if (tempTable == "") {
1393 QSettings settings("www.bacula.org", "bat");
1394 settings.beginGroup("Restore");
1395 int counter = settings.value("Counter", 1).toInt();
1396 settings.setValue("Counter", counter+1);
1397 settings.endGroup();
1398 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1399 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1400 if (mainWin->m_sqlDebug)
1401 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1402 QStringList results;
1403 if (!m_console->sql_cmd(sqlcmd, results))
1404 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1407 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1408 QStringList fullPathList = versionFilesMulti.values(fversion);
1409 /* create the command to perform the restore */
1410 foreach(QString ffullPath, fullPathList) {
1411 int fileIndex = fileIndexHash.value(ffullPath);
1412 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1413 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1414 if (mainWin->m_sqlDebug)
1415 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1416 QStringList results;
1417 if (!m_console->sql_cmd(sqlcmd, results))
1418 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1419 } /* foreach fullPathList */
1420 doneKeys.insert(fversion,1);
1421 jobList.append(fversion);
1422 } /* if (doneKeys.value(fversion, 0) == 0) */
1423 } /* while (vFMiter.hasNext()) */
1424 if (tempTable != "") {
1425 QString jobOption = " jobid=\"";
1427 foreach (int job, jobList) {
1428 if (first) first = false;
1429 else jobOption += ",";
1430 jobOption += QString("%1").arg(job);
1433 QString cmd = QString("restore");
1434 cmd += " client=\"" + m_prevClientCombo + "\""
1436 " file=\"?" + tempTable + "\" yes";
1437 if (mainWin->m_commandDebug)
1438 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1439 consoleCommand(cmd);
1440 mainWin->resetFocus();
1444 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1447 QString directory, fileName;
1448 int index = m_slashregex.lastIndexIn(fullPath, -2);
1450 directory = fileName = fullPath;
1451 directory.replace(index+1, fullPath.length()-index-1, "");
1452 fileName.replace(0, index+1, "");
1454 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1455 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1456 Pmsg0(000, msg.toUtf8().data());
1458 /* so now we need the latest version from the database */
1460 "SELECT MAX(Job.JobId)"
1462 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1463 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1464 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1465 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1466 " AND Job.Jobid IN (" + m_jobQuery + ")"
1467 " AND Filename.Name='" + fileName + "'"
1468 " GROUP BY Filename.Name";
1470 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1471 QStringList results;
1472 if (m_console->sql_cmd(cmd, results)) {
1473 QStringList fieldlist;
1475 /* Iterate through the record returned from the query */
1476 foreach (QString resultline, results) {
1477 /* Iterate through fields in the record */
1479 fieldlist = resultline.split("\t");
1480 foreach (QString field, fieldlist) {
1482 qversion = field.toInt();
1489 } /* if (index != -1) */
1494 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1497 QString directory, fileName;
1498 int index = m_slashregex.lastIndexIn(fullPath, -2);
1500 directory = fileName = fullPath;
1501 directory.replace(index+1, fullPath.length()-index-1, "");
1502 fileName.replace(0, index+1, "");
1504 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1505 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1506 Pmsg0(000, msg.toUtf8().data());
1508 /* so now we need the latest version from the database */
1513 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1514 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1515 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1517 " Path.Path='" + directory + "'"
1518 " AND Filename.Name='" + fileName + "'"
1519 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1520 " GROUP BY File.FileIndex";
1522 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1523 QStringList results;
1524 if (m_console->sql_cmd(cmd, results)) {
1525 QStringList fieldlist;
1527 /* Iterate through the record returned from the query */
1528 foreach (QString resultline, results) {
1529 /* Iterate through fields in the record */
1531 fieldlist = resultline.split("\t");
1532 foreach (QString field, fieldlist) {
1534 qfileIndex = field.toInt();
1541 } /* if (index != -1) */