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"
41 #include "restoretreerun.h"
43 restoreTree::restoreTree()
46 m_name = "Version Browser";
48 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
49 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
56 m_winRegExpDrive.setPattern("^[a-z]:/$");
57 m_winRegExpPath.setPattern("^[a-z]:/");
58 m_slashregex.setPattern("/");
63 restoreTree::~restoreTree()
69 * Called from the constructor to set up the page widgets and connections.
71 void restoreTree::setupPage()
73 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
74 connect(testButton, SIGNAL(pressed()), this, SLOT(testButtonPushed()));
75 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
76 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
77 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
78 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
79 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
80 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
81 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
82 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
83 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
85 QStringList titles = QStringList() << "Directories";
86 directoryTree->setHeaderLabels(titles);
87 clientCombo->addItems(m_console->client_list);
88 fileSetCombo->addItem("Any");
89 fileSetCombo->addItems(m_console->fileset_list);
90 jobCombo->addItems(m_console->job_list);
92 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
96 * When refresh button is pushed, perform a query getting the directories and
97 * use parseDirectory and addDirectory to populate the directory tree with items.
99 void restoreTree::populateDirectoryTree()
103 directoryTree->clear();
105 fileTable->setRowCount(0);
106 fileTable->setColumnCount(0);
107 versionTable->clear();
108 versionTable->setRowCount(0);
109 versionTable->setColumnCount(0);
110 m_fileExceptionHash.clear();
111 m_fileExceptionMulti.clear();
112 m_versionExceptionHash.clear();
113 m_directoryIconStateHash.clear();
116 int clientIndex = clientCombo->currentIndex();
117 int fileSetIndex = fileSetCombo->currentIndex();
118 QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
119 QString clientComboText = clientCombo->itemText(clientIndex);
120 QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
121 if ((m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText)) {
122 m_prevJobCombo = jobComboText;
123 m_prevClientCombo = clientComboText;
124 m_prevFileSetCombo = fileSetComboText;
125 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
127 m_condition = " Job.name = '" + jobCombo->itemText(jobCombo->currentIndex()) + "'";
128 if ((clientIndex >= 0) && (clientCombo->itemText(clientIndex) != "Any")) {
129 m_condition.append(" AND Client.Name='" + clientCombo->itemText(clientIndex) + "'");
131 if ((fileSetIndex >= 0) && (fileSetCombo->itemText(fileSetIndex) != "Any")) {
132 m_condition.append(" AND FileSet.FileSet='" + fileSetCombo->itemText(fileSetIndex) + "'");
135 " LEFT OUTER JOIN Client ON (Job.ClientId=Client.ClientId)"
136 " LEFT OUTER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
137 " WHERE" + m_condition +
138 " AND Job.purgedfiles=0";
141 " From Job" + m_jobQueryPart;
142 if (mainWin->m_sqlDebug) {
143 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
146 setJobsCheckedList();
148 setJobsCheckedList();
152 "SELECT DISTINCT Path.Path AS Path"
154 " LEFT OUTER JOIN File ON (File.PathId=Path.PathId)"
155 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
156 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
158 if (mainWin->m_sqlDebug) {
159 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
161 QStringList directories;
162 if (m_console->sql_cmd(cmd, directories)) {
163 if (mainWin->m_miscDebug) {
164 Pmsg1(000, "Done with query %i directories\n", directories.count());
166 foreach(QString directory, directories) {
168 parseDirectory(directory);
174 * Function to set m_jobQuery from the jobs that are checked in the table
177 void restoreTree::setJobsCheckedList()
179 m_JobsCheckedList = "";
181 /* Update the items in the version table */
182 int cnt = jobTable->rowCount();
183 for (int row=0; row<cnt; row++) {
184 QTableWidgetItem* jobItem = jobTable->item(row, 0);
185 if (jobItem->checkState() == Qt::Checked) {
187 m_JobsCheckedList += ",";
188 m_JobsCheckedList += jobItem->text();
190 jobItem->setBackground(Qt::green);
192 jobItem->setBackground(Qt::gray);
194 m_jobQuery = m_JobsCheckedList;
198 * Function to parse a directory into all possible subdirectories, then add to
201 void restoreTree::parseDirectory(QString &dir_in)
203 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
204 * instead of printing out what could potentially a whole bunch */
207 /* Clean up the directory string remove some funny char after last '/' */
208 QRegExp rgx("[^/]$");
209 int lastslash = rgx.indexIn(dir_in);
210 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
211 if ((mainWin->m_miscDebug) && (m_debugTrap))
212 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
214 /* split and add if not in yet */
215 QString direct, path;
218 QStringList pathAfter, dirAfter;
219 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
220 * if not added into tree, then try /etc/ and somedir/ if not added, then try
221 * / and etc/ . That should succeed, then add the ones that failed in reverse */
222 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
223 direct = path = dir_in;
224 path.replace(index+1, dir_in.length()-index-1,"");
225 direct.replace(0, index+1, "");
226 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
227 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
228 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
229 Pmsg0(000, msg.toUtf8().data());
231 if (addDirectory(path, direct)) done = true;
233 if ((mainWin->m_miscDebug) && (m_debugTrap))
234 Pmsg0(000, "Saving for later\n");
235 pathAfter.prepend(path);
236 dirAfter.prepend(direct);
241 for (int k=0; k<pathAfter.count(); k++) {
242 if (addDirectory(pathAfter[k], dirAfter[k]))
243 if ((mainWin->m_miscDebug) && (m_debugTrap))
244 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
246 if ((mainWin->m_miscDebug) && (m_debugTrap))
247 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
252 * Function called from fill directory when a directory is found to see if this
253 * directory exists in the directory pane and then add it to the directory pane
255 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
257 QString newdir = newdirr;
258 QString fullPath = m_cwd + newdirr;
259 bool ok = true, added = false;
261 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
262 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
265 Pmsg0(000, msg.toUtf8().data());
269 /* add unix '/' directory first */
270 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
272 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
274 item->setText(0, text.toUtf8().data());
275 item->setData(0, Qt::UserRole, QVariant(text));
276 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
277 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
278 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
279 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
281 m_dirPaths.insert(text, item);
283 /* no need to check for windows drive if unix */
284 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
285 /* this is a windows drive add the base widget */
286 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
287 item->setText(0, m_cwd);
288 item->setData(0, Qt::UserRole, QVariant(fullPath));
289 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
290 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
291 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
292 Pmsg0(000, "Added Base \"letter\":/\n");
294 m_dirPaths.insert(m_cwd, item);
298 /* is it already existent ?? */
299 if (!m_dirPaths.contains(fullPath)) {
300 QTreeWidgetItem *item = NULL;
301 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
303 /* new directories to add */
304 item = new QTreeWidgetItem(parent);
305 item->setText(0, newdir.toUtf8().data());
306 item->setData(0, Qt::UserRole, QVariant(fullPath));
307 item->setCheckState(0, Qt::Unchecked);
308 /* Store the current state of the check status in column 1, which at
309 * this point has no text*/
310 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
313 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
314 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
317 Pmsg0(000, msg.toUtf8().data());
320 /* insert into hash */
322 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
323 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
325 m_dirPaths.insert(fullPath, item);
333 * Virtual function which is called when this page is visible on the stack
335 void restoreTree::currentStackItem()
338 if (!m_console->preventInUseConnect())
346 * Populate the tree when refresh button pushed.
348 void restoreTree::refreshButtonPushed()
350 populateDirectoryTree();
354 * Set the values of non-job combo boxes to the job defaults
356 void restoreTree::jobComboChanged(int)
358 job_defaults job_defs;
361 job_defs.job_name = jobCombo->currentText();
362 if (m_console->get_job_defaults(job_defs)) {
363 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
364 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
369 * Function to populate the file list table
371 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
376 m_fileCheckStateList.clear();
377 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
378 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
379 QBrush blackBrush(Qt::black);
380 QString directory = item->data(0, Qt::UserRole).toString();
381 directoryLabel->setText("Present Working Directory : " + directory);
383 "SELECT DISTINCT Filename.Name"
385 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
386 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
387 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
388 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
389 " AND Job.Jobid IN (" + m_jobQuery + ")";
391 QStringList headerlist = (QStringList() << "File Name");
393 /* Also clear the version table here */
394 versionTable->clear();
395 versionFileLabel->setText("");
396 versionTable->setRowCount(0);
397 versionTable->setColumnCount(0);
398 fileTable->setColumnCount(headerlist.size());
399 fileTable->setHorizontalHeaderLabels(headerlist);
401 if (mainWin->m_sqlDebug) {
402 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
405 if (m_console->sql_cmd(cmd, results)) {
407 QTableWidgetItem* tableItem;
409 QStringList fieldlist;
410 fileTable->setRowCount(results.size());
413 /* Iterate through the record returned from the query */
414 foreach (QString resultline, results) {
415 /* Iterate through fields in the record */
417 fieldlist = resultline.split("\t");
418 foreach (field, fieldlist) {
419 field = field.trimmed(); /* strip leading & trailing spaces */
420 tableItem = new QTableWidgetItem(field, 1);
421 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
422 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
423 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
424 tableItem->setForeground(blackBrush);
425 /* Just in case a column ever gets added */
427 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
428 tableItem->setFlags(flag);
429 tableItem->setData(Qt::UserRole, QVariant(directory));
430 fileTable->setItem(row, column, tableItem);
431 m_fileCheckStateList.append(Qt::Unchecked);
432 tableItem->setCheckState(Qt::Unchecked);
438 fileTable->setRowCount(row);
440 fileTable->resizeColumnsToContents();
441 fileTable->resizeRowsToContents();
442 fileTable->verticalHeader()->hide();
443 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
444 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
445 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
446 updateFileTableChecks();
450 * Function to populate the version table
452 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
454 if (fileTableItem == NULL)
457 m_versionCheckStateList.clear();
458 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
459 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
461 QString file = fileTableItem->text();
462 versionFileLabel->setText(file);
463 QString directory = fileTableItem->data(Qt::UserRole).toString();
465 QBrush blackBrush(Qt::black);
467 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
469 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
470 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
471 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
472 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
473 " AND Job.Jobid IN (" + m_jobQuery + ")"
474 " ORDER BY Job.EndTime DESC";
476 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
477 versionTable->clear();
478 versionTable->setColumnCount(headerlist.size());
479 versionTable->setHorizontalHeaderLabels(headerlist);
481 if (mainWin->m_sqlDebug) {
482 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
485 if (m_console->sql_cmd(cmd, results)) {
487 QTableWidgetItem* tableItem;
489 QStringList fieldlist;
490 versionTable->setRowCount(results.size());
493 /* Iterate through the record returned from the query */
494 foreach (QString resultline, results) {
495 fieldlist = resultline.split("\t");
497 /* remove directory */
498 if (fieldlist[0].trimmed() != "") {
499 /* Iterate through fields in the record */
500 foreach (field, fieldlist) {
501 field = field.trimmed(); /* strip leading & trailing spaces */
502 tableItem = new QTableWidgetItem(field, 1);
503 tableItem->setFlags(0);
504 tableItem->setForeground(blackBrush);
505 tableItem->setData(Qt::UserRole, QVariant(directory));
506 versionTable->setItem(row, column, tableItem);
509 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
510 tableItem->setFlags(flag);
511 m_versionCheckStateList.append(Qt::Unchecked);
512 tableItem->setCheckState(Qt::Unchecked);
520 versionTable->resizeColumnsToContents();
521 versionTable->resizeRowsToContents();
522 versionTable->verticalHeader()->hide();
523 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
524 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
525 updateVersionTableChecks();
529 * Save user settings associated with this page
531 void restoreTree::writeSettings()
533 QSettings settings(m_console->m_dir->name(), "bat");
534 settings.beginGroup("RestoreTree");
535 settings.setValue("splitterSizes", splitter->saveState());
540 * Read and restore user settings associated with this page
542 void restoreTree::readSettings()
544 QSettings settings(m_console->m_dir->name(), "bat");
545 settings.beginGroup("RestoreTree");
546 splitter->restoreState(settings.value("splitterSizes").toByteArray());
551 * This is a funcion to accomplish the one thing I struggled to figure out what
552 * was taking so long. It add the icons, but after the tree is made. Seemed to
553 * work fast after changing from svg to png file for graphic.
555 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
557 int childCount = item->childCount();
558 for (int i=0; i<childCount; i++) {
559 QTreeWidgetItem *child = item->child(i);
560 if (child->icon(0).isNull())
561 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
566 * I wanted a table to show what jobs meet the criterion and are being used to
567 * populate the directory tree and file and version tables.
569 void restoreTree::populateJobTable()
571 QBrush blackBrush(Qt::black);
572 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
574 jobTable->setColumnCount(headerlist.size());
575 jobTable->setHorizontalHeaderLabels(headerlist);
577 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
578 " FROM Job" + m_jobQueryPart +
579 " ORDER BY Job.EndTime DESC";
580 if (mainWin->m_sqlDebug) {
581 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
585 if (m_console->sql_cmd(jobQuery, results)) {
587 QTableWidgetItem* tableItem;
589 QStringList fieldlist;
590 jobTable->setRowCount(results.size());
593 /* Iterate through the record returned from the query */
594 foreach (QString resultline, results) {
595 fieldlist = resultline.split("\t");
597 /* remove directory */
598 if (fieldlist[0].trimmed() != "") {
599 /* Iterate through fields in the record */
600 foreach (field, fieldlist) {
601 field = field.trimmed(); /* strip leading & trailing spaces */
602 tableItem = new QTableWidgetItem(field, 1);
603 tableItem->setFlags(0);
604 tableItem->setForeground(blackBrush);
605 jobTable->setItem(row, column, tableItem);
607 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
608 tableItem->setFlags(flag);
609 tableItem->setCheckState(Qt::Checked);
610 tableItem->setBackground(Qt::green);
618 jobTable->resizeColumnsToContents();
619 jobTable->resizeRowsToContents();
620 jobTable->verticalHeader()->hide();
624 * When a directory item is "changed" check the state of the checkable item
625 * to see if it is different than what it was which is stored in Qt::UserRole
626 * of the 2nd column, column 1, of the tree widget.
628 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
630 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
631 Qt::CheckState curState = item->checkState(0);
632 QTreeWidgetItem* parent = item->parent();
633 Qt::CheckState parState;
634 if (parent) parState = parent->checkState(0);
635 else parState = (Qt::CheckState)3;
636 if (mainWin->m_rtDirICDebug) {
637 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
638 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
639 Pmsg1(000, "%s", msg.toUtf8().data()); }
640 /* I only care when the check state changes */
641 if (prevState == curState) {
642 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
646 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
647 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
648 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
649 curState = Qt::PartiallyChecked;
651 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
652 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
653 directoryTreeDisconnectedSet(item, Qt::Unchecked);
654 curState = Qt::Unchecked;
656 if (mainWin->m_rtDirICDebug) {
657 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
658 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
659 Pmsg1(000, "%s", msg.toUtf8().data()); }
661 item->setData(1, Qt::UserRole, QVariant(curState));
662 Qt::CheckState childState = curState;
663 if (childState == Qt::Checked)
664 childState = Qt::PartiallyChecked;
665 setCheckofChildren(item, childState);
667 /* Remove items from the exception lists. The multi exception list is my index
668 * of what exceptions can be removed when the directory is known*/
669 QString directory = item->data(0, Qt::UserRole).toString();
670 QStringList fullPathList = m_fileExceptionMulti.values(directory);
671 int fullPathListCount = fullPathList.count();
672 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
673 foreach (QString fullPath, fullPathList) {
674 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
675 * which will match no Qt::xxx values */
676 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
677 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
678 if (hashState == Qt::Unchecked) {
679 fileExceptionRemove(fullPath, directory);
680 m_versionExceptionHash.remove(fullPath);
681 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
683 if (hashState == Qt::Checked) {
684 fileExceptionRemove(fullPath, directory);
685 m_versionExceptionHash.remove(fullPath);
686 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
690 if (item == directoryTree->currentItem()) {
691 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
692 updateFileTableChecks();
693 versionTable->clear();
694 versionTable->setRowCount(0);
695 versionTable->setColumnCount(0);
697 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
701 * When a directory item check state is changed, this function iterates through
702 * all subdirectories and sets all to the passed state, which is either partially
703 * checked or unchecked.
705 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
708 childCount = item->childCount();
709 for (int i=0; i<childCount; i++) {
710 QTreeWidgetItem *child = item->child(i);
711 child->setData(1, Qt::UserRole, QVariant(state));
712 child->setCheckState(0, state);
713 setCheckofChildren(child, state);
718 * When a File Table Item is "changed" check to see if the state of the checkable
719 * item has changed which is stored in m_fileCheckStateList
720 * If changed store in a hash m_fileExceptionHash that whether this file should be
722 * Called as a slot, connected after populated (after directory current changed called)
724 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
726 /* get the previous and current check states */
727 int row = fileTable->row(item);
728 Qt::CheckState prevState;
729 /* prevent a segfault */
730 prevState = m_fileCheckStateList[row];
731 Qt::CheckState curState = item->checkState();
733 /* deterimine the default state from the state of the directory */
734 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
735 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
736 Qt::CheckState defState = Qt::PartiallyChecked;
737 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
739 /* determine if it is already in the m_fileExceptionHash */
740 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
741 QString file = item->text();
742 QString fullPath = directory + file;
743 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
744 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
746 if (mainWin->m_rtFileTabICDebug) {
747 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
748 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
749 Pmsg1(000, "%s", msg.toUtf8().data()); }
751 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
752 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
753 /* it can behave as defaulted so current of unchecked is fine */
754 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
755 fileExceptionRemove(fullPath, directory);
756 m_versionExceptionHash.remove(fullPath);
757 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
758 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
759 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
760 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
761 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
762 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
763 fileExceptionRemove(fullPath, directory);
764 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
765 /* Check dir, check version, attempt uncheck in file
766 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
767 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
768 fileExceptionRemove(fullPath, directory);
769 m_versionExceptionHash.remove(fullPath);
770 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
771 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
772 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
773 } else if (prevState != curState) {
774 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
775 /* A user did not set the check state to Partially checked, ignore if so */
776 if (curState != Qt::PartiallyChecked) {
777 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
778 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
780 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
781 fileExceptionInsert(fullPath, directory, curState);
784 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
785 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
786 m_versionExceptionHash.remove(fullPath);
790 updateFileTableChecks();
791 updateVersionTableChecks();
795 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
797 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
799 m_fileExceptionHash.insert(fullPath, state);
800 m_fileExceptionMulti.insert(direcotry, fullPath);
801 directoryIconStateInsert(fullPath, state);
805 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
807 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
809 m_fileExceptionHash.remove(fullPath);
810 /* pull the list of values in the multi */
811 QStringList fullPathList = m_fileExceptionMulti.values(directory);
812 /* get the index of the fullpath to remove */
813 int index = fullPathList.indexOf(fullPath);
815 /* remove the desired item in the list */
816 fullPathList.removeAt(index);
817 /* remove the entire list from the multi */
818 m_fileExceptionMulti.remove(directory);
819 /* readd the remaining */
820 foreach (QString fp, fullPathList) {
821 m_fileExceptionMulti.insert(directory, fp);
824 directoryIconStateRemove();
828 * Overloaded function to be called from the slot and from other places to set the state
829 * of the check marks in the version table
831 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
833 /* get the previous and current check states */
834 int row = versionTable->row(item);
835 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
836 Qt::CheckState prevState = m_versionCheckStateList[row];
837 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
838 m_versionCheckStateList[row] = curState;
840 /* deterimine the default state from the state of the file */
841 QTableWidgetItem *fileTableItem = fileTable->currentItem();
842 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
844 /* determine the default state */
845 Qt::CheckState defState;
847 defState = Qt::PartiallyChecked;
848 if (fileState == Qt::Unchecked)
849 defState = Qt::Unchecked;
852 defState = Qt::Unchecked;
854 /* determine if it is already in the versionExceptionHash */
855 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
856 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
857 QString file = fileTableItem->text();
858 QString fullPath = directory + file;
859 int thisJobNum = colZeroItem->text().toInt();
860 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
862 if (mainWin->m_rtVerTabICDebug) {
863 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
864 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
865 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
866 Pmsg1(000, "%s", msg.toUtf8().data()); }
867 /* if changed from partially checked to checked, make it unchecked */
868 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
869 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
870 fileTableItem->setCheckState(Qt::Checked);
871 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
872 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
873 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
874 fileExceptionRemove(fullPath, directory);
875 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
876 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
877 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
878 m_versionExceptionHash.remove(fullPath);
879 fileExceptionRemove(fullPath, directory);
880 } else if ((curState == Qt::Checked) && (row == 0)) {
881 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
882 m_versionExceptionHash.remove(fullPath);
883 } else if (prevState != curState) {
884 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
885 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
886 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
887 m_versionExceptionHash.insert(fullPath, thisJobNum);
888 if (fileState != Qt::Checked) {
889 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
890 fileExceptionInsert(fullPath, directory, curState);
893 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
896 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
899 updateFileTableChecks();
900 updateVersionTableChecks();
904 * Simple function to set the check state in the file table by disconnecting the
905 * signal/slot the setting then reconnecting the signal/slot
907 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
909 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
910 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
911 item->setCheckState(state);
912 if (color) item->setBackground(Qt::yellow);
913 else item->setBackground(Qt::white);
914 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
915 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
919 * Simple function to set the check state in the version table by disconnecting the
920 * signal/slot the setting then reconnecting the signal/slot
922 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
924 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
925 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
926 item->setCheckState(state);
927 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
928 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
932 * Simple function to set the check state in the directory tree by disconnecting the
933 * signal/slot the setting then reconnecting the signal/slot
935 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
937 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
938 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
939 item->setCheckState(0, state);
940 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
941 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
945 * Simplify the updating of the check state in the File table by iterating through
946 * each item in the file table to determine it's appropriate state.
947 * !! Will probably want to concoct a way to do this without iterating for the possibility
948 * of the very large directories.
950 void restoreTree::updateFileTableChecks()
952 /* deterimine the default state from the state of the directory */
953 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
954 Qt::CheckState dirState = dirTreeItem->checkState(0);
956 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
958 /* Update the items in the version table */
959 int rcnt = fileTable->rowCount();
960 for (int row=0; row<rcnt; row++) {
961 QTableWidgetItem* item = fileTable->item(row, 0);
963 Qt::CheckState curState = item->checkState();
964 Qt::CheckState newState = Qt::PartiallyChecked;
965 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
967 /* determine if it is already in the m_fileExceptionHash */
968 QString file = item->text();
969 QString fullPath = dirName + file;
970 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
971 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
973 if (hashState != 3) newState = hashState;
975 if (mainWin->m_rtUpdateFTDebug) {
976 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
977 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
978 Pmsg1(000, "%s", msg.toUtf8().data());
981 bool docolor = false;
982 if (hashJobNum != 0) docolor = true;
983 bool isyellow = item->background().color() == QColor(Qt::yellow);
984 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
985 fileTableDisconnectedSet(item, newState, docolor);
986 m_fileCheckStateList[row] = newState;
991 * Simplify the updating of the check state in the Version table by iterating through
992 * each item in the file table to determine it's appropriate state.
994 void restoreTree::updateVersionTableChecks()
996 /* deterimine the default state from the state of the directory */
997 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
998 Qt::CheckState dirState = dirTreeItem->checkState(0);
999 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1001 /* deterimine the default state from the state of the file */
1002 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1003 Qt::CheckState fileState = fileTableItem->checkState();
1004 QString file = fileTableItem->text();
1005 QString fullPath = dirName + file;
1006 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1008 /* Update the items in the version table */
1009 int cnt = versionTable->rowCount();
1010 for (int row=0; row<cnt; row++) {
1011 QTableWidgetItem* item = versionTable->item(row, 0);
1013 Qt::CheckState curState = item->checkState();
1014 Qt::CheckState newState = Qt::Unchecked;
1016 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1017 newState = Qt::PartiallyChecked;
1018 /* determine if it is already in the versionExceptionHash */
1020 int thisJobNum = item->text().toInt();
1021 if (thisJobNum == hashJobNum)
1022 newState = Qt::Checked;
1024 if (mainWin->m_rtChecksDebug) {
1025 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1026 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1027 Pmsg1(000, "%s", msg.toUtf8().data());
1029 if (newState != curState)
1030 versionTableDisconnectedSet(item, newState);
1031 m_versionCheckStateList[row] = newState;
1036 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1038 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1042 QString fullPath = fullPath_in;
1043 QString direct, path;
1044 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1045 direct = path = fullPath;
1046 path.replace(index+1, fullPath.length()-index-1, "");
1047 direct.replace(0, index+1, "");
1049 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1050 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1051 Pmsg0(000, msg.toUtf8().data());
1054 subPaths.append(fullPath);
1059 * A Function to set the icon state and insert a record into
1060 * m_directoryIconStateHash when an exception is added by the user
1062 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1065 fullPathtoSubPaths(paths, fullPath);
1066 /* an exception that causes the item in the file table to be "Checked" has occured */
1067 if (excpState == Qt::Checked) {
1068 bool foundAsUnChecked = false;
1069 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1071 if (firstItem->checkState(0) == Qt::Unchecked)
1072 foundAsUnChecked = true;
1074 if (foundAsUnChecked) {
1075 /* as long as directory item is Unchecked, set icon state to "green check" */
1077 QListIterator<QString> siter(paths);
1078 while (siter.hasNext() && !done) {
1079 QString path = siter.next();
1080 QTreeWidgetItem *item = m_dirPaths.value(path);
1082 if (item->checkState(0) != Qt::Unchecked)
1085 directorySetIcon(1, FolderGreenChecked, path, item);
1086 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1091 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1092 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1094 QListIterator<QString> siter(paths);
1095 while (siter.hasNext() && !done) {
1096 QString path = siter.next();
1097 QTreeWidgetItem *item = m_dirPaths.value(path);
1098 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1099 if (item->checkState(0) == Qt::Checked)
1101 directorySetIcon(1, FolderGreenChecked, path, item);
1102 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1107 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1108 if (excpState == Qt::Unchecked) {
1110 QListIterator<QString> siter(paths);
1111 while (siter.hasNext() && !done) {
1112 QString path = siter.next();
1113 QTreeWidgetItem *item = m_dirPaths.value(path);
1114 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1115 if (item->checkState(0) == Qt::Checked)
1117 directorySetIcon(1, FolderWhiteChecked, path, item);
1118 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1125 * A function to set the icon state back to "folder" and to remove a record from
1126 * m_directoryIconStateHash when an exception is removed by a user.
1128 void restoreTree::directoryIconStateRemove()
1130 QHash<QString, int> shouldBeIconStateHash;
1131 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1132 /* Use iterator tera to iterate through m_fileExceptionHash */
1133 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1134 while (tera.hasNext()) {
1136 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1138 QString keyPath = tera.key();
1139 Qt::CheckState state = tera.value();
1142 fullPathtoSubPaths(paths, keyPath);
1143 /* if the state of the item in m_fileExceptionHash is checked
1144 * each of the subpaths should be "Checked Green" */
1145 if (state == Qt::Checked) {
1147 bool foundAsUnChecked = false;
1148 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1150 if (firstItem->checkState(0) == Qt::Unchecked)
1151 foundAsUnChecked = true;
1153 if (foundAsUnChecked) {
1154 /* The right most directory is Unchecked, iterate leftwards
1155 * as long as directory item is Unchecked, set icon state to "green check" */
1157 QListIterator<QString> siter(paths);
1158 while (siter.hasNext() && !done) {
1159 QString path = siter.next();
1160 QTreeWidgetItem *item = m_dirPaths.value(path);
1162 if (item->checkState(0) != Qt::Unchecked)
1165 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1166 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1172 /* The right most directory is Unchecked, iterate leftwards
1173 * until directory item is Checked, set icon state to "green check" */
1175 QListIterator<QString> siter(paths);
1176 while (siter.hasNext() && !done) {
1177 QString path = siter.next();
1178 QTreeWidgetItem *item = m_dirPaths.value(path);
1180 if (item->checkState(0) == Qt::Checked)
1182 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1187 /* if the state of the item in m_fileExceptionHash is UNChecked
1188 * each of the subpaths should be "Checked white" until the tree item
1189 * which represents that path is Qt::Checked */
1190 if (state == Qt::Unchecked) {
1192 QListIterator<QString> siter(paths);
1193 while (siter.hasNext() && !done) {
1194 QString path = siter.next();
1195 QTreeWidgetItem *item = m_dirPaths.value(path);
1197 if (item->checkState(0) == Qt::Checked)
1199 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1204 /* now iterate through m_directoryIconStateHash which are the items that are checked
1205 * and remove all of those that are not in shouldBeIconStateHash */
1206 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1207 while (iter.hasNext()) {
1209 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1211 QString keyPath = iter.key();
1212 if (shouldBeIconStateHash.value(keyPath)) {
1213 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1214 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1215 int newval = shouldBeIconStateHash.value(keyPath);
1217 newval = newval & FolderBothChecked;
1218 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1220 directorySetIcon(0, newval, keyPath, item);
1222 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1223 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1225 directorySetIcon(0, FolderBothChecked, keyPath, item);
1226 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1227 //m_directoryIconStateHash.remove(keyPath);
1232 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1234 /* we are adding a check type white or green */
1235 if (operation > 0) {
1236 /* get the old val and "bitwise OR" with the change */
1237 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1238 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1239 m_directoryIconStateHash.insert(path, newval);
1241 /* we are removing a check type white or green */
1242 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1244 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1245 m_directoryIconStateHash.remove(path);
1248 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1249 m_directoryIconStateHash.insert(path, newval);
1252 if (newval == FolderUnchecked)
1253 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1254 else if (newval == FolderGreenChecked)
1255 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1256 else if (newval == FolderWhiteChecked)
1257 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1258 else if (newval == FolderBothChecked)
1259 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1265 void restoreTree::testButtonPushed()
1267 QMultiHash<int, QString> versionFilesMulti;
1268 QHash <QString, bool> fullPathDone;
1269 QHash <QString, int> fileIndexHash;
1270 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1271 Pmsg0(000, "In restoreTree::testButtonPushed\n");
1272 /* Use a tree widget item iterator filtering for Checked Items */
1273 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1275 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1276 if (mainWin->m_rtRestore1Debug)
1277 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1278 /* With a checked directory, query for the files in the directory */
1281 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1283 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1285 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1286 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1287 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1288 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1289 " AND Job.Jobid IN (" + m_jobQuery + ")"
1290 " GROUP BY Filename.Name"
1292 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1293 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1294 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1296 " Path.Path='" + directory + "'"
1297 " AND Filename.Name=t1.Filename"
1298 " AND Job.Jobid=t1.JobId"
1299 " ORDER BY Filename";
1301 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1302 QStringList results;
1303 if (m_console->sql_cmd(cmd, results)) {
1305 QStringList fieldlist;
1308 /* Iterate through the record returned from the query */
1309 foreach (QString resultline, results) {
1310 /* Iterate through fields in the record */
1312 QString fullPath = "";
1313 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1314 fieldlist = resultline.split("\t");
1317 foreach (QString field, fieldlist) {
1319 fullPath = directory + field;
1322 version = field.toInt();
1325 fileIndex = field.toInt();
1329 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1331 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1332 if (fileExcpState != Qt::Unchecked) {
1334 if (excpVersion != 0) {
1335 debugtext = QString("*E* version=%1").arg(excpVersion);
1336 version = excpVersion;
1337 fileIndex = queryFileIndex(fullPath, excpVersion);
1339 debugtext = QString("___ version=%1").arg(version);
1340 if (mainWin->m_rtRestore1Debug)
1341 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1342 fullPathDone.insert(fullPath, 1);
1343 fileIndexHash.insert(fullPath, fileIndex);
1344 versionFilesMulti.insert(version, fullPath);
1350 } /* while (*diter) */
1352 /* There may be some exceptions not accounted for yet with fullPathDone */
1353 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1354 while (ftera.hasNext()) {
1356 QString fullPath = ftera.key();
1357 Qt::CheckState state = ftera.value();
1359 /* now we don't want the ones already done */
1360 if (fullPathDone.value(fullPath, 0) == 0) {
1361 int version = m_versionExceptionHash.value(fullPath, 0);
1363 QString debugtext = "";
1365 fileIndex = queryFileIndex(fullPath, version);
1366 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1368 version = mostRecentVersionfromFullPath(fullPath);
1370 fileIndex = queryFileIndex(fullPath, version);
1371 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1373 debugtext = QString("Error det vers").arg(version);
1375 if (mainWin->m_rtRestore1Debug)
1376 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1377 versionFilesMulti.insert(version, fullPath);
1378 fileIndexHash.insert(fullPath, fileIndex);
1379 } /* if fullPathDone.value(fullPath, 0) == 0 */
1380 } /* if state != 0 */
1381 } /* while ftera.hasNext */
1383 /* now for the final spit out of the versions and lists of files for each version */
1384 QHash<int, int> doneKeys;
1385 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1386 QString tempTable = "";
1388 while (vFMiter.hasNext()) {
1390 int fversion = vFMiter.key();
1391 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1392 if (doneKeys.value(fversion, 0) == 0) {
1393 if (tempTable == "") {
1394 QSettings settings("www.bacula.org", "bat");
1395 settings.beginGroup("Restore");
1396 int counter = settings.value("Counter", 1).toInt();
1397 settings.setValue("Counter", counter+1);
1398 settings.endGroup();
1399 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1400 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1401 if (mainWin->m_sqlDebug)
1402 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1403 QStringList results;
1404 if (!m_console->sql_cmd(sqlcmd, results))
1405 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1408 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1409 QStringList fullPathList = versionFilesMulti.values(fversion);
1410 /* create the command to perform the restore */
1411 foreach(QString ffullPath, fullPathList) {
1412 int fileIndex = fileIndexHash.value(ffullPath);
1413 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1414 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1415 if (mainWin->m_sqlDebug)
1416 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1417 QStringList results;
1418 if (!m_console->sql_cmd(sqlcmd, results))
1419 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1420 } /* foreach fullPathList */
1421 doneKeys.insert(fversion,1);
1422 jobList.append(fversion);
1423 } /* if (doneKeys.value(fversion, 0) == 0) */
1424 } /* while (vFMiter.hasNext()) */
1425 if (tempTable != "") {
1426 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
1427 new restoreTreeRunPage(tempTable, m_prevClientCombo, jobList, pageSelectorTreeWidgetItem);
1431 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1434 QString directory, fileName;
1435 int index = m_slashregex.lastIndexIn(fullPath, -2);
1437 directory = fileName = fullPath;
1438 directory.replace(index+1, fullPath.length()-index-1, "");
1439 fileName.replace(0, index+1, "");
1441 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1442 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1443 Pmsg0(000, msg.toUtf8().data());
1445 /* so now we need the latest version from the database */
1447 "SELECT MAX(Job.JobId)"
1449 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1450 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1451 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1452 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1453 " AND Job.Jobid IN (" + m_jobQuery + ")"
1454 " AND Filename.Name='" + fileName + "'"
1455 " GROUP BY Filename.Name";
1457 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1458 QStringList results;
1459 if (m_console->sql_cmd(cmd, results)) {
1460 QStringList fieldlist;
1462 /* Iterate through the record returned from the query */
1463 foreach (QString resultline, results) {
1464 /* Iterate through fields in the record */
1466 fieldlist = resultline.split("\t");
1467 foreach (QString field, fieldlist) {
1469 qversion = field.toInt();
1476 } /* if (index != -1) */
1481 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1484 QString directory, fileName;
1485 int index = m_slashregex.lastIndexIn(fullPath, -2);
1487 directory = fileName = fullPath;
1488 directory.replace(index+1, fullPath.length()-index-1, "");
1489 fileName.replace(0, index+1, "");
1491 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1492 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1493 Pmsg0(000, msg.toUtf8().data());
1495 /* so now we need the latest version from the database */
1500 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1501 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1502 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1504 " Path.Path='" + directory + "'"
1505 " AND Filename.Name='" + fileName + "'"
1506 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1507 " GROUP BY File.FileIndex";
1509 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1510 QStringList results;
1511 if (m_console->sql_cmd(cmd, results)) {
1512 QStringList fieldlist;
1514 /* Iterate through the record returned from the query */
1515 foreach (QString resultline, results) {
1516 /* Iterate through fields in the record */
1518 fieldlist = resultline.split("\t");
1519 foreach (QString field, fieldlist) {
1521 qfileIndex = field.toInt();
1528 } /* if (index != -1) */