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(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
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 AS FileName"
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 + ")"
390 " ORDER BY FileName";
392 QStringList headerlist = (QStringList() << "File Name");
394 /* Also clear the version table here */
395 versionTable->clear();
396 versionFileLabel->setText("");
397 versionTable->setRowCount(0);
398 versionTable->setColumnCount(0);
399 fileTable->setColumnCount(headerlist.size());
400 fileTable->setHorizontalHeaderLabels(headerlist);
402 if (mainWin->m_sqlDebug) {
403 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
406 if (m_console->sql_cmd(cmd, results)) {
408 QTableWidgetItem* tableItem;
410 QStringList fieldlist;
411 fileTable->setRowCount(results.size());
414 /* Iterate through the record returned from the query */
415 foreach (QString resultline, results) {
416 /* Iterate through fields in the record */
418 fieldlist = resultline.split("\t");
419 foreach (field, fieldlist) {
420 field = field.trimmed(); /* strip leading & trailing spaces */
421 tableItem = new QTableWidgetItem(field, 1);
422 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
423 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
424 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
425 tableItem->setForeground(blackBrush);
426 /* Just in case a column ever gets added */
428 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
429 tableItem->setFlags(flag);
430 tableItem->setData(Qt::UserRole, QVariant(directory));
431 fileTable->setItem(row, column, tableItem);
432 m_fileCheckStateList.append(Qt::Unchecked);
433 tableItem->setCheckState(Qt::Unchecked);
439 fileTable->setRowCount(row);
441 fileTable->resizeColumnsToContents();
442 fileTable->resizeRowsToContents();
443 fileTable->verticalHeader()->hide();
444 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
445 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
446 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
447 updateFileTableChecks();
451 * Function to populate the version table
453 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
455 if (fileTableItem == NULL)
458 m_versionCheckStateList.clear();
459 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
460 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
462 QString file = fileTableItem->text();
463 versionFileLabel->setText(file);
464 QString directory = fileTableItem->data(Qt::UserRole).toString();
466 QBrush blackBrush(Qt::black);
468 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
470 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
471 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
472 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
473 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
474 " AND Job.Jobid IN (" + m_jobQuery + ")"
475 " ORDER BY Job.EndTime DESC";
477 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
478 versionTable->clear();
479 versionTable->setColumnCount(headerlist.size());
480 versionTable->setHorizontalHeaderLabels(headerlist);
482 if (mainWin->m_sqlDebug) {
483 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
486 if (m_console->sql_cmd(cmd, results)) {
488 QTableWidgetItem* tableItem;
490 QStringList fieldlist;
491 versionTable->setRowCount(results.size());
494 /* Iterate through the record returned from the query */
495 foreach (QString resultline, results) {
496 fieldlist = resultline.split("\t");
498 /* remove directory */
499 if (fieldlist[0].trimmed() != "") {
500 /* Iterate through fields in the record */
501 foreach (field, fieldlist) {
502 field = field.trimmed(); /* strip leading & trailing spaces */
503 tableItem = new QTableWidgetItem(field, 1);
504 tableItem->setFlags(0);
505 tableItem->setForeground(blackBrush);
506 tableItem->setData(Qt::UserRole, QVariant(directory));
507 versionTable->setItem(row, column, tableItem);
510 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
511 tableItem->setFlags(flag);
512 m_versionCheckStateList.append(Qt::Unchecked);
513 tableItem->setCheckState(Qt::Unchecked);
521 versionTable->resizeColumnsToContents();
522 versionTable->resizeRowsToContents();
523 versionTable->verticalHeader()->hide();
524 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
525 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
526 updateVersionTableChecks();
530 * Save user settings associated with this page
532 void restoreTree::writeSettings()
534 QSettings settings(m_console->m_dir->name(), "bat");
535 settings.beginGroup("RestoreTree");
536 settings.setValue("splitterSizes", splitter->saveState());
541 * Read and restore user settings associated with this page
543 void restoreTree::readSettings()
545 QSettings settings(m_console->m_dir->name(), "bat");
546 settings.beginGroup("RestoreTree");
547 splitter->restoreState(settings.value("splitterSizes").toByteArray());
552 * This is a funcion to accomplish the one thing I struggled to figure out what
553 * was taking so long. It add the icons, but after the tree is made. Seemed to
554 * work fast after changing from svg to png file for graphic.
556 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
558 int childCount = item->childCount();
559 for (int i=0; i<childCount; i++) {
560 QTreeWidgetItem *child = item->child(i);
561 if (child->icon(0).isNull())
562 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
567 * I wanted a table to show what jobs meet the criterion and are being used to
568 * populate the directory tree and file and version tables.
570 void restoreTree::populateJobTable()
572 QBrush blackBrush(Qt::black);
573 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
575 jobTable->setColumnCount(headerlist.size());
576 jobTable->setHorizontalHeaderLabels(headerlist);
578 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
579 " FROM Job" + m_jobQueryPart +
580 " ORDER BY Job.EndTime DESC";
581 if (mainWin->m_sqlDebug) {
582 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
586 if (m_console->sql_cmd(jobQuery, results)) {
588 QTableWidgetItem* tableItem;
590 QStringList fieldlist;
591 jobTable->setRowCount(results.size());
594 /* Iterate through the record returned from the query */
595 foreach (QString resultline, results) {
596 fieldlist = resultline.split("\t");
598 /* remove directory */
599 if (fieldlist[0].trimmed() != "") {
600 /* Iterate through fields in the record */
601 foreach (field, fieldlist) {
602 field = field.trimmed(); /* strip leading & trailing spaces */
603 tableItem = new QTableWidgetItem(field, 1);
604 tableItem->setFlags(0);
605 tableItem->setForeground(blackBrush);
606 jobTable->setItem(row, column, tableItem);
608 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
609 tableItem->setFlags(flag);
610 tableItem->setCheckState(Qt::Checked);
611 tableItem->setBackground(Qt::green);
619 jobTable->resizeColumnsToContents();
620 jobTable->resizeRowsToContents();
621 jobTable->verticalHeader()->hide();
625 * When a directory item is "changed" check the state of the checkable item
626 * to see if it is different than what it was which is stored in Qt::UserRole
627 * of the 2nd column, column 1, of the tree widget.
629 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
631 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
632 Qt::CheckState curState = item->checkState(0);
633 QTreeWidgetItem* parent = item->parent();
634 Qt::CheckState parState;
635 if (parent) parState = parent->checkState(0);
636 else parState = (Qt::CheckState)3;
637 if (mainWin->m_rtDirICDebug) {
638 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
639 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
640 Pmsg1(000, "%s", msg.toUtf8().data()); }
641 /* I only care when the check state changes */
642 if (prevState == curState) {
643 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
647 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
648 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
649 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
650 curState = Qt::PartiallyChecked;
652 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
653 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
654 directoryTreeDisconnectedSet(item, Qt::Unchecked);
655 curState = Qt::Unchecked;
657 if (mainWin->m_rtDirICDebug) {
658 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
659 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
660 Pmsg1(000, "%s", msg.toUtf8().data()); }
662 item->setData(1, Qt::UserRole, QVariant(curState));
663 Qt::CheckState childState = curState;
664 if (childState == Qt::Checked)
665 childState = Qt::PartiallyChecked;
666 setCheckofChildren(item, childState);
668 /* Remove items from the exception lists. The multi exception list is my index
669 * of what exceptions can be removed when the directory is known*/
670 QString directory = item->data(0, Qt::UserRole).toString();
671 QStringList fullPathList = m_fileExceptionMulti.values(directory);
672 int fullPathListCount = fullPathList.count();
673 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
674 foreach (QString fullPath, fullPathList) {
675 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
676 * which will match no Qt::xxx values */
677 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
678 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
679 if (hashState == Qt::Unchecked) {
680 fileExceptionRemove(fullPath, directory);
681 m_versionExceptionHash.remove(fullPath);
682 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
684 if (hashState == Qt::Checked) {
685 fileExceptionRemove(fullPath, directory);
686 m_versionExceptionHash.remove(fullPath);
687 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
691 if (item == directoryTree->currentItem()) {
692 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
693 updateFileTableChecks();
694 versionTable->clear();
695 versionTable->setRowCount(0);
696 versionTable->setColumnCount(0);
698 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
702 * When a directory item check state is changed, this function iterates through
703 * all subdirectories and sets all to the passed state, which is either partially
704 * checked or unchecked.
706 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
709 childCount = item->childCount();
710 for (int i=0; i<childCount; i++) {
711 QTreeWidgetItem *child = item->child(i);
712 child->setData(1, Qt::UserRole, QVariant(state));
713 child->setCheckState(0, state);
714 setCheckofChildren(child, state);
719 * When a File Table Item is "changed" check to see if the state of the checkable
720 * item has changed which is stored in m_fileCheckStateList
721 * If changed store in a hash m_fileExceptionHash that whether this file should be
723 * Called as a slot, connected after populated (after directory current changed called)
725 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
727 /* get the previous and current check states */
728 int row = fileTable->row(item);
729 Qt::CheckState prevState;
730 /* prevent a segfault */
731 prevState = m_fileCheckStateList[row];
732 Qt::CheckState curState = item->checkState();
734 /* deterimine the default state from the state of the directory */
735 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
736 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
737 Qt::CheckState defState = Qt::PartiallyChecked;
738 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
740 /* determine if it is already in the m_fileExceptionHash */
741 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
742 QString file = item->text();
743 QString fullPath = directory + file;
744 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
745 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
747 if (mainWin->m_rtFileTabICDebug) {
748 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
749 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
750 Pmsg1(000, "%s", msg.toUtf8().data()); }
752 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
753 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
754 /* it can behave as defaulted so current of unchecked is fine */
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::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
759 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
760 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
761 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
762 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
763 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
764 fileExceptionRemove(fullPath, directory);
765 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
766 /* Check dir, check version, attempt uncheck in file
767 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
768 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
769 fileExceptionRemove(fullPath, directory);
770 m_versionExceptionHash.remove(fullPath);
771 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
772 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
773 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
774 } else if (prevState != curState) {
775 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
776 /* A user did not set the check state to Partially checked, ignore if so */
777 if (curState != Qt::PartiallyChecked) {
778 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
779 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
781 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
782 fileExceptionInsert(fullPath, directory, curState);
785 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
786 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
787 m_versionExceptionHash.remove(fullPath);
791 updateFileTableChecks();
792 updateVersionTableChecks();
796 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
798 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
800 m_fileExceptionHash.insert(fullPath, state);
801 m_fileExceptionMulti.insert(direcotry, fullPath);
802 directoryIconStateInsert(fullPath, state);
806 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
808 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
810 m_fileExceptionHash.remove(fullPath);
811 /* pull the list of values in the multi */
812 QStringList fullPathList = m_fileExceptionMulti.values(directory);
813 /* get the index of the fullpath to remove */
814 int index = fullPathList.indexOf(fullPath);
816 /* remove the desired item in the list */
817 fullPathList.removeAt(index);
818 /* remove the entire list from the multi */
819 m_fileExceptionMulti.remove(directory);
820 /* readd the remaining */
821 foreach (QString fp, fullPathList) {
822 m_fileExceptionMulti.insert(directory, fp);
825 directoryIconStateRemove();
829 * Overloaded function to be called from the slot and from other places to set the state
830 * of the check marks in the version table
832 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
834 /* get the previous and current check states */
835 int row = versionTable->row(item);
836 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
837 Qt::CheckState prevState = m_versionCheckStateList[row];
838 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
839 m_versionCheckStateList[row] = curState;
841 /* deterimine the default state from the state of the file */
842 QTableWidgetItem *fileTableItem = fileTable->currentItem();
843 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
845 /* determine the default state */
846 Qt::CheckState defState;
848 defState = Qt::PartiallyChecked;
849 if (fileState == Qt::Unchecked)
850 defState = Qt::Unchecked;
853 defState = Qt::Unchecked;
855 /* determine if it is already in the versionExceptionHash */
856 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
857 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
858 QString file = fileTableItem->text();
859 QString fullPath = directory + file;
860 int thisJobNum = colZeroItem->text().toInt();
861 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
863 if (mainWin->m_rtVerTabICDebug) {
864 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
865 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
866 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
867 Pmsg1(000, "%s", msg.toUtf8().data()); }
868 /* if changed from partially checked to checked, make it unchecked */
869 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
870 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
871 fileTableItem->setCheckState(Qt::Checked);
872 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
873 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
874 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
875 fileExceptionRemove(fullPath, directory);
876 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
877 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
878 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
879 m_versionExceptionHash.remove(fullPath);
880 fileExceptionRemove(fullPath, directory);
881 } else if ((curState == Qt::Checked) && (row == 0)) {
882 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
883 m_versionExceptionHash.remove(fullPath);
884 } else if (prevState != curState) {
885 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
886 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
887 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
888 m_versionExceptionHash.insert(fullPath, thisJobNum);
889 if (fileState != Qt::Checked) {
890 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
891 fileExceptionInsert(fullPath, directory, curState);
894 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
897 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
900 updateFileTableChecks();
901 updateVersionTableChecks();
905 * Simple function to set the check state in the file table by disconnecting the
906 * signal/slot the setting then reconnecting the signal/slot
908 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
910 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
911 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
912 item->setCheckState(state);
913 if (color) item->setBackground(Qt::yellow);
914 else item->setBackground(Qt::white);
915 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
916 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
920 * Simple function to set the check state in the version table by disconnecting the
921 * signal/slot the setting then reconnecting the signal/slot
923 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
925 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
926 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
927 item->setCheckState(state);
928 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
929 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
933 * Simple function to set the check state in the directory tree by disconnecting the
934 * signal/slot the setting then reconnecting the signal/slot
936 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
938 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
939 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
940 item->setCheckState(0, state);
941 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
942 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
946 * Simplify the updating of the check state in the File table by iterating through
947 * each item in the file table to determine it's appropriate state.
948 * !! Will probably want to concoct a way to do this without iterating for the possibility
949 * of the very large directories.
951 void restoreTree::updateFileTableChecks()
953 /* deterimine the default state from the state of the directory */
954 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
955 Qt::CheckState dirState = dirTreeItem->checkState(0);
957 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
959 /* Update the items in the version table */
960 int rcnt = fileTable->rowCount();
961 for (int row=0; row<rcnt; row++) {
962 QTableWidgetItem* item = fileTable->item(row, 0);
964 Qt::CheckState curState = item->checkState();
965 Qt::CheckState newState = Qt::PartiallyChecked;
966 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
968 /* determine if it is already in the m_fileExceptionHash */
969 QString file = item->text();
970 QString fullPath = dirName + file;
971 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
972 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
974 if (hashState != 3) newState = hashState;
976 if (mainWin->m_rtUpdateFTDebug) {
977 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
978 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
979 Pmsg1(000, "%s", msg.toUtf8().data());
982 bool docolor = false;
983 if (hashJobNum != 0) docolor = true;
984 bool isyellow = item->background().color() == QColor(Qt::yellow);
985 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
986 fileTableDisconnectedSet(item, newState, docolor);
987 m_fileCheckStateList[row] = newState;
992 * Simplify the updating of the check state in the Version table by iterating through
993 * each item in the file table to determine it's appropriate state.
995 void restoreTree::updateVersionTableChecks()
997 /* deterimine the default state from the state of the directory */
998 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
999 Qt::CheckState dirState = dirTreeItem->checkState(0);
1000 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1002 /* deterimine the default state from the state of the file */
1003 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1004 Qt::CheckState fileState = fileTableItem->checkState();
1005 QString file = fileTableItem->text();
1006 QString fullPath = dirName + file;
1007 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1009 /* Update the items in the version table */
1010 int cnt = versionTable->rowCount();
1011 for (int row=0; row<cnt; row++) {
1012 QTableWidgetItem* item = versionTable->item(row, 0);
1014 Qt::CheckState curState = item->checkState();
1015 Qt::CheckState newState = Qt::Unchecked;
1017 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1018 newState = Qt::PartiallyChecked;
1019 /* determine if it is already in the versionExceptionHash */
1021 int thisJobNum = item->text().toInt();
1022 if (thisJobNum == hashJobNum)
1023 newState = Qt::Checked;
1025 if (mainWin->m_rtChecksDebug) {
1026 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1027 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1028 Pmsg1(000, "%s", msg.toUtf8().data());
1030 if (newState != curState)
1031 versionTableDisconnectedSet(item, newState);
1032 m_versionCheckStateList[row] = newState;
1037 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1039 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1043 QString fullPath = fullPath_in;
1044 QString direct, path;
1045 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1046 direct = path = fullPath;
1047 path.replace(index+1, fullPath.length()-index-1, "");
1048 direct.replace(0, index+1, "");
1050 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1051 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1052 Pmsg0(000, msg.toUtf8().data());
1055 subPaths.append(fullPath);
1060 * A Function to set the icon state and insert a record into
1061 * m_directoryIconStateHash when an exception is added by the user
1063 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1066 fullPathtoSubPaths(paths, fullPath);
1067 /* an exception that causes the item in the file table to be "Checked" has occured */
1068 if (excpState == Qt::Checked) {
1069 bool foundAsUnChecked = false;
1070 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1072 if (firstItem->checkState(0) == Qt::Unchecked)
1073 foundAsUnChecked = true;
1075 if (foundAsUnChecked) {
1076 /* as long as directory item is Unchecked, set icon state to "green check" */
1078 QListIterator<QString> siter(paths);
1079 while (siter.hasNext() && !done) {
1080 QString path = siter.next();
1081 QTreeWidgetItem *item = m_dirPaths.value(path);
1083 if (item->checkState(0) != Qt::Unchecked)
1086 directorySetIcon(1, FolderGreenChecked, path, item);
1087 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1092 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1093 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1095 QListIterator<QString> siter(paths);
1096 while (siter.hasNext() && !done) {
1097 QString path = siter.next();
1098 QTreeWidgetItem *item = m_dirPaths.value(path);
1099 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1100 if (item->checkState(0) == Qt::Checked)
1102 directorySetIcon(1, FolderGreenChecked, path, item);
1103 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1108 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1109 if (excpState == Qt::Unchecked) {
1111 QListIterator<QString> siter(paths);
1112 while (siter.hasNext() && !done) {
1113 QString path = siter.next();
1114 QTreeWidgetItem *item = m_dirPaths.value(path);
1115 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1116 if (item->checkState(0) == Qt::Checked)
1118 directorySetIcon(1, FolderWhiteChecked, path, item);
1119 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1126 * A function to set the icon state back to "folder" and to remove a record from
1127 * m_directoryIconStateHash when an exception is removed by a user.
1129 void restoreTree::directoryIconStateRemove()
1131 QHash<QString, int> shouldBeIconStateHash;
1132 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1133 /* Use iterator tera to iterate through m_fileExceptionHash */
1134 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1135 while (tera.hasNext()) {
1137 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1139 QString keyPath = tera.key();
1140 Qt::CheckState state = tera.value();
1143 fullPathtoSubPaths(paths, keyPath);
1144 /* if the state of the item in m_fileExceptionHash is checked
1145 * each of the subpaths should be "Checked Green" */
1146 if (state == Qt::Checked) {
1148 bool foundAsUnChecked = false;
1149 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1151 if (firstItem->checkState(0) == Qt::Unchecked)
1152 foundAsUnChecked = true;
1154 if (foundAsUnChecked) {
1155 /* The right most directory is Unchecked, iterate leftwards
1156 * as long as directory item is Unchecked, set icon state to "green check" */
1158 QListIterator<QString> siter(paths);
1159 while (siter.hasNext() && !done) {
1160 QString path = siter.next();
1161 QTreeWidgetItem *item = m_dirPaths.value(path);
1163 if (item->checkState(0) != Qt::Unchecked)
1166 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1167 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1173 /* The right most directory is Unchecked, iterate leftwards
1174 * until directory item is Checked, set icon state to "green check" */
1176 QListIterator<QString> siter(paths);
1177 while (siter.hasNext() && !done) {
1178 QString path = siter.next();
1179 QTreeWidgetItem *item = m_dirPaths.value(path);
1181 if (item->checkState(0) == Qt::Checked)
1183 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1188 /* if the state of the item in m_fileExceptionHash is UNChecked
1189 * each of the subpaths should be "Checked white" until the tree item
1190 * which represents that path is Qt::Checked */
1191 if (state == Qt::Unchecked) {
1193 QListIterator<QString> siter(paths);
1194 while (siter.hasNext() && !done) {
1195 QString path = siter.next();
1196 QTreeWidgetItem *item = m_dirPaths.value(path);
1198 if (item->checkState(0) == Qt::Checked)
1200 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1205 /* now iterate through m_directoryIconStateHash which are the items that are checked
1206 * and remove all of those that are not in shouldBeIconStateHash */
1207 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1208 while (iter.hasNext()) {
1210 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1212 QString keyPath = iter.key();
1213 if (shouldBeIconStateHash.value(keyPath)) {
1214 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1215 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1216 int newval = shouldBeIconStateHash.value(keyPath);
1218 newval = newval & FolderBothChecked;
1219 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1221 directorySetIcon(0, newval, keyPath, item);
1223 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1224 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1226 directorySetIcon(0, FolderBothChecked, keyPath, item);
1227 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1228 //m_directoryIconStateHash.remove(keyPath);
1233 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1235 /* we are adding a check type white or green */
1236 if (operation > 0) {
1237 /* get the old val and "bitwise OR" with the change */
1238 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1239 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1240 m_directoryIconStateHash.insert(path, newval);
1242 /* we are removing a check type white or green */
1243 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1245 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1246 m_directoryIconStateHash.remove(path);
1249 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1250 m_directoryIconStateHash.insert(path, newval);
1253 if (newval == FolderUnchecked)
1254 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1255 else if (newval == FolderGreenChecked)
1256 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1257 else if (newval == FolderWhiteChecked)
1258 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1259 else if (newval == FolderBothChecked)
1260 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1266 void restoreTree::restoreButtonPushed()
1268 QMultiHash<int, QString> versionFilesMulti;
1269 QHash <QString, bool> fullPathDone;
1270 QHash <QString, int> fileIndexHash;
1271 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1272 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1273 /* Use a tree widget item iterator filtering for Checked Items */
1274 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1276 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1277 if (mainWin->m_rtRestore1Debug)
1278 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1279 /* With a checked directory, query for the files in the directory */
1282 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1284 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1286 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1287 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1288 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1289 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1290 " AND Job.Jobid IN (" + m_jobQuery + ")"
1291 " GROUP BY Filename.Name"
1293 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1294 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1295 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1297 " Path.Path='" + directory + "'"
1298 " AND Filename.Name=t1.Filename"
1299 " AND Job.Jobid=t1.JobId"
1300 " ORDER BY Filename";
1302 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1303 QStringList results;
1304 if (m_console->sql_cmd(cmd, results)) {
1306 QStringList fieldlist;
1309 /* Iterate through the record returned from the query */
1310 foreach (QString resultline, results) {
1311 /* Iterate through fields in the record */
1313 QString fullPath = "";
1314 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1315 fieldlist = resultline.split("\t");
1318 foreach (QString field, fieldlist) {
1320 fullPath = directory + field;
1323 version = field.toInt();
1326 fileIndex = field.toInt();
1330 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1332 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1333 if (fileExcpState != Qt::Unchecked) {
1335 if (excpVersion != 0) {
1336 debugtext = QString("*E* version=%1").arg(excpVersion);
1337 version = excpVersion;
1338 fileIndex = queryFileIndex(fullPath, excpVersion);
1340 debugtext = QString("___ version=%1").arg(version);
1341 if (mainWin->m_rtRestore1Debug)
1342 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1343 fullPathDone.insert(fullPath, 1);
1344 fileIndexHash.insert(fullPath, fileIndex);
1345 versionFilesMulti.insert(version, fullPath);
1351 } /* while (*diter) */
1353 /* There may be some exceptions not accounted for yet with fullPathDone */
1354 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1355 while (ftera.hasNext()) {
1357 QString fullPath = ftera.key();
1358 Qt::CheckState state = ftera.value();
1360 /* now we don't want the ones already done */
1361 if (fullPathDone.value(fullPath, 0) == 0) {
1362 int version = m_versionExceptionHash.value(fullPath, 0);
1364 QString debugtext = "";
1366 fileIndex = queryFileIndex(fullPath, version);
1367 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1369 version = mostRecentVersionfromFullPath(fullPath);
1371 fileIndex = queryFileIndex(fullPath, version);
1372 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1374 debugtext = QString("Error det vers").arg(version);
1376 if (mainWin->m_rtRestore1Debug)
1377 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1378 versionFilesMulti.insert(version, fullPath);
1379 fileIndexHash.insert(fullPath, fileIndex);
1380 } /* if fullPathDone.value(fullPath, 0) == 0 */
1381 } /* if state != 0 */
1382 } /* while ftera.hasNext */
1384 /* now for the final spit out of the versions and lists of files for each version */
1385 QHash<int, int> doneKeys;
1386 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1387 QString tempTable = "";
1389 while (vFMiter.hasNext()) {
1391 int fversion = vFMiter.key();
1392 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1393 if (doneKeys.value(fversion, 0) == 0) {
1394 if (tempTable == "") {
1395 QSettings settings("www.bacula.org", "bat");
1396 settings.beginGroup("Restore");
1397 int counter = settings.value("Counter", 1).toInt();
1398 settings.setValue("Counter", counter+1);
1399 settings.endGroup();
1400 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1401 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1402 if (mainWin->m_sqlDebug)
1403 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1404 QStringList results;
1405 if (!m_console->sql_cmd(sqlcmd, results))
1406 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1409 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1410 QStringList fullPathList = versionFilesMulti.values(fversion);
1411 /* create the command to perform the restore */
1412 foreach(QString ffullPath, fullPathList) {
1413 int fileIndex = fileIndexHash.value(ffullPath);
1414 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1415 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1416 if (mainWin->m_sqlDebug)
1417 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1418 QStringList results;
1419 if (!m_console->sql_cmd(sqlcmd, results))
1420 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1421 } /* foreach fullPathList */
1422 doneKeys.insert(fversion,1);
1423 jobList.append(fversion);
1424 } /* if (doneKeys.value(fversion, 0) == 0) */
1425 } /* while (vFMiter.hasNext()) */
1426 if (tempTable != "") {
1427 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
1428 new restoreTreeRunPage(tempTable, m_prevClientCombo, jobList, pageSelectorTreeWidgetItem);
1432 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1435 QString directory, fileName;
1436 int index = m_slashregex.lastIndexIn(fullPath, -2);
1438 directory = fileName = fullPath;
1439 directory.replace(index+1, fullPath.length()-index-1, "");
1440 fileName.replace(0, index+1, "");
1442 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1443 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1444 Pmsg0(000, msg.toUtf8().data());
1446 /* so now we need the latest version from the database */
1448 "SELECT MAX(Job.JobId)"
1450 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1451 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1452 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1453 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1454 " AND Job.Jobid IN (" + m_jobQuery + ")"
1455 " AND Filename.Name='" + fileName + "'"
1456 " GROUP BY Filename.Name";
1458 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1459 QStringList results;
1460 if (m_console->sql_cmd(cmd, results)) {
1461 QStringList fieldlist;
1463 /* Iterate through the record returned from the query */
1464 foreach (QString resultline, results) {
1465 /* Iterate through fields in the record */
1467 fieldlist = resultline.split("\t");
1468 foreach (QString field, fieldlist) {
1470 qversion = field.toInt();
1477 } /* if (index != -1) */
1482 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1485 QString directory, fileName;
1486 int index = m_slashregex.lastIndexIn(fullPath, -2);
1488 directory = fileName = fullPath;
1489 directory.replace(index+1, fullPath.length()-index-1, "");
1490 fileName.replace(0, index+1, "");
1492 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1493 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1494 Pmsg0(000, msg.toUtf8().data());
1496 /* so now we need the latest version from the database */
1501 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1502 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1503 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1505 " Path.Path='" + directory + "'"
1506 " AND Filename.Name='" + fileName + "'"
1507 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1508 " GROUP BY File.FileIndex";
1510 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1511 QStringList results;
1512 if (m_console->sql_cmd(cmd, results)) {
1513 QStringList fieldlist;
1515 /* Iterate through the record returned from the query */
1516 foreach (QString resultline, results) {
1517 /* Iterate through fields in the record */
1519 fieldlist = resultline.split("\t");
1520 foreach (QString field, fieldlist) {
1522 qfileIndex = field.toInt();
1529 } /* if (index != -1) */