2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
34 * Kern Sibbald, February MMVII
39 #include "restoretree.h"
42 restoreTree::restoreTree()
45 m_name = "Version Browser";
47 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
55 m_winRegExpDrive.setPattern("^[a-z]:/$");
56 m_winRegExpPath.setPattern("^[a-z]:/");
57 m_slashregex.setPattern("/");
60 /* progress widgets */
61 prBar1->setVisible(false);
62 prBar2->setVisible(false);
63 prLabel1->setVisible(false);
64 prLabel2->setVisible(false);
67 restoreTree::~restoreTree()
73 * Called from the constructor to set up the page widgets and connections.
75 void restoreTree::setupPage()
77 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
78 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
79 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
80 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
81 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
82 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
83 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
84 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
85 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
86 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
87 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
89 QStringList titles = QStringList() << "Directories";
90 directoryTree->setHeaderLabels(titles);
91 clientCombo->addItems(m_console->client_list);
92 fileSetCombo->addItem("Any");
93 fileSetCombo->addItems(m_console->fileset_list);
94 jobCombo->addItems(m_console->job_list);
96 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
100 * When refresh button is pushed, perform a query getting the directories and
101 * use parseDirectory and addDirectory to populate the directory tree with items.
103 void restoreTree::populateDirectoryTree()
107 directoryTree->clear();
109 fileTable->setRowCount(0);
110 fileTable->setColumnCount(0);
111 versionTable->clear();
112 versionTable->setRowCount(0);
113 versionTable->setColumnCount(0);
114 m_fileExceptionHash.clear();
115 m_fileExceptionMulti.clear();
116 m_versionExceptionHash.clear();
117 m_directoryIconStateHash.clear();
119 /* Set progress bars and repaint */
120 prBar1->setVisible(true);
121 prBar1->setRange(0,2);
123 prLabel1->setText("Task 1 of 2");
124 prLabel1->setVisible(true);
125 prBar2->setVisible(true);
126 prBar2->setRange(0,0);
127 prLabel2->setText("Querying Database");
128 prLabel2->setVisible(true);
131 int clientIndex = clientCombo->currentIndex();
132 int fileSetIndex = fileSetCombo->currentIndex();
133 QString jobComboText = jobCombo->itemText(jobCombo->currentIndex());
134 QString clientComboText = clientCombo->itemText(clientIndex);
135 QString fileSetComboText = fileSetCombo->itemText(fileSetIndex);
136 if ((m_prevJobCombo != jobComboText) || (m_prevClientCombo != clientComboText) || (m_prevFileSetCombo != fileSetComboText)) {
137 m_prevJobCombo = jobComboText;
138 m_prevClientCombo = clientComboText;
139 m_prevFileSetCombo = fileSetComboText;
140 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
142 m_condition = " Job.name = '" + jobCombo->itemText(jobCombo->currentIndex()) + "'";
143 if ((clientIndex >= 0) && (clientCombo->itemText(clientIndex) != "Any")) {
144 m_condition.append(" AND Client.Name='" + clientCombo->itemText(clientIndex) + "'");
146 if ((fileSetIndex >= 0) && (fileSetCombo->itemText(fileSetIndex) != "Any")) {
147 m_condition.append(" AND FileSet.FileSet='" + fileSetCombo->itemText(fileSetIndex) + "'");
150 " LEFT OUTER JOIN Client ON (Job.ClientId=Client.ClientId)"
151 " LEFT OUTER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
152 " WHERE" + m_condition +
153 " AND Job.purgedfiles=0";
156 " From Job" + m_jobQueryPart;
157 if (mainWin->m_sqlDebug) {
158 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
161 setJobsCheckedList();
163 setJobsCheckedList();
167 "SELECT DISTINCT Path.Path AS Path"
169 " LEFT OUTER JOIN File ON (File.PathId=Path.PathId)"
170 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
171 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
173 if (mainWin->m_sqlDebug) {
174 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
177 prLabel1->setText("Task 2 of 2");
178 QStringList directories;
179 if (m_console->sql_cmd(cmd, directories)) {
180 if (mainWin->m_miscDebug) {
181 Pmsg1(000, "Done with query %i directories\n", directories.count());
184 prBar2->setRange(0,directories.count());
185 prLabel2->setText("Processing Directories");
187 foreach(QString directory, directories) {
189 prBar2->setValue(m_debugCnt);
190 parseDirectory(directory);
193 prBar1->setVisible(false);
194 prBar2->setVisible(false);
195 prLabel1->setVisible(false);
196 prLabel2->setVisible(false);
200 * Function to set m_jobQuery from the jobs that are checked in the table
203 void restoreTree::setJobsCheckedList()
205 m_JobsCheckedList = "";
207 /* Update the items in the version table */
208 int cnt = jobTable->rowCount();
209 for (int row=0; row<cnt; row++) {
210 QTableWidgetItem* jobItem = jobTable->item(row, 0);
211 if (jobItem->checkState() == Qt::Checked) {
213 m_JobsCheckedList += ",";
214 m_JobsCheckedList += jobItem->text();
216 jobItem->setBackground(Qt::green);
218 jobItem->setBackground(Qt::gray);
220 m_jobQuery = m_JobsCheckedList;
224 * Function to parse a directory into all possible subdirectories, then add to
227 void restoreTree::parseDirectory(QString &dir_in)
229 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
230 * instead of printing out what could potentially a whole bunch */
233 /* Clean up the directory string remove some funny char after last '/' */
234 QRegExp rgx("[^/]$");
235 int lastslash = rgx.indexIn(dir_in);
236 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
237 if ((mainWin->m_miscDebug) && (m_debugTrap))
238 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
240 /* split and add if not in yet */
241 QString direct, path;
244 QStringList pathAfter, dirAfter;
245 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
246 * if not added into tree, then try /etc/ and somedir/ if not added, then try
247 * / and etc/ . That should succeed, then add the ones that failed in reverse */
248 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
249 direct = path = dir_in;
250 path.replace(index+1, dir_in.length()-index-1,"");
251 direct.replace(0, index+1, "");
252 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
253 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
254 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
255 Pmsg0(000, msg.toUtf8().data());
257 if (addDirectory(path, direct)) done = true;
259 if ((mainWin->m_miscDebug) && (m_debugTrap))
260 Pmsg0(000, "Saving for later\n");
261 pathAfter.prepend(path);
262 dirAfter.prepend(direct);
267 for (int k=0; k<pathAfter.count(); k++) {
268 if (addDirectory(pathAfter[k], dirAfter[k]))
269 if ((mainWin->m_miscDebug) && (m_debugTrap))
270 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
272 if ((mainWin->m_miscDebug) && (m_debugTrap))
273 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
278 * Function called from fill directory when a directory is found to see if this
279 * directory exists in the directory pane and then add it to the directory pane
281 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
283 QString newdir = newdirr;
284 QString fullPath = m_cwd + newdirr;
285 bool ok = true, added = false;
287 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
288 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
291 Pmsg0(000, msg.toUtf8().data());
295 /* add unix '/' directory first */
296 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
298 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
300 item->setText(0, text.toUtf8().data());
301 item->setData(0, Qt::UserRole, QVariant(text));
302 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
303 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
304 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
305 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
307 m_dirPaths.insert(text, item);
309 /* no need to check for windows drive if unix */
310 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
311 /* this is a windows drive add the base widget */
312 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
313 item->setText(0, m_cwd);
314 item->setData(0, Qt::UserRole, QVariant(fullPath));
315 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
316 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
317 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
318 Pmsg0(000, "Added Base \"letter\":/\n");
320 m_dirPaths.insert(m_cwd, item);
324 /* is it already existent ?? */
325 if (!m_dirPaths.contains(fullPath)) {
326 QTreeWidgetItem *item = NULL;
327 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
329 /* new directories to add */
330 item = new QTreeWidgetItem(parent);
331 item->setText(0, newdir.toUtf8().data());
332 item->setData(0, Qt::UserRole, QVariant(fullPath));
333 item->setCheckState(0, Qt::Unchecked);
334 /* Store the current state of the check status in column 1, which at
335 * this point has no text*/
336 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
339 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
340 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
343 Pmsg0(000, msg.toUtf8().data());
346 /* insert into hash */
348 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
349 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
351 m_dirPaths.insert(fullPath, item);
359 * Virtual function which is called when this page is visible on the stack
361 void restoreTree::currentStackItem()
364 if (!m_console->preventInUseConnect())
372 * Populate the tree when refresh button pushed.
374 void restoreTree::refreshButtonPushed()
376 populateDirectoryTree();
380 * Set the values of non-job combo boxes to the job defaults
382 void restoreTree::jobComboChanged(int)
384 job_defaults job_defs;
387 job_defs.job_name = jobCombo->currentText();
388 if (m_console->get_job_defaults(job_defs)) {
389 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
390 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
395 * Function to populate the file list table
397 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
402 m_fileCheckStateList.clear();
403 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
404 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
405 QBrush blackBrush(Qt::black);
406 QString directory = item->data(0, Qt::UserRole).toString();
407 directoryLabel->setText("Present Working Directory : " + directory);
409 "SELECT DISTINCT Filename.Name AS FileName"
411 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
412 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
413 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
414 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
415 " AND Job.Jobid IN (" + m_jobQuery + ")"
416 " ORDER BY FileName";
418 QStringList headerlist = (QStringList() << "File Name");
420 /* Also clear the version table here */
421 versionTable->clear();
422 versionFileLabel->setText("");
423 versionTable->setRowCount(0);
424 versionTable->setColumnCount(0);
425 fileTable->setColumnCount(headerlist.size());
426 fileTable->setHorizontalHeaderLabels(headerlist);
428 if (mainWin->m_sqlDebug) {
429 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
432 if (m_console->sql_cmd(cmd, results)) {
434 QTableWidgetItem* tableItem;
436 QStringList fieldlist;
437 fileTable->setRowCount(results.size());
440 /* Iterate through the record returned from the query */
441 foreach (QString resultline, results) {
442 /* Iterate through fields in the record */
444 fieldlist = resultline.split("\t");
445 foreach (field, fieldlist) {
446 field = field.trimmed(); /* strip leading & trailing spaces */
447 tableItem = new QTableWidgetItem(field, 1);
448 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
449 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
450 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
451 tableItem->setForeground(blackBrush);
452 /* Just in case a column ever gets added */
454 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
455 tableItem->setFlags(flag);
456 tableItem->setData(Qt::UserRole, QVariant(directory));
457 fileTable->setItem(row, column, tableItem);
458 m_fileCheckStateList.append(Qt::Unchecked);
459 tableItem->setCheckState(Qt::Unchecked);
465 fileTable->setRowCount(row);
467 fileTable->resizeColumnsToContents();
468 fileTable->resizeRowsToContents();
469 fileTable->verticalHeader()->hide();
470 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
471 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
472 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
473 updateFileTableChecks();
477 * Function to populate the version table
479 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
481 if (fileTableItem == NULL)
484 m_versionCheckStateList.clear();
485 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
486 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
488 QString file = fileTableItem->text();
489 versionFileLabel->setText(file);
490 QString directory = fileTableItem->data(Qt::UserRole).toString();
492 QBrush blackBrush(Qt::black);
494 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
496 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
497 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
498 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
499 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
500 " AND Job.Jobid IN (" + m_jobQuery + ")"
501 " ORDER BY Job.EndTime DESC";
503 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
504 versionTable->clear();
505 versionTable->setColumnCount(headerlist.size());
506 versionTable->setHorizontalHeaderLabels(headerlist);
508 if (mainWin->m_sqlDebug) {
509 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
512 if (m_console->sql_cmd(cmd, results)) {
514 QTableWidgetItem* tableItem;
516 QStringList fieldlist;
517 versionTable->setRowCount(results.size());
520 /* Iterate through the record returned from the query */
521 foreach (QString resultline, results) {
522 fieldlist = resultline.split("\t");
524 /* remove directory */
525 if (fieldlist[0].trimmed() != "") {
526 /* Iterate through fields in the record */
527 foreach (field, fieldlist) {
528 field = field.trimmed(); /* strip leading & trailing spaces */
529 tableItem = new QTableWidgetItem(field, 1);
530 tableItem->setFlags(0);
531 tableItem->setForeground(blackBrush);
532 tableItem->setData(Qt::UserRole, QVariant(directory));
533 versionTable->setItem(row, column, tableItem);
536 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
537 tableItem->setFlags(flag);
538 m_versionCheckStateList.append(Qt::Unchecked);
539 tableItem->setCheckState(Qt::Unchecked);
547 versionTable->resizeColumnsToContents();
548 versionTable->resizeRowsToContents();
549 versionTable->verticalHeader()->hide();
550 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
551 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
552 updateVersionTableChecks();
556 * Save user settings associated with this page
558 void restoreTree::writeSettings()
560 QSettings settings(m_console->m_dir->name(), "bat");
561 settings.beginGroup("RestoreTree");
562 settings.setValue("splitterSizes", splitter->saveState());
567 * Read and restore user settings associated with this page
569 void restoreTree::readSettings()
571 QSettings settings(m_console->m_dir->name(), "bat");
572 settings.beginGroup("RestoreTree");
573 splitter->restoreState(settings.value("splitterSizes").toByteArray());
578 * This is a funcion to accomplish the one thing I struggled to figure out what
579 * was taking so long. It add the icons, but after the tree is made. Seemed to
580 * work fast after changing from svg to png file for graphic.
582 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
584 int childCount = item->childCount();
585 for (int i=0; i<childCount; i++) {
586 QTreeWidgetItem *child = item->child(i);
587 if (child->icon(0).isNull())
588 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
593 * I wanted a table to show what jobs meet the criterion and are being used to
594 * populate the directory tree and file and version tables.
596 void restoreTree::populateJobTable()
598 QBrush blackBrush(Qt::black);
599 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
601 jobTable->setColumnCount(headerlist.size());
602 jobTable->setHorizontalHeaderLabels(headerlist);
604 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
605 " FROM Job" + m_jobQueryPart +
606 " ORDER BY Job.EndTime DESC";
607 if (mainWin->m_sqlDebug) {
608 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
612 if (m_console->sql_cmd(jobQuery, results)) {
614 QTableWidgetItem* tableItem;
616 QStringList fieldlist;
617 jobTable->setRowCount(results.size());
620 /* Iterate through the record returned from the query */
621 foreach (QString resultline, results) {
622 fieldlist = resultline.split("\t");
624 /* remove directory */
625 if (fieldlist[0].trimmed() != "") {
626 /* Iterate through fields in the record */
627 foreach (field, fieldlist) {
628 field = field.trimmed(); /* strip leading & trailing spaces */
629 tableItem = new QTableWidgetItem(field, 1);
630 tableItem->setFlags(0);
631 tableItem->setForeground(blackBrush);
632 jobTable->setItem(row, column, tableItem);
634 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
635 tableItem->setFlags(flag);
636 tableItem->setCheckState(Qt::Checked);
637 tableItem->setBackground(Qt::green);
645 jobTable->resizeColumnsToContents();
646 jobTable->resizeRowsToContents();
647 jobTable->verticalHeader()->hide();
651 * When a directory item is "changed" check the state of the checkable item
652 * to see if it is different than what it was which is stored in Qt::UserRole
653 * of the 2nd column, column 1, of the tree widget.
655 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
657 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
658 Qt::CheckState curState = item->checkState(0);
659 QTreeWidgetItem* parent = item->parent();
660 Qt::CheckState parState;
661 if (parent) parState = parent->checkState(0);
662 else parState = (Qt::CheckState)3;
663 if (mainWin->m_rtDirICDebug) {
664 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
665 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
666 Pmsg1(000, "%s", msg.toUtf8().data()); }
667 /* I only care when the check state changes */
668 if (prevState == curState) {
669 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
673 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
674 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
675 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
676 curState = Qt::PartiallyChecked;
678 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
679 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
680 directoryTreeDisconnectedSet(item, Qt::Unchecked);
681 curState = Qt::Unchecked;
683 if (mainWin->m_rtDirICDebug) {
684 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
685 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
686 Pmsg1(000, "%s", msg.toUtf8().data()); }
688 item->setData(1, Qt::UserRole, QVariant(curState));
689 Qt::CheckState childState = curState;
690 if (childState == Qt::Checked)
691 childState = Qt::PartiallyChecked;
692 setCheckofChildren(item, childState);
694 /* Remove items from the exception lists. The multi exception list is my index
695 * of what exceptions can be removed when the directory is known*/
696 QString directory = item->data(0, Qt::UserRole).toString();
697 QStringList fullPathList = m_fileExceptionMulti.values(directory);
698 int fullPathListCount = fullPathList.count();
699 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
700 foreach (QString fullPath, fullPathList) {
701 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
702 * which will match no Qt::xxx values */
703 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
704 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
705 if (hashState == Qt::Unchecked) {
706 fileExceptionRemove(fullPath, directory);
707 m_versionExceptionHash.remove(fullPath);
708 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
710 if (hashState == Qt::Checked) {
711 fileExceptionRemove(fullPath, directory);
712 m_versionExceptionHash.remove(fullPath);
713 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
717 if (item == directoryTree->currentItem()) {
718 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
719 updateFileTableChecks();
720 versionTable->clear();
721 versionTable->setRowCount(0);
722 versionTable->setColumnCount(0);
724 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
728 * When a directory item check state is changed, this function iterates through
729 * all subdirectories and sets all to the passed state, which is either partially
730 * checked or unchecked.
732 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
735 childCount = item->childCount();
736 for (int i=0; i<childCount; i++) {
737 QTreeWidgetItem *child = item->child(i);
738 child->setData(1, Qt::UserRole, QVariant(state));
739 child->setCheckState(0, state);
740 setCheckofChildren(child, state);
745 * When a File Table Item is "changed" check to see if the state of the checkable
746 * item has changed which is stored in m_fileCheckStateList
747 * If changed store in a hash m_fileExceptionHash that whether this file should be
749 * Called as a slot, connected after populated (after directory current changed called)
751 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
753 /* get the previous and current check states */
754 int row = fileTable->row(item);
755 Qt::CheckState prevState;
756 /* prevent a segfault */
757 prevState = m_fileCheckStateList[row];
758 Qt::CheckState curState = item->checkState();
760 /* deterimine the default state from the state of the directory */
761 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
762 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
763 Qt::CheckState defState = Qt::PartiallyChecked;
764 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
766 /* determine if it is already in the m_fileExceptionHash */
767 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
768 QString file = item->text();
769 QString fullPath = directory + file;
770 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
771 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
773 if (mainWin->m_rtFileTabICDebug) {
774 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
775 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
776 Pmsg1(000, "%s", msg.toUtf8().data()); }
778 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
779 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
780 /* it can behave as defaulted so current of unchecked is fine */
781 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
782 fileExceptionRemove(fullPath, directory);
783 m_versionExceptionHash.remove(fullPath);
784 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
785 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
786 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
787 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
788 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
789 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
790 fileExceptionRemove(fullPath, directory);
791 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
792 /* Check dir, check version, attempt uncheck in file
793 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
794 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
795 fileExceptionRemove(fullPath, directory);
796 m_versionExceptionHash.remove(fullPath);
797 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
798 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
799 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
800 } else if (prevState != curState) {
801 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
802 /* A user did not set the check state to Partially checked, ignore if so */
803 if (curState != Qt::PartiallyChecked) {
804 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
805 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
807 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
808 fileExceptionInsert(fullPath, directory, curState);
811 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
812 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
813 m_versionExceptionHash.remove(fullPath);
817 updateFileTableChecks();
818 updateVersionTableChecks();
822 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
824 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
826 m_fileExceptionHash.insert(fullPath, state);
827 m_fileExceptionMulti.insert(direcotry, fullPath);
828 directoryIconStateInsert(fullPath, state);
832 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
834 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
836 m_fileExceptionHash.remove(fullPath);
837 /* pull the list of values in the multi */
838 QStringList fullPathList = m_fileExceptionMulti.values(directory);
839 /* get the index of the fullpath to remove */
840 int index = fullPathList.indexOf(fullPath);
842 /* remove the desired item in the list */
843 fullPathList.removeAt(index);
844 /* remove the entire list from the multi */
845 m_fileExceptionMulti.remove(directory);
846 /* readd the remaining */
847 foreach (QString fp, fullPathList) {
848 m_fileExceptionMulti.insert(directory, fp);
851 directoryIconStateRemove();
855 * Overloaded function to be called from the slot and from other places to set the state
856 * of the check marks in the version table
858 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
860 /* get the previous and current check states */
861 int row = versionTable->row(item);
862 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
863 Qt::CheckState prevState = m_versionCheckStateList[row];
864 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
865 m_versionCheckStateList[row] = curState;
867 /* deterimine the default state from the state of the file */
868 QTableWidgetItem *fileTableItem = fileTable->currentItem();
869 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
871 /* determine the default state */
872 Qt::CheckState defState;
874 defState = Qt::PartiallyChecked;
875 if (fileState == Qt::Unchecked)
876 defState = Qt::Unchecked;
879 defState = Qt::Unchecked;
881 /* determine if it is already in the versionExceptionHash */
882 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
883 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
884 QString file = fileTableItem->text();
885 QString fullPath = directory + file;
886 int thisJobNum = colZeroItem->text().toInt();
887 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
889 if (mainWin->m_rtVerTabICDebug) {
890 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
891 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
892 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
893 Pmsg1(000, "%s", msg.toUtf8().data()); }
894 /* if changed from partially checked to checked, make it unchecked */
895 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
896 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
897 fileTableItem->setCheckState(Qt::Checked);
898 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
899 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
900 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
901 fileExceptionRemove(fullPath, directory);
902 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
903 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
904 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
905 m_versionExceptionHash.remove(fullPath);
906 fileExceptionRemove(fullPath, directory);
907 } else if ((curState == Qt::Checked) && (row == 0)) {
908 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
909 m_versionExceptionHash.remove(fullPath);
910 } else if (prevState != curState) {
911 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
912 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
913 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
914 m_versionExceptionHash.insert(fullPath, thisJobNum);
915 if (fileState != Qt::Checked) {
916 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
917 fileExceptionInsert(fullPath, directory, curState);
920 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
923 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
926 updateFileTableChecks();
927 updateVersionTableChecks();
931 * Simple function to set the check state in the file table by disconnecting the
932 * signal/slot the setting then reconnecting the signal/slot
934 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
936 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
937 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
938 item->setCheckState(state);
939 if (color) item->setBackground(Qt::yellow);
940 else item->setBackground(Qt::white);
941 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
942 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
946 * Simple function to set the check state in the version table by disconnecting the
947 * signal/slot the setting then reconnecting the signal/slot
949 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
951 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
952 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
953 item->setCheckState(state);
954 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
955 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
959 * Simple function to set the check state in the directory tree by disconnecting the
960 * signal/slot the setting then reconnecting the signal/slot
962 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
964 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
965 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
966 item->setCheckState(0, state);
967 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
968 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
972 * Simplify the updating of the check state in the File table by iterating through
973 * each item in the file table to determine it's appropriate state.
974 * !! Will probably want to concoct a way to do this without iterating for the possibility
975 * of the very large directories.
977 void restoreTree::updateFileTableChecks()
979 /* deterimine the default state from the state of the directory */
980 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
981 Qt::CheckState dirState = dirTreeItem->checkState(0);
983 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
985 /* Update the items in the version table */
986 int rcnt = fileTable->rowCount();
987 for (int row=0; row<rcnt; row++) {
988 QTableWidgetItem* item = fileTable->item(row, 0);
990 Qt::CheckState curState = item->checkState();
991 Qt::CheckState newState = Qt::PartiallyChecked;
992 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
994 /* determine if it is already in the m_fileExceptionHash */
995 QString file = item->text();
996 QString fullPath = dirName + file;
997 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
998 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1000 if (hashState != 3) newState = hashState;
1002 if (mainWin->m_rtUpdateFTDebug) {
1003 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1004 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1005 Pmsg1(000, "%s", msg.toUtf8().data());
1008 bool docolor = false;
1009 if (hashJobNum != 0) docolor = true;
1010 bool isyellow = item->background().color() == QColor(Qt::yellow);
1011 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1012 fileTableDisconnectedSet(item, newState, docolor);
1013 m_fileCheckStateList[row] = newState;
1018 * Simplify the updating of the check state in the Version table by iterating through
1019 * each item in the file table to determine it's appropriate state.
1021 void restoreTree::updateVersionTableChecks()
1023 /* deterimine the default state from the state of the directory */
1024 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1025 Qt::CheckState dirState = dirTreeItem->checkState(0);
1026 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1028 /* deterimine the default state from the state of the file */
1029 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1030 Qt::CheckState fileState = fileTableItem->checkState();
1031 QString file = fileTableItem->text();
1032 QString fullPath = dirName + file;
1033 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1035 /* Update the items in the version table */
1036 int cnt = versionTable->rowCount();
1037 for (int row=0; row<cnt; row++) {
1038 QTableWidgetItem* item = versionTable->item(row, 0);
1040 Qt::CheckState curState = item->checkState();
1041 Qt::CheckState newState = Qt::Unchecked;
1043 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1044 newState = Qt::PartiallyChecked;
1045 /* determine if it is already in the versionExceptionHash */
1047 int thisJobNum = item->text().toInt();
1048 if (thisJobNum == hashJobNum)
1049 newState = Qt::Checked;
1051 if (mainWin->m_rtChecksDebug) {
1052 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1053 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1054 Pmsg1(000, "%s", msg.toUtf8().data());
1056 if (newState != curState)
1057 versionTableDisconnectedSet(item, newState);
1058 m_versionCheckStateList[row] = newState;
1063 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1065 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1069 QString fullPath = fullPath_in;
1070 QString direct, path;
1071 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1072 direct = path = fullPath;
1073 path.replace(index+1, fullPath.length()-index-1, "");
1074 direct.replace(0, index+1, "");
1076 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1077 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1078 Pmsg0(000, msg.toUtf8().data());
1081 subPaths.append(fullPath);
1086 * A Function to set the icon state and insert a record into
1087 * m_directoryIconStateHash when an exception is added by the user
1089 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1092 fullPathtoSubPaths(paths, fullPath);
1093 /* an exception that causes the item in the file table to be "Checked" has occured */
1094 if (excpState == Qt::Checked) {
1095 bool foundAsUnChecked = false;
1096 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1098 if (firstItem->checkState(0) == Qt::Unchecked)
1099 foundAsUnChecked = true;
1101 if (foundAsUnChecked) {
1102 /* as long as directory item is Unchecked, set icon state to "green check" */
1104 QListIterator<QString> siter(paths);
1105 while (siter.hasNext() && !done) {
1106 QString path = siter.next();
1107 QTreeWidgetItem *item = m_dirPaths.value(path);
1109 if (item->checkState(0) != Qt::Unchecked)
1112 directorySetIcon(1, FolderGreenChecked, path, item);
1113 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1118 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1119 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1121 QListIterator<QString> siter(paths);
1122 while (siter.hasNext() && !done) {
1123 QString path = siter.next();
1124 QTreeWidgetItem *item = m_dirPaths.value(path);
1125 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1126 if (item->checkState(0) == Qt::Checked)
1128 directorySetIcon(1, FolderGreenChecked, path, item);
1129 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1134 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1135 if (excpState == Qt::Unchecked) {
1137 QListIterator<QString> siter(paths);
1138 while (siter.hasNext() && !done) {
1139 QString path = siter.next();
1140 QTreeWidgetItem *item = m_dirPaths.value(path);
1141 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1142 if (item->checkState(0) == Qt::Checked)
1144 directorySetIcon(1, FolderWhiteChecked, path, item);
1145 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1152 * A function to set the icon state back to "folder" and to remove a record from
1153 * m_directoryIconStateHash when an exception is removed by a user.
1155 void restoreTree::directoryIconStateRemove()
1157 QHash<QString, int> shouldBeIconStateHash;
1158 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1159 /* Use iterator tera to iterate through m_fileExceptionHash */
1160 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1161 while (tera.hasNext()) {
1163 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1165 QString keyPath = tera.key();
1166 Qt::CheckState state = tera.value();
1169 fullPathtoSubPaths(paths, keyPath);
1170 /* if the state of the item in m_fileExceptionHash is checked
1171 * each of the subpaths should be "Checked Green" */
1172 if (state == Qt::Checked) {
1174 bool foundAsUnChecked = false;
1175 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1177 if (firstItem->checkState(0) == Qt::Unchecked)
1178 foundAsUnChecked = true;
1180 if (foundAsUnChecked) {
1181 /* The right most directory is Unchecked, iterate leftwards
1182 * as long as directory item is Unchecked, set icon state to "green check" */
1184 QListIterator<QString> siter(paths);
1185 while (siter.hasNext() && !done) {
1186 QString path = siter.next();
1187 QTreeWidgetItem *item = m_dirPaths.value(path);
1189 if (item->checkState(0) != Qt::Unchecked)
1192 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1193 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1199 /* The right most directory is Unchecked, iterate leftwards
1200 * until directory item is Checked, set icon state to "green check" */
1202 QListIterator<QString> siter(paths);
1203 while (siter.hasNext() && !done) {
1204 QString path = siter.next();
1205 QTreeWidgetItem *item = m_dirPaths.value(path);
1207 if (item->checkState(0) == Qt::Checked)
1209 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1214 /* if the state of the item in m_fileExceptionHash is UNChecked
1215 * each of the subpaths should be "Checked white" until the tree item
1216 * which represents that path is Qt::Checked */
1217 if (state == Qt::Unchecked) {
1219 QListIterator<QString> siter(paths);
1220 while (siter.hasNext() && !done) {
1221 QString path = siter.next();
1222 QTreeWidgetItem *item = m_dirPaths.value(path);
1224 if (item->checkState(0) == Qt::Checked)
1226 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1231 /* now iterate through m_directoryIconStateHash which are the items that are checked
1232 * and remove all of those that are not in shouldBeIconStateHash */
1233 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1234 while (iter.hasNext()) {
1236 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1238 QString keyPath = iter.key();
1239 if (shouldBeIconStateHash.value(keyPath)) {
1240 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1241 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1242 int newval = shouldBeIconStateHash.value(keyPath);
1244 newval = newval & FolderBothChecked;
1245 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1247 directorySetIcon(0, newval, keyPath, item);
1249 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1250 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1252 directorySetIcon(0, FolderBothChecked, keyPath, item);
1253 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1254 //m_directoryIconStateHash.remove(keyPath);
1259 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1261 /* we are adding a check type white or green */
1262 if (operation > 0) {
1263 /* get the old val and "bitwise OR" with the change */
1264 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1265 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1266 m_directoryIconStateHash.insert(path, newval);
1268 /* we are removing a check type white or green */
1269 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1271 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1272 m_directoryIconStateHash.remove(path);
1275 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1276 m_directoryIconStateHash.insert(path, newval);
1279 if (newval == FolderUnchecked)
1280 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1281 else if (newval == FolderGreenChecked)
1282 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1283 else if (newval == FolderWhiteChecked)
1284 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1285 else if (newval == FolderBothChecked)
1286 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1292 void restoreTree::restoreButtonPushed()
1294 /* Set progress bars and repaint */
1295 prLabel1->setVisible(true);
1296 prLabel1->setText("Task 1 of 3");
1297 prLabel2->setVisible(true);
1298 prLabel2->setText("Processing Checked directories");
1299 prBar1->setVisible(true);
1300 prBar1->setRange(0, 3);
1301 prBar1->setValue(0);
1302 prBar2->setVisible(true);
1303 prBar2->setRange(0, 0);
1305 QMultiHash<int, QString> versionFilesMulti;
1307 QHash <QString, bool> fullPathDone;
1308 QHash <QString, int> fileIndexHash;
1309 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1310 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1311 /* Use a tree widget item iterator to count directories for the progress bar */
1312 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1317 } /* while (*diterc) */
1318 prBar2->setRange(0, ditcount);
1319 prBar2->setValue(0);
1321 /* Use a tree widget item iterator filtering for Checked Items */
1322 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1324 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1325 if (mainWin->m_rtRestore1Debug)
1326 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1327 /* With a checked directory, query for the files in the directory */
1330 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1332 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1334 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1335 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1336 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1337 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1338 " AND Job.Jobid IN (" + m_jobQuery + ")"
1339 " GROUP BY Filename.Name"
1341 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1342 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1343 " LEFT OUTER JOIN Job ON (Job.JobId=File.JobId)"
1345 " Path.Path='" + directory + "'"
1346 " AND Filename.Name=t1.Filename"
1347 " AND Job.Jobid=t1.JobId"
1348 " ORDER BY Filename";
1350 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1351 QStringList results;
1352 if (m_console->sql_cmd(cmd, results)) {
1353 QStringList fieldlist;
1356 /* Iterate through the record returned from the query */
1357 foreach (QString resultline, results) {
1358 /* Iterate through fields in the record */
1360 QString fullPath = "";
1361 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1362 fieldlist = resultline.split("\t");
1365 foreach (QString field, fieldlist) {
1367 fullPath = directory + field;
1370 version = field.toInt();
1373 fileIndex = field.toInt();
1377 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1379 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1380 if (fileExcpState != Qt::Unchecked) {
1382 if (excpVersion != 0) {
1383 debugtext = QString("*E* version=%1").arg(excpVersion);
1384 version = excpVersion;
1385 fileIndex = queryFileIndex(fullPath, excpVersion);
1387 debugtext = QString("___ version=%1").arg(version);
1388 if (mainWin->m_rtRestore1Debug)
1389 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1390 fullPathDone.insert(fullPath, 1);
1391 fileIndexHash.insert(fullPath, fileIndex);
1392 versionFilesMulti.insert(version, fullPath);
1399 prBar2->setValue(ditcount);
1401 } /* while (*diter) */
1402 prBar1->setValue(1);
1403 prLabel1->setText("Task 2 of 3");
1404 prLabel2->setText("Processing Exceptions");
1405 prBar2->setRange(0, 0);
1408 /* There may be some exceptions not accounted for yet with fullPathDone */
1409 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1410 while (ftera.hasNext()) {
1412 QString fullPath = ftera.key();
1413 Qt::CheckState state = ftera.value();
1415 /* now we don't want the ones already done */
1416 if (fullPathDone.value(fullPath, 0) == 0) {
1417 int version = m_versionExceptionHash.value(fullPath, 0);
1419 QString debugtext = "";
1421 fileIndex = queryFileIndex(fullPath, version);
1422 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1424 version = mostRecentVersionfromFullPath(fullPath);
1426 fileIndex = queryFileIndex(fullPath, version);
1427 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1429 debugtext = QString("Error det vers").arg(version);
1431 if (mainWin->m_rtRestore1Debug)
1432 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1433 versionFilesMulti.insert(version, fullPath);
1435 fileIndexHash.insert(fullPath, fileIndex);
1436 } /* if fullPathDone.value(fullPath, 0) == 0 */
1437 } /* if state != 0 */
1438 } /* while ftera.hasNext */
1439 /* The progress bars for the next step */
1440 prBar1->setValue(2);
1441 prLabel1->setText("Task 3 of 3");
1442 prLabel2->setText("Filling Database Table");
1443 prBar2->setRange(0, vFMCounter);
1445 prBar2->setValue(vFMCounter);
1448 /* now for the final spit out of the versions and lists of files for each version */
1449 QHash<int, int> doneKeys;
1450 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1451 QString tempTable = "";
1453 while (vFMiter.hasNext()) {
1455 int fversion = vFMiter.key();
1456 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1457 if (doneKeys.value(fversion, 0) == 0) {
1458 if (tempTable == "") {
1459 QSettings settings("www.bacula.org", "bat");
1460 settings.beginGroup("Restore");
1461 int counter = settings.value("Counter", 1).toInt();
1462 settings.setValue("Counter", counter+1);
1463 settings.endGroup();
1464 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1465 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1466 if (mainWin->m_sqlDebug)
1467 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1468 QStringList results;
1469 if (!m_console->sql_cmd(sqlcmd, results))
1470 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1473 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1474 QStringList fullPathList = versionFilesMulti.values(fversion);
1475 /* create the command to perform the restore */
1476 foreach(QString ffullPath, fullPathList) {
1477 int fileIndex = fileIndexHash.value(ffullPath);
1478 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1479 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1480 if (mainWin->m_rtRestore3Debug)
1481 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1482 QStringList results;
1483 if (!m_console->sql_cmd(sqlcmd, results))
1484 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1485 prBar2->setValue(++vFMCounter);
1486 } /* foreach fullPathList */
1487 doneKeys.insert(fversion,1);
1488 jobList.append(fversion);
1489 } /* if (doneKeys.value(fversion, 0) == 0) */
1490 } /* while (vFMiter.hasNext()) */
1491 if (tempTable != "") {
1492 /* a table was made, lets run the job */
1493 QString jobOption = " jobid=\"";
1495 /* create a list of jobs comma separated */
1496 foreach (int job, jobList) {
1497 if (first) first = false;
1498 else jobOption += ",";
1499 jobOption += QString("%1").arg(job);
1502 QString cmd = QString("restore");
1504 " file=\"?" + tempTable + "\" done";
1505 if (mainWin->m_commandDebug)
1506 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1507 consoleCommand(cmd);
1509 /* turn off the progress widgets */
1510 prBar1->setVisible(false);
1511 prBar2->setVisible(false);
1512 prLabel1->setVisible(false);
1513 prLabel2->setVisible(false);
1516 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1519 QString directory, fileName;
1520 int index = m_slashregex.lastIndexIn(fullPath, -2);
1522 directory = fileName = fullPath;
1523 directory.replace(index+1, fullPath.length()-index-1, "");
1524 fileName.replace(0, index+1, "");
1526 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1527 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1528 Pmsg0(000, msg.toUtf8().data());
1530 /* so now we need the latest version from the database */
1532 "SELECT MAX(Job.JobId)"
1534 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1535 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1536 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1537 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1538 " AND Job.Jobid IN (" + m_jobQuery + ")"
1539 " AND Filename.Name='" + fileName + "'"
1540 " GROUP BY Filename.Name";
1542 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1543 QStringList results;
1544 if (m_console->sql_cmd(cmd, results)) {
1545 QStringList fieldlist;
1547 /* Iterate through the record returned from the query */
1548 foreach (QString resultline, results) {
1549 /* Iterate through fields in the record */
1551 fieldlist = resultline.split("\t");
1552 foreach (QString field, fieldlist) {
1554 qversion = field.toInt();
1561 } /* if (index != -1) */
1566 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1569 QString directory, fileName;
1570 int index = m_slashregex.lastIndexIn(fullPath, -2);
1572 directory = fileName = fullPath;
1573 directory.replace(index+1, fullPath.length()-index-1, "");
1574 fileName.replace(0, index+1, "");
1576 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1577 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1578 Pmsg0(000, msg.toUtf8().data());
1580 /* so now we need the latest version from the database */
1585 " LEFT OUTER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1586 " LEFT OUTER JOIN Path ON (Path.PathId=File.PathId)"
1587 " LEFT OUTER JOIN Job ON (File.JobId=Job.JobId)"
1589 " Path.Path='" + directory + "'"
1590 " AND Filename.Name='" + fileName + "'"
1591 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1592 " GROUP BY File.FileIndex";
1594 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1595 QStringList results;
1596 if (m_console->sql_cmd(cmd, results)) {
1597 QStringList fieldlist;
1599 /* Iterate through the record returned from the query */
1600 foreach (QString resultline, results) {
1601 /* Iterate through fields in the record */
1603 fieldlist = resultline.split("\t");
1604 foreach (QString field, fieldlist) {
1606 qfileIndex = field.toInt();
1613 } /* if (index != -1) */