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());
146 m_JobsCheckedList = "";
148 /* Update the items in the version table */
149 int cnt = jobTable->rowCount();
150 for (int row=0; row<cnt; row++) {
151 QTableWidgetItem* jobItem = jobTable->item(row, 0);
152 if (jobItem->checkState() == Qt::Checked) {
154 m_JobsCheckedList += ",";
155 m_JobsCheckedList += jobItem->text();
157 jobItem->setBackground(Qt::green);
159 jobItem->setBackground(Qt::gray);
161 m_jobQuery = m_JobsCheckedList;
165 "SELECT DISTINCT Path.Path"
167 " LEFT OUTER JOIN File ON (File.PathId=Path.PathId)"
168 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
169 " WHERE Job.Jobid IN (" + m_jobQuery + ")";
170 if (mainWin->m_sqlDebug) {
171 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
173 QStringList directories;
174 if (m_console->sql_cmd(cmd, directories)) {
175 if (mainWin->m_miscDebug) {
176 Pmsg1(000, "Done with query %i directories\n", directories.count());
178 foreach(QString directory, directories) {
180 parseDirectory(directory);
186 * Function to parse a directory into all possible subdirectories, then add to
189 void restoreTree::parseDirectory(QString &dir_in)
191 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
192 * instead of printing out what could potentially a whole bunch */
195 /* Clean up the directory string remove some funny char after last '/' */
196 QRegExp rgx("[^/]$");
197 int lastslash = rgx.indexIn(dir_in);
198 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
199 if ((mainWin->m_miscDebug) && (m_debugTrap))
200 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
202 /* split and add if not in yet */
203 QString direct, path;
206 QStringList pathAfter, dirAfter;
207 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
208 * if not added into tree, then try /etc/ and somedir/ if not added, then try
209 * / and etc/ . That should succeed, then add the ones that failed in reverse */
210 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
211 direct = path = dir_in;
212 path.replace(index+1, dir_in.length()-index-1,"");
213 direct.replace(0, index+1, "");
214 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
215 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
216 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
217 Pmsg0(000, msg.toUtf8().data());
219 if (addDirectory(path, direct)) done = true;
221 if ((mainWin->m_miscDebug) && (m_debugTrap))
222 Pmsg0(000, "Saving for later\n");
223 pathAfter.prepend(path);
224 dirAfter.prepend(direct);
229 for (int k=0; k<pathAfter.count(); k++) {
230 if (addDirectory(pathAfter[k], dirAfter[k]))
231 if ((mainWin->m_miscDebug) && (m_debugTrap))
232 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
234 if ((mainWin->m_miscDebug) && (m_debugTrap))
235 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
240 * Function called from fill directory when a directory is found to see if this
241 * directory exists in the directory pane and then add it to the directory pane
243 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
245 QString newdir = newdirr;
246 QString fullPath = m_cwd + newdirr;
247 bool ok = true, added = false;
249 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
250 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
253 Pmsg0(000, msg.toUtf8().data());
257 /* add unix '/' directory first */
258 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
260 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
262 item->setText(0, text.toUtf8().data());
263 item->setData(0, Qt::UserRole, QVariant(text));
264 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
265 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
266 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
267 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
269 m_dirPaths.insert(text, item);
271 /* no need to check for windows drive if unix */
272 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
273 /* this is a windows drive add the base widget */
274 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
275 item->setText(0, m_cwd);
276 item->setData(0, Qt::UserRole, QVariant(fullPath));
277 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
278 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
279 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
280 Pmsg0(000, "Added Base \"letter\":/\n");
282 m_dirPaths.insert(m_cwd, item);
286 /* is it already existent ?? */
287 if (!m_dirPaths.contains(fullPath)) {
288 QTreeWidgetItem *item = NULL;
289 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
291 /* new directories to add */
292 item = new QTreeWidgetItem(parent);
293 item->setText(0, newdir.toUtf8().data());
294 item->setData(0, Qt::UserRole, QVariant(fullPath));
295 item->setCheckState(0, Qt::Unchecked);
296 /* Store the current state of the check status in column 1, which at
297 * this point has no text*/
298 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
301 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
302 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
305 Pmsg0(000, msg.toUtf8().data());
308 /* insert into hash */
310 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
311 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
313 m_dirPaths.insert(fullPath, item);
321 * Virtual function which is called when this page is visible on the stack
323 void restoreTree::currentStackItem()
326 if (!m_console->preventInUseConnect())
334 * Populate the tree when refresh button pushed.
336 void restoreTree::refreshButtonPushed()
338 populateDirectoryTree();
342 * Set the values of non-job combo boxes to the job defaults
344 void restoreTree::jobComboChanged(int)
346 job_defaults job_defs;
349 job_defs.job_name = jobCombo->currentText();
350 if (m_console->get_job_defaults(job_defs)) {
351 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
352 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
357 * Function to populate the file list table
359 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
364 m_fileCheckStateList.clear();
365 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
366 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
367 QBrush blackBrush(Qt::black);
368 QString directory = item->data(0, Qt::UserRole).toString();
369 directoryLabel->setText("Present Working Directory : " + directory);
371 "SELECT DISTINCT Filename.Name"
373 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
374 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
375 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
376 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
377 " AND Job.Jobid IN (" + m_jobQuery + ")";
379 QStringList headerlist = (QStringList() << "File Name");
381 /* Also clear the version table here */
382 versionTable->clear();
383 versionFileLabel->setText("");
384 versionTable->setRowCount(0);
385 versionTable->setColumnCount(0);
386 fileTable->setColumnCount(headerlist.size());
387 fileTable->setHorizontalHeaderLabels(headerlist);
389 if (mainWin->m_sqlDebug) {
390 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
393 if (m_console->sql_cmd(cmd, results)) {
395 QTableWidgetItem* tableItem;
397 QStringList fieldlist;
398 fileTable->setRowCount(results.size());
401 /* Iterate through the record returned from the query */
402 foreach (QString resultline, results) {
403 /* Iterate through fields in the record */
405 fieldlist = resultline.split("\t");
406 foreach (field, fieldlist) {
407 field = field.trimmed(); /* strip leading & trailing spaces */
408 tableItem = new QTableWidgetItem(field, 1);
409 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
410 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
411 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
412 tableItem->setForeground(blackBrush);
413 /* Just in case a column ever gets added */
415 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
416 tableItem->setFlags(flag);
417 tableItem->setData(Qt::UserRole, QVariant(directory));
418 fileTable->setItem(row, column, tableItem);
419 m_fileCheckStateList.append(Qt::Unchecked);
420 tableItem->setCheckState(Qt::Unchecked);
426 fileTable->setRowCount(row);
428 fileTable->resizeColumnsToContents();
429 fileTable->resizeRowsToContents();
430 fileTable->verticalHeader()->hide();
431 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
432 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
433 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
434 updateFileTableChecks();
438 * Function to populate the version table
440 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
442 if (fileTableItem == NULL)
445 m_versionCheckStateList.clear();
446 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
447 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
449 QString file = fileTableItem->text();
450 versionFileLabel->setText(file);
451 QString directory = fileTableItem->data(Qt::UserRole).toString();
453 QBrush blackBrush(Qt::black);
455 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5"
457 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
458 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
459 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
460 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
461 " AND Job.Jobid IN (" + m_jobQuery + ")"
462 " ORDER BY Job.EndTime DESC";
464 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5");
465 versionTable->clear();
466 versionTable->setColumnCount(headerlist.size());
467 versionTable->setHorizontalHeaderLabels(headerlist);
469 if (mainWin->m_sqlDebug) {
470 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
473 if (m_console->sql_cmd(cmd, results)) {
475 QTableWidgetItem* tableItem;
477 QStringList fieldlist;
478 versionTable->setRowCount(results.size());
481 /* Iterate through the record returned from the query */
482 foreach (QString resultline, results) {
483 fieldlist = resultline.split("\t");
485 /* remove directory */
486 if (fieldlist[0].trimmed() != "") {
487 /* Iterate through fields in the record */
488 foreach (field, fieldlist) {
489 field = field.trimmed(); /* strip leading & trailing spaces */
490 tableItem = new QTableWidgetItem(field, 1);
491 tableItem->setFlags(0);
492 tableItem->setForeground(blackBrush);
493 tableItem->setData(Qt::UserRole, QVariant(directory));
494 versionTable->setItem(row, column, tableItem);
497 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
498 tableItem->setFlags(flag);
499 m_versionCheckStateList.append(Qt::Unchecked);
500 tableItem->setCheckState(Qt::Unchecked);
508 versionTable->resizeColumnsToContents();
509 versionTable->resizeRowsToContents();
510 versionTable->verticalHeader()->hide();
511 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
512 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
513 updateVersionTableChecks();
517 * Save user settings associated with this page
519 void restoreTree::writeSettings()
521 QSettings settings(m_console->m_dir->name(), "bat");
522 settings.beginGroup("RestoreTree");
523 settings.setValue("splitterSizes", splitter->saveState());
528 * Read and restore user settings associated with this page
530 void restoreTree::readSettings()
532 QSettings settings(m_console->m_dir->name(), "bat");
533 settings.beginGroup("RestoreTree");
534 splitter->restoreState(settings.value("splitterSizes").toByteArray());
539 * This is a funcion to accomplish the one thing I struggled to figure out what
540 * was taking so long. It add the icons, but after the tree is made. Seemed to
541 * work fast after changing from svg to png file for graphic.
543 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
545 int childCount = item->childCount();
546 for (int i=0; i<childCount; i++) {
547 QTreeWidgetItem *child = item->child(i);
548 if (child->icon(0).isNull())
549 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
554 * I wanted a table to show what jobs meet the criterion and are being used to
555 * populate the directory tree and file and version tables.
557 void restoreTree::populateJobTable()
559 QBrush blackBrush(Qt::black);
560 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
562 jobTable->setColumnCount(headerlist.size());
563 jobTable->setHorizontalHeaderLabels(headerlist);
565 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
566 " FROM Job" + m_jobQueryPart +
567 " ORDER BY Job.EndTime DESC";
568 if (mainWin->m_sqlDebug) {
569 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
573 if (m_console->sql_cmd(jobQuery, results)) {
575 QTableWidgetItem* tableItem;
577 QStringList fieldlist;
578 jobTable->setRowCount(results.size());
581 /* Iterate through the record returned from the query */
582 foreach (QString resultline, results) {
583 fieldlist = resultline.split("\t");
585 /* remove directory */
586 if (fieldlist[0].trimmed() != "") {
587 /* Iterate through fields in the record */
588 foreach (field, fieldlist) {
589 field = field.trimmed(); /* strip leading & trailing spaces */
590 tableItem = new QTableWidgetItem(field, 1);
591 tableItem->setFlags(0);
592 tableItem->setForeground(blackBrush);
593 jobTable->setItem(row, column, tableItem);
595 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
596 tableItem->setFlags(flag);
597 tableItem->setCheckState(Qt::Checked);
598 tableItem->setBackground(Qt::green);
606 jobTable->resizeColumnsToContents();
607 jobTable->resizeRowsToContents();
608 jobTable->verticalHeader()->hide();
612 * When a directory item is "changed" check the state of the checkable item
613 * to see if it is different than what it was which is stored in Qt::UserRole
614 * of the 2nd column, column 1, of the tree widget.
616 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
618 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
619 Qt::CheckState curState = item->checkState(0);
620 QTreeWidgetItem* parent = item->parent();
621 Qt::CheckState parState;
622 if (parent) parState = parent->checkState(0);
623 else parState = (Qt::CheckState)3;
624 if (mainWin->m_rtDirICDebug) {
625 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
626 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
627 Pmsg1(000, "%s", msg.toUtf8().data()); }
628 /* I only care when the check state changes */
629 if (prevState == curState) {
630 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
634 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
635 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
636 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
637 curState = Qt::PartiallyChecked;
639 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
640 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
641 directoryTreeDisconnectedSet(item, Qt::Unchecked);
642 curState = Qt::Unchecked;
644 if (mainWin->m_rtDirICDebug) {
645 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
646 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
647 Pmsg1(000, "%s", msg.toUtf8().data()); }
649 item->setData(1, Qt::UserRole, QVariant(curState));
650 Qt::CheckState childState = curState;
651 if (childState == Qt::Checked)
652 childState = Qt::PartiallyChecked;
653 setCheckofChildren(item, childState);
655 /* Remove items from the exception lists. The multi exception list is my index
656 * of what exceptions can be removed when the directory is known*/
657 QString directory = item->data(0, Qt::UserRole).toString();
658 QStringList fullPathList = m_fileExceptionMulti.values(directory);
659 int fullPathListCount = fullPathList.count();
660 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
661 foreach (QString fullPath, fullPathList) {
662 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
663 * which will match no Qt::xxx values */
664 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
665 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
666 if (hashState == Qt::Unchecked) {
667 fileExceptionRemove(fullPath, directory);
668 m_versionExceptionHash.remove(fullPath);
669 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
671 if (hashState == Qt::Checked) {
672 fileExceptionRemove(fullPath, directory);
673 m_versionExceptionHash.remove(fullPath);
674 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
678 if (item == directoryTree->currentItem()) {
679 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
680 updateFileTableChecks();
681 versionTable->clear();
682 versionTable->setRowCount(0);
683 versionTable->setColumnCount(0);
685 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
689 * When a directory item check state is changed, this function iterates through
690 * all subdirectories and sets all to the passed state, which is either partially
691 * checked or unchecked.
693 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
696 childCount = item->childCount();
697 for (int i=0; i<childCount; i++) {
698 QTreeWidgetItem *child = item->child(i);
699 child->setData(1, Qt::UserRole, QVariant(state));
700 child->setCheckState(0, state);
701 setCheckofChildren(child, state);
706 * When a File Table Item is "changed" check to see if the state of the checkable
707 * item has changed which is stored in m_fileCheckStateList
708 * If changed store in a hash m_fileExceptionHash that whether this file should be
710 * Called as a slot, connected after populated (after directory current changed called)
712 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
714 /* get the previous and current check states */
715 int row = fileTable->row(item);
716 Qt::CheckState prevState;
717 /* prevent a segfault */
718 prevState = m_fileCheckStateList[row];
719 Qt::CheckState curState = item->checkState();
721 /* deterimine the default state from the state of the directory */
722 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
723 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
724 Qt::CheckState defState = Qt::PartiallyChecked;
725 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
727 /* determine if it is already in the m_fileExceptionHash */
728 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
729 QString file = item->text();
730 QString fullPath = directory + file;
731 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
732 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
734 if (mainWin->m_rtFileTabICDebug) {
735 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
736 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
737 Pmsg1(000, "%s", msg.toUtf8().data()); }
739 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
740 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
741 /* it can behave as defaulted so current of unchecked is fine */
742 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
743 fileExceptionRemove(fullPath, directory);
744 m_versionExceptionHash.remove(fullPath);
745 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
746 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
747 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
748 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
749 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
750 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
751 fileExceptionRemove(fullPath, directory);
752 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
753 /* Check dir, check version, attempt uncheck in file
754 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
755 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
756 fileExceptionRemove(fullPath, directory);
757 m_versionExceptionHash.remove(fullPath);
758 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
759 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
760 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
761 } else if (prevState != curState) {
762 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
763 /* A user did not set the check state to Partially checked, ignore if so */
764 if (curState != Qt::PartiallyChecked) {
765 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
766 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
768 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
769 fileExceptionInsert(fullPath, directory, curState);
772 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
773 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
774 m_versionExceptionHash.remove(fullPath);
778 updateFileTableChecks();
779 updateVersionTableChecks();
783 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
785 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
787 m_fileExceptionHash.insert(fullPath, state);
788 m_fileExceptionMulti.insert(direcotry, fullPath);
789 directoryIconStateInsert(fullPath, state);
793 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
795 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
797 m_fileExceptionHash.remove(fullPath);
798 /* pull the list of values in the multi */
799 QStringList fullPathList = m_fileExceptionMulti.values(directory);
800 /* get the index of the fullpath to remove */
801 int index = fullPathList.indexOf(fullPath);
803 /* remove the desired item in the list */
804 fullPathList.removeAt(index);
805 /* remove the entire list from the multi */
806 m_fileExceptionMulti.remove(directory);
807 /* readd the remaining */
808 foreach (QString fp, fullPathList) {
809 m_fileExceptionMulti.insert(directory, fp);
812 directoryIconStateRemove();
816 * Overloaded function to be called from the slot and from other places to set the state
817 * of the check marks in the version table
819 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
821 /* get the previous and current check states */
822 int row = versionTable->row(item);
823 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
824 Qt::CheckState prevState = m_versionCheckStateList[row];
825 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
826 m_versionCheckStateList[row] = curState;
828 /* deterimine the default state from the state of the file */
829 QTableWidgetItem *fileTableItem = fileTable->currentItem();
830 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
832 /* determine the default state */
833 Qt::CheckState defState;
835 defState = Qt::PartiallyChecked;
836 if (fileState == Qt::Unchecked)
837 defState = Qt::Unchecked;
840 defState = Qt::Unchecked;
842 /* determine if it is already in the versionExceptionHash */
843 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
844 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
845 QString file = fileTableItem->text();
846 QString fullPath = directory + file;
847 int thisJobNum = colZeroItem->text().toInt();
848 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
850 if (mainWin->m_rtVerTabICDebug) {
851 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
852 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
853 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
854 Pmsg1(000, "%s", msg.toUtf8().data()); }
855 /* if changed from partially checked to checked, make it unchecked */
856 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
857 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
858 fileTableItem->setCheckState(Qt::Checked);
859 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
860 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
861 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
862 fileExceptionRemove(fullPath, directory);
863 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
864 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
865 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
866 m_versionExceptionHash.remove(fullPath);
867 fileExceptionRemove(fullPath, directory);
868 } else if ((curState == Qt::Checked) && (row == 0)) {
869 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
870 m_versionExceptionHash.remove(fullPath);
871 } else if (prevState != curState) {
872 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
873 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
874 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
875 m_versionExceptionHash.insert(fullPath, thisJobNum);
876 if (fileState != Qt::Checked) {
877 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
878 fileExceptionInsert(fullPath, directory, curState);
881 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
884 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
887 updateFileTableChecks();
888 updateVersionTableChecks();
892 * Simple function to set the check state in the file table by disconnecting the
893 * signal/slot the setting then reconnecting the signal/slot
895 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
897 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
898 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
899 item->setCheckState(state);
900 if (color) item->setBackground(Qt::yellow);
901 else item->setBackground(Qt::white);
902 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
903 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
907 * Simple function to set the check state in the version table by disconnecting the
908 * signal/slot the setting then reconnecting the signal/slot
910 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
912 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
913 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
914 item->setCheckState(state);
915 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
916 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
920 * Simple function to set the check state in the directory tree by disconnecting the
921 * signal/slot the setting then reconnecting the signal/slot
923 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
925 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
926 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
927 item->setCheckState(0, state);
928 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
929 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
933 * Simplify the updating of the check state in the File table by iterating through
934 * each item in the file table to determine it's appropriate state.
935 * !! Will probably want to concoct a way to do this without iterating for the possibility
936 * of the very large directories.
938 void restoreTree::updateFileTableChecks()
940 /* deterimine the default state from the state of the directory */
941 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
942 Qt::CheckState dirState = dirTreeItem->checkState(0);
944 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
946 /* Update the items in the version table */
947 int rcnt = fileTable->rowCount();
948 for (int row=0; row<rcnt; row++) {
949 QTableWidgetItem* item = fileTable->item(row, 0);
951 Qt::CheckState curState = item->checkState();
952 Qt::CheckState newState = Qt::PartiallyChecked;
953 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
955 /* determine if it is already in the m_fileExceptionHash */
956 QString file = item->text();
957 QString fullPath = dirName + file;
958 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
959 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
961 if (hashState != 3) newState = hashState;
963 if (mainWin->m_rtUpdateFTDebug) {
964 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
965 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
966 Pmsg1(000, "%s", msg.toUtf8().data());
969 bool docolor = false;
970 if (hashJobNum != 0) docolor = true;
971 bool isyellow = item->background().color() == QColor(Qt::yellow);
972 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
973 fileTableDisconnectedSet(item, newState, docolor);
974 m_fileCheckStateList[row] = newState;
979 * Simplify the updating of the check state in the Version table by iterating through
980 * each item in the file table to determine it's appropriate state.
982 void restoreTree::updateVersionTableChecks()
984 /* deterimine the default state from the state of the directory */
985 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
986 Qt::CheckState dirState = dirTreeItem->checkState(0);
987 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
989 /* deterimine the default state from the state of the file */
990 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
991 Qt::CheckState fileState = fileTableItem->checkState();
992 QString file = fileTableItem->text();
993 QString fullPath = dirName + file;
994 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
996 /* Update the items in the version table */
997 int cnt = versionTable->rowCount();
998 for (int row=0; row<cnt; row++) {
999 QTableWidgetItem* item = versionTable->item(row, 0);
1001 Qt::CheckState curState = item->checkState();
1002 Qt::CheckState newState = Qt::Unchecked;
1004 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1005 newState = Qt::PartiallyChecked;
1006 /* determine if it is already in the versionExceptionHash */
1008 int thisJobNum = item->text().toInt();
1009 if (thisJobNum == hashJobNum)
1010 newState = Qt::Checked;
1012 if (mainWin->m_rtChecksDebug) {
1013 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1014 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1015 Pmsg1(000, "%s", msg.toUtf8().data());
1017 if (newState != curState)
1018 versionTableDisconnectedSet(item, newState);
1019 m_versionCheckStateList[row] = newState;
1024 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1026 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1030 QString fullPath = fullPath_in;
1031 QString direct, path;
1032 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1033 direct = path = fullPath;
1034 path.replace(index+1, fullPath.length()-index-1, "");
1035 direct.replace(0, index+1, "");
1037 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1038 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1039 Pmsg0(000, msg.toUtf8().data());
1042 subPaths.append(fullPath);
1047 * A Function to set the icon state and insert a record into
1048 * m_directoryIconStateHash when an exception is added by the user
1050 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1053 fullPathtoSubPaths(paths, fullPath);
1054 /* an exception that causes the item in the file table to be "Checked" has occured */
1055 if (excpState == Qt::Checked) {
1056 bool foundAsUnChecked = false;
1057 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1059 if (firstItem->checkState(0) == Qt::Unchecked)
1060 foundAsUnChecked = true;
1062 if (foundAsUnChecked) {
1063 /* as long as directory item is Unchecked, set icon state to "green check" */
1065 QListIterator<QString> siter(paths);
1066 while (siter.hasNext() && !done) {
1067 QString path = siter.next();
1068 QTreeWidgetItem *item = m_dirPaths.value(path);
1070 if (item->checkState(0) != Qt::Unchecked)
1073 directorySetIcon(1, FolderGreenChecked, path, item);
1074 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1079 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1080 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1082 QListIterator<QString> siter(paths);
1083 while (siter.hasNext() && !done) {
1084 QString path = siter.next();
1085 QTreeWidgetItem *item = m_dirPaths.value(path);
1086 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1087 if (item->checkState(0) == Qt::Checked)
1089 directorySetIcon(1, FolderGreenChecked, path, item);
1090 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1095 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1096 if (excpState == Qt::Unchecked) {
1098 QListIterator<QString> siter(paths);
1099 while (siter.hasNext() && !done) {
1100 QString path = siter.next();
1101 QTreeWidgetItem *item = m_dirPaths.value(path);
1102 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1103 if (item->checkState(0) == Qt::Checked)
1105 directorySetIcon(1, FolderWhiteChecked, path, item);
1106 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1113 * A function to set the icon state back to "folder" and to remove a record from
1114 * m_directoryIconStateHash when an exception is removed by a user.
1116 void restoreTree::directoryIconStateRemove()
1118 QHash<QString, int> shouldBeIconStateHash;
1119 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1120 /* Use iterator tera to iterate through m_fileExceptionHash */
1121 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1122 while (tera.hasNext()) {
1124 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1126 QString keyPath = tera.key();
1127 Qt::CheckState state = tera.value();
1130 fullPathtoSubPaths(paths, keyPath);
1131 /* if the state of the item in m_fileExceptionHash is checked
1132 * each of the subpaths should be "Checked Green" */
1133 if (state == Qt::Checked) {
1135 bool foundAsUnChecked = false;
1136 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1138 if (firstItem->checkState(0) == Qt::Unchecked)
1139 foundAsUnChecked = true;
1141 if (foundAsUnChecked) {
1142 /* The right most directory is Unchecked, iterate leftwards
1143 * as long as directory item is Unchecked, set icon state to "green check" */
1145 QListIterator<QString> siter(paths);
1146 while (siter.hasNext() && !done) {
1147 QString path = siter.next();
1148 QTreeWidgetItem *item = m_dirPaths.value(path);
1150 if (item->checkState(0) != Qt::Unchecked)
1153 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1154 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1160 /* The right most directory is Unchecked, iterate leftwards
1161 * until directory item is Checked, set icon state to "green check" */
1163 QListIterator<QString> siter(paths);
1164 while (siter.hasNext() && !done) {
1165 QString path = siter.next();
1166 QTreeWidgetItem *item = m_dirPaths.value(path);
1168 if (item->checkState(0) == Qt::Checked)
1170 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1175 /* if the state of the item in m_fileExceptionHash is UNChecked
1176 * each of the subpaths should be "Checked white" until the tree item
1177 * which represents that path is Qt::Checked */
1178 if (state == Qt::Unchecked) {
1180 QListIterator<QString> siter(paths);
1181 while (siter.hasNext() && !done) {
1182 QString path = siter.next();
1183 QTreeWidgetItem *item = m_dirPaths.value(path);
1185 if (item->checkState(0) == Qt::Checked)
1187 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1192 /* now iterate through m_directoryIconStateHash which are the items that are checked
1193 * and remove all of those that are not in shouldBeIconStateHash */
1194 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1195 while (iter.hasNext()) {
1197 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1199 QString keyPath = iter.key();
1200 if (shouldBeIconStateHash.value(keyPath)) {
1201 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1202 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1203 int newval = shouldBeIconStateHash.value(keyPath);
1205 newval = newval & FolderBothChecked;
1206 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1208 directorySetIcon(0, newval, keyPath, item);
1210 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1211 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1213 directorySetIcon(0, FolderBothChecked, keyPath, item);
1214 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1215 //m_directoryIconStateHash.remove(keyPath);
1220 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1222 /* we are adding a check type white or green */
1223 if (operation > 0) {
1224 /* get the old val and "bitwise OR" with the change */
1225 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1226 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1227 m_directoryIconStateHash.insert(path, newval);
1229 /* we are removing a check type white or green */
1230 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1232 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1233 m_directoryIconStateHash.remove(path);
1236 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1237 m_directoryIconStateHash.insert(path, newval);
1240 if (newval == FolderUnchecked)
1241 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1242 else if (newval == FolderGreenChecked)
1243 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1244 else if (newval == FolderWhiteChecked)
1245 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1246 else if (newval == FolderBothChecked)
1247 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1253 void restoreTree::testButtonPushed()
1255 QMultiHash<int, QString> versionFilesMulti;
1256 QHash <QString, bool> fullPathDone;
1257 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1258 Pmsg0(000, "In restoreTree::testButtonPushed\n");
1259 /* Use a tree widget item iterator filtering for Checked Items */
1260 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1262 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1263 if (mainWin->m_rtRestore1Debug)
1264 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1265 /* With a checked directory, query for the files in the directory */
1267 "SELECT DISTINCT Filename.Name, MAX(Job.JobId)"
1269 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1270 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1271 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1272 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1273 " AND Job.Jobid IN (" + m_jobQuery + ")"
1274 " GROUP BY Filename.Name";
1276 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1277 QStringList results;
1278 if (m_console->sql_cmd(cmd, results)) {
1280 QStringList fieldlist;
1283 /* Iterate through the record returned from the query */
1284 foreach (QString resultline, results) {
1285 /* Iterate through fields in the record */
1287 QString fullPath = "";
1288 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1289 fieldlist = resultline.split("\t");
1291 foreach (QString field, fieldlist) {
1293 fullPath = directory + field;
1296 version = field.toInt();
1300 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1302 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1303 if (fileExcpState != Qt::Unchecked) {
1305 if (excpVersion != 0) {
1306 debugtext = QString("*E* version=%1").arg(excpVersion);
1307 version = excpVersion;
1309 debugtext = QString("___ version=%1").arg(version);
1310 if (mainWin->m_rtRestore1Debug)
1311 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1312 fullPathDone.insert(fullPath, 1);
1313 versionFilesMulti.insert(version, fullPath);
1319 } /* while (*diter) */
1321 /* There may be some exceptions not accounted for yet with fullPathDone */
1322 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1323 while (ftera.hasNext()) {
1325 QString fullPath = ftera.key();
1326 Qt::CheckState state = ftera.value();
1328 /* now we don't want the ones already done */
1329 if (fullPathDone.value(fullPath, 0) == 0) {
1330 int version = m_versionExceptionHash.value(fullPath, 0);
1331 QString debugtext = "";
1333 debugtext = QString("E1* version=%1").arg(version);
1335 version = mostRecentVersionfromFullPath(fullPath);
1337 debugtext = QString("E2* version=%1").arg(version);
1339 debugtext = QString("Error det vers").arg(version);
1341 if (mainWin->m_rtRestore1Debug)
1342 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1343 versionFilesMulti.insert(version, fullPath);
1344 } /* if fullPathDone.value(fullPath, 0) == 0 */
1345 } /* if state != 0 */
1346 } /* while ftera.hasNext */
1348 /* now for the final spit out of the versions and lists of files for each version */
1349 QHash<int, int> doneKeys;
1350 QHashIterator<int, QString> miter(versionFilesMulti);
1351 while (miter.hasNext()) {
1353 int fversion = miter.key();
1354 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1355 if (doneKeys.value(fversion, 0) == 0) {
1356 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1357 QStringList fullPathList = versionFilesMulti.values(fversion);
1358 /* create the command to perform the restore */
1359 QString cmd = QString("restore");
1360 cmd += " client=\"" + m_prevClientCombo + "\""
1361 " jobid=\"" + QString("%1").arg(fversion) + "\" yes";
1362 foreach(QString ffullPath, fullPathList) {
1363 if (mainWin->m_rtRestore2Debug) Pmsg1(000, " file->%s\n", ffullPath.toUtf8().data());
1364 cmd += " file=\"" + ffullPath + "\"";
1367 if (mainWin->m_commandDebug)
1368 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1369 consoleCommand(cmd);
1370 mainWin->resetFocus();
1371 doneKeys.insert(fversion,1);
1376 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1379 QString directory, fileName;
1380 int index = m_slashregex.lastIndexIn(fullPath, -2);
1382 directory = fileName = fullPath;
1383 directory.replace(index+1, fullPath.length()-index-1, "");
1384 fileName.replace(0, index+1, "");
1386 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1387 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1388 Pmsg0(000, msg.toUtf8().data());
1390 /* so now we need the latest version from the database */
1392 "SELECT MAX(Job.JobId)"
1394 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1395 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1396 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1397 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1398 " AND Job.Jobid IN (" + m_jobQuery + ")"
1399 " AND Filename.Name='" + fileName + "'"
1400 " GROUP BY Filename.Name";
1402 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1403 QStringList results;
1404 if (m_console->sql_cmd(cmd, results)) {
1405 QStringList fieldlist;
1407 /* Iterate through the record returned from the query */
1408 foreach (QString resultline, results) {
1409 /* Iterate through fields in the record */
1411 fieldlist = resultline.split("\t");
1412 foreach (QString field, fieldlist) {
1414 qversion = field.toInt();
1421 } /* if (index != -1) */