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("/");
61 QGridLayout *m_gridLayout = new QGridLayout(this);
62 m_gridLayout->setSpacing(6);
63 m_gridLayout->setMargin(9);
64 m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
66 QSplitter *splitter_2 = new QSplitter(Qt::Vertical, this);
67 QScrollArea *area = new QScrollArea();
68 area->setObjectName(QString::fromUtf8("area"));
69 area->setWidget(widget);
70 area->setWidgetResizable(true);
71 splitter_2->addWidget(splitter);
72 splitter_2->addWidget(area);
74 m_gridLayout->addWidget(splitter_2, 0, 0, 1, 1);
76 /* progress widgets */
77 prBar1->setVisible(false);
78 prBar2->setVisible(false);
79 prLabel1->setVisible(false);
80 prLabel2->setVisible(false);
82 /* Set Defaults for check and spin for limits */
83 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
84 limitSpinBox->setValue(mainWin->m_recordLimitVal);
85 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
86 daysSpinBox->setValue(mainWin->m_daysLimitVal);
89 restoreTree::~restoreTree()
95 * Called from the constructor to set up the page widgets and connections.
97 void restoreTree::setupPage()
99 connect(refreshButton, SIGNAL(pressed()), this, SLOT(refreshButtonPushed()));
100 connect(restoreButton, SIGNAL(pressed()), this, SLOT(restoreButtonPushed()));
101 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobComboChanged(int)));
102 connect(jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
103 connect(clientCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
104 connect(fileSetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRefresh()));
105 connect(limitCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
106 connect(daysCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateRefresh()));
107 connect(daysSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
108 connect(limitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateRefresh()));
109 connect(directoryTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
110 this, SLOT(directoryCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
111 connect(directoryTree, SIGNAL(itemExpanded(QTreeWidgetItem *)),
112 this, SLOT(directoryItemExpanded(QTreeWidgetItem *)));
113 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
114 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
115 connect(fileTable, SIGNAL(currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
116 this, SLOT(fileCurrentItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
118 QStringList titles = QStringList() << "Directories";
119 directoryTree->setHeaderLabels(titles);
120 clientCombo->addItems(m_console->client_list);
121 fileSetCombo->addItem("Any");
122 fileSetCombo->addItems(m_console->fileset_list);
123 jobCombo->addItem("Any");
124 jobCombo->addItems(m_console->job_list);
126 directoryTree->setContextMenuPolicy(Qt::ActionsContextMenu);
129 void restoreTree::updateRefresh()
131 if (mainWin->m_rtPopDirDebug) Pmsg2(000, "testing prev=\"%s\" current=\"%s\"\n", m_prevJobCombo.toUtf8().data(), jobCombo->currentText().toUtf8().data());
132 m_dropdownChanged = (m_prevJobCombo != jobCombo->currentText())
133 || (m_prevClientCombo != clientCombo->currentText())
134 || (m_prevFileSetCombo != fileSetCombo->currentText()
135 || (m_prevLimitSpinBox != limitSpinBox->value())
136 || (m_prevDaysSpinBox != daysSpinBox->value())
137 || (m_prevLimitCheckState != limitCheckBox->checkState())
138 || (m_prevDaysCheckState != daysCheckBox->checkState())
140 if (m_dropdownChanged) {
141 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is CHANGED\n");
142 refreshLabel->setText("Refresh From Re-Select");
144 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "In restoreTree::updateRefresh Is not Changed\n");
145 refreshLabel->setText("Refresh From JobChecks");
150 * When refresh button is pushed, perform a query getting the directories and
151 * use parseDirectory and addDirectory to populate the directory tree with items.
153 void restoreTree::populateDirectoryTree()
157 directoryTree->clear();
159 fileTable->setRowCount(0);
160 fileTable->setColumnCount(0);
161 versionTable->clear();
162 versionTable->setRowCount(0);
163 versionTable->setColumnCount(0);
164 m_fileExceptionHash.clear();
165 m_fileExceptionMulti.clear();
166 m_versionExceptionHash.clear();
167 m_directoryIconStateHash.clear();
169 QString jobComboText = jobCombo->currentText();
170 QString clientComboText = clientCombo->currentText();
171 QString fileSetComboText = fileSetCombo->currentText();
173 int taskcount = 2, ontask = 1;
174 if (m_dropdownChanged) taskcount += 1;
176 /* Set progress bars and repaint */
177 prBar1->setVisible(true);
178 prBar1->setRange(0,taskcount);
180 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
181 prLabel1->setVisible(true);
182 prBar2->setVisible(true);
183 prBar2->setRange(0,0);
184 prLabel2->setText("Querying Database");
185 prLabel2->setVisible(true);
188 if (m_dropdownChanged) {
189 m_prevJobCombo = jobComboText;
190 m_prevClientCombo = clientComboText;
191 m_prevFileSetCombo = fileSetComboText;
192 m_prevLimitSpinBox = limitSpinBox->value();
193 m_prevDaysSpinBox = daysSpinBox->value();
194 m_prevLimitCheckState = limitCheckBox->checkState();
195 m_prevDaysCheckState = daysCheckBox->checkState();
197 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating the Job Table\n");
199 QString condition = " Client.Name='" + clientCombo->itemText(clientCombo->currentIndex()) + "'";
200 if ((jobCombo->currentIndex() >= 0) && (jobComboText != "Any")) {
201 condition.append(" AND Job.name = '" + jobComboText + "'");
203 if ((fileSetCombo->currentIndex() >= 0) && (fileSetComboText != "Any")) {
204 condition.append(" AND FileSet.FileSet='" + fileSetComboText + "'");
206 /* If Limit check box For limit by days is checked */
207 if (daysCheckBox->checkState() == Qt::Checked) {
208 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
209 QString since = stamp.toString(Qt::ISODate);
210 condition.append(" AND Job.Starttime>'" + since + "'");
213 " INNER JOIN Client ON (Job.ClientId=Client.ClientId)"
214 " INNER JOIN FileSet ON (Job.FileSetId=FileSet.FileSetId)"
215 " WHERE" + condition +
216 " AND Job.purgedfiles=0";
219 " From Job" + m_jobQueryPart;
220 /* If Limit check box for limit records returned is checked */
221 if (limitCheckBox->checkState() == Qt::Checked) {
223 limit.setNum(limitSpinBox->value());
224 m_jobQuery += " LIMIT " + limit;
227 if (mainWin->m_sqlDebug) {
228 Pmsg1(000, "Query cmd : %s\n", m_jobQuery.toUtf8().data());
230 prBar1->setValue(ontask++);
231 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
233 prBar2->setRange(0,0);
234 prLabel2->setText("Querying Jobs");
237 setJobsCheckedList();
239 if (mainWin->m_rtPopDirDebug) Pmsg0(000, "Repopulating from checks in Job Table\n");
240 setJobsCheckedList();
244 "SELECT DISTINCT Path.Path AS Path"
246 " INNER JOIN File ON (File.PathId=Path.PathId)"
247 " INNER JOIN Job ON (File.JobId=Job.JobId)"
248 " WHERE Job.Jobid IN (" + m_jobQuery + ")"
250 if (mainWin->m_sqlDebug) {
251 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
253 prBar1->setValue(ontask++);
254 prLabel1->setText("Task " + QString("%1").arg(ontask)+ " of " + QString("%1").arg(taskcount));
256 prLabel2->setText("Processing Directories");
257 QStringList directories;
258 if (m_console->sql_cmd(cmd, directories)) {
259 if (mainWin->m_miscDebug) {
260 Pmsg1(000, "Done with query %i directories\n", directories.count());
262 prBar2->setRange(0,directories.count());
264 foreach(QString directory, directories) {
266 prBar2->setValue(m_debugCnt);
267 parseDirectory(directory);
270 prBar1->setVisible(false);
271 prBar2->setVisible(false);
272 prLabel1->setVisible(false);
273 prLabel2->setVisible(false);
277 * Function to set m_jobQuery from the jobs that are checked in the table
280 void restoreTree::setJobsCheckedList()
282 m_JobsCheckedList = "";
284 /* Update the items in the version table */
285 int cnt = jobTable->rowCount();
286 for (int row=0; row<cnt; row++) {
287 QTableWidgetItem* jobItem = jobTable->item(row, 0);
288 if (jobItem->checkState() == Qt::Checked) {
290 m_JobsCheckedList += ",";
291 m_JobsCheckedList += jobItem->text();
293 jobItem->setBackground(Qt::green);
295 jobItem->setBackground(Qt::gray);
297 m_jobQuery = m_JobsCheckedList;
301 * Function to parse a directory into all possible subdirectories, then add to
304 void restoreTree::parseDirectory(QString &dir_in)
306 /* m_debugTrap is to only print debugs for a few occurances of calling parseDirectory
307 * instead of printing out what could potentially a whole bunch */
310 /* Clean up the directory string remove some funny char after last '/' */
311 QRegExp rgx("[^/]$");
312 int lastslash = rgx.indexIn(dir_in);
313 dir_in.replace(lastslash, dir_in.length()-lastslash, "");
314 if ((mainWin->m_miscDebug) && (m_debugTrap))
315 Pmsg1(000, "parsing %s\n", dir_in.toUtf8().data());
317 /* split and add if not in yet */
318 QString direct, path;
321 QStringList pathAfter, dirAfter;
322 /* start from the end, turn /etc/somedir/subdir/ into /etc/somedir and subdir/
323 * if not added into tree, then try /etc/ and somedir/ if not added, then try
324 * / and etc/ . That should succeed, then add the ones that failed in reverse */
325 while (((index = m_slashregex.lastIndexIn(dir_in, -2)) != -1) && (!done)) {
326 direct = path = dir_in;
327 path.replace(index+1, dir_in.length()-index-1,"");
328 direct.replace(0, index+1, "");
329 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
330 QString msg = QString("length = \"%1\" index = \"%2\" Adding \"%3\" \"%4\"\n")
331 .arg(dir_in.length()).arg(index).arg(path).arg(direct);
332 Pmsg0(000, msg.toUtf8().data());
334 if (addDirectory(path, direct)) done = true;
336 if ((mainWin->m_miscDebug) && (m_debugTrap))
337 Pmsg0(000, "Saving for later\n");
338 pathAfter.prepend(path);
339 dirAfter.prepend(direct);
344 for (int k=0; k<pathAfter.count(); k++) {
345 if (addDirectory(pathAfter[k], dirAfter[k]))
346 if ((mainWin->m_miscDebug) && (m_debugTrap))
347 Pmsg2(000, "Adding After %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
349 if ((mainWin->m_miscDebug) && (m_debugTrap))
350 Pmsg2(000, "Error Adding %s %s\n", pathAfter[k].toUtf8().data(), dirAfter[k].toUtf8().data());
355 * Function called from fill directory when a directory is found to see if this
356 * directory exists in the directory pane and then add it to the directory pane
358 bool restoreTree::addDirectory(QString &m_cwd, QString &newdirr)
360 QString newdir = newdirr;
361 QString fullPath = m_cwd + newdirr;
362 bool ok = true, added = false;
364 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
365 QString msg = QString("In addDirectory cwd \"%1\" newdir \"%2\"\n")
368 Pmsg0(000, msg.toUtf8().data());
372 /* add unix '/' directory first */
373 if (m_dirPaths.empty() && (m_winRegExpPath.indexIn(fullPath, 0) == -1)) {
375 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
377 item->setText(0, text.toUtf8().data());
378 item->setData(0, Qt::UserRole, QVariant(text));
379 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
380 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
381 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
382 Pmsg1(000, "Pre Inserting %s\n", text.toUtf8().data());
384 m_dirPaths.insert(text, item);
386 /* no need to check for windows drive if unix */
387 if (m_winRegExpDrive.indexIn(m_cwd, 0) == 0) {
388 /* this is a windows drive add the base widget */
389 QTreeWidgetItem *item = new QTreeWidgetItem(directoryTree);
390 item->setText(0, m_cwd);
391 item->setData(0, Qt::UserRole, QVariant(fullPath));
392 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
393 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
394 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
395 Pmsg0(000, "Added Base \"letter\":/\n");
397 m_dirPaths.insert(m_cwd, item);
401 /* is it already existent ?? */
402 if (!m_dirPaths.contains(fullPath)) {
403 QTreeWidgetItem *item = NULL;
404 QTreeWidgetItem *parent = m_dirPaths.value(m_cwd);
406 /* new directories to add */
407 item = new QTreeWidgetItem(parent);
408 item->setText(0, newdir.toUtf8().data());
409 item->setData(0, Qt::UserRole, QVariant(fullPath));
410 item->setCheckState(0, Qt::Unchecked);
411 /* Store the current state of the check status in column 1, which at
412 * this point has no text*/
413 item->setData(1, Qt::UserRole, QVariant(Qt::Unchecked));
416 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
417 QString msg = QString("In else of if parent cwd \"%1\" newdir \"%2\"\n")
420 Pmsg0(000, msg.toUtf8().data());
423 /* insert into hash */
425 if ((mainWin->m_miscDebug) && (m_debugTrap)) {
426 Pmsg1(000, "Inserting %s\n", fullPath.toUtf8().data());
428 m_dirPaths.insert(fullPath, item);
436 * Virtual function which is called when this page is visible on the stack
438 void restoreTree::currentStackItem()
441 if (!m_console->preventInUseConnect())
449 * Populate the tree when refresh button pushed.
451 void restoreTree::refreshButtonPushed()
453 populateDirectoryTree();
457 * Set the values of non-job combo boxes to the job defaults
459 void restoreTree::jobComboChanged(int)
461 if (jobCombo->currentText() == "Any") {
462 fileSetCombo->setCurrentIndex(fileSetCombo->findText("Any", Qt::MatchExactly));
465 job_defaults job_defs;
468 job_defs.job_name = jobCombo->currentText();
469 if (m_console->get_job_defaults(job_defs)) {
470 fileSetCombo->setCurrentIndex(fileSetCombo->findText(job_defs.fileset_name, Qt::MatchExactly));
471 clientCombo->setCurrentIndex(clientCombo->findText(job_defs.client_name, Qt::MatchExactly));
476 * Function to populate the file list table
478 void restoreTree::directoryCurrentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *)
483 m_fileCheckStateList.clear();
484 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
485 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
486 QBrush blackBrush(Qt::black);
487 QString directory = item->data(0, Qt::UserRole).toString();
488 directoryLabel->setText("Present Working Directory : " + directory);
490 "SELECT DISTINCT Filename.Name AS FileName"
492 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
493 " INNER JOIN Path ON (Path.PathId=File.PathId)"
494 " INNER JOIN Job ON (File.JobId=Job.JobId)"
495 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
496 " AND Job.Jobid IN (" + m_jobQuery + ")"
497 " ORDER BY FileName";
499 QStringList headerlist = (QStringList() << "File Name");
501 /* Also clear the version table here */
502 versionTable->clear();
503 versionFileLabel->setText("");
504 versionTable->setRowCount(0);
505 versionTable->setColumnCount(0);
506 fileTable->setColumnCount(headerlist.size());
507 fileTable->setHorizontalHeaderLabels(headerlist);
509 if (mainWin->m_sqlDebug) {
510 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
513 if (m_console->sql_cmd(cmd, results)) {
515 QTableWidgetItem* tableItem;
517 QStringList fieldlist;
518 fileTable->setRowCount(results.size());
521 /* Iterate through the record returned from the query */
522 foreach (QString resultline, results) {
523 /* Iterate through fields in the record */
525 fieldlist = resultline.split("\t");
526 foreach (field, fieldlist) {
527 field = field.trimmed(); /* strip leading & trailing spaces */
528 tableItem = new QTableWidgetItem(field, 1);
529 /* Possible flags are Qt::ItemFlags flag = Qt::ItemIsSelectable | Qt::ItemIsEditablex
530 * | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable
531 * | Qt::ItemIsEnabled | Qt::ItemIsTristate; */
532 tableItem->setForeground(blackBrush);
533 /* Just in case a column ever gets added */
535 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
536 tableItem->setFlags(flag);
537 tableItem->setData(Qt::UserRole, QVariant(directory));
538 fileTable->setItem(row, column, tableItem);
539 m_fileCheckStateList.append(Qt::Unchecked);
540 tableItem->setCheckState(Qt::Unchecked);
546 fileTable->setRowCount(row);
548 fileTable->resizeColumnsToContents();
549 fileTable->resizeRowsToContents();
550 fileTable->verticalHeader()->hide();
551 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
552 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
553 if (mainWin->m_rtDirCurICDebug) Pmsg0(000, "will update file table checks\n");
554 updateFileTableChecks();
558 * Function to populate the version table
560 void restoreTree::fileCurrentItemChanged(QTableWidgetItem *fileTableItem, QTableWidgetItem *)
562 if (fileTableItem == NULL)
565 m_versionCheckStateList.clear();
566 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
567 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
569 QString file = fileTableItem->text();
570 versionFileLabel->setText(file);
571 QString directory = fileTableItem->data(Qt::UserRole).toString();
573 QBrush blackBrush(Qt::black);
575 "SELECT Job.JobId AS JobId, Job.Level AS Type, Job.EndTime AS EndTime, File.Md5 AS MD5, File.FileId AS FileId"
577 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
578 " INNER JOIN Path ON (Path.PathId=File.PathId)"
579 " INNER JOIN Job ON (File.JobId=Job.JobId)"
580 " WHERE Filename.Name='" + file + "' AND Path.Path='" + directory + "'"
581 " AND Job.Jobid IN (" + m_jobQuery + ")"
582 " ORDER BY Job.EndTime DESC";
584 QStringList headerlist = (QStringList() << "Job Id" << "Type" << "End Time" << "Md5" << "FileId");
585 versionTable->clear();
586 versionTable->setColumnCount(headerlist.size());
587 versionTable->setHorizontalHeaderLabels(headerlist);
589 if (mainWin->m_sqlDebug) {
590 Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
593 if (m_console->sql_cmd(cmd, results)) {
595 QTableWidgetItem* tableItem;
597 QStringList fieldlist;
598 versionTable->setRowCount(results.size());
601 /* Iterate through the record returned from the query */
602 foreach (QString resultline, results) {
603 fieldlist = resultline.split("\t");
605 /* remove directory */
606 if (fieldlist[0].trimmed() != "") {
607 /* Iterate through fields in the record */
608 foreach (field, fieldlist) {
609 field = field.trimmed(); /* strip leading & trailing spaces */
610 tableItem = new QTableWidgetItem(field, 1);
611 tableItem->setFlags(0);
612 tableItem->setForeground(blackBrush);
613 tableItem->setData(Qt::UserRole, QVariant(directory));
614 versionTable->setItem(row, column, tableItem);
617 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
618 tableItem->setFlags(flag);
619 m_versionCheckStateList.append(Qt::Unchecked);
620 tableItem->setCheckState(Qt::Unchecked);
628 versionTable->resizeColumnsToContents();
629 versionTable->resizeRowsToContents();
630 versionTable->verticalHeader()->hide();
631 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
632 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
633 updateVersionTableChecks();
637 * Save user settings associated with this page
639 void restoreTree::writeSettings()
641 QSettings settings(m_console->m_dir->name(), "bat");
642 settings.beginGroup("RestoreTree");
643 settings.setValue("splitterSizes", splitter->saveState());
648 * Read and restore user settings associated with this page
650 void restoreTree::readSettings()
652 QSettings settings(m_console->m_dir->name(), "bat");
653 settings.beginGroup("RestoreTree");
654 splitter->restoreState(settings.value("splitterSizes").toByteArray());
659 * This is a funcion to accomplish the one thing I struggled to figure out what
660 * was taking so long. It add the icons, but after the tree is made. Seemed to
661 * work fast after changing from svg to png file for graphic.
663 void restoreTree::directoryItemExpanded(QTreeWidgetItem *item)
665 int childCount = item->childCount();
666 for (int i=0; i<childCount; i++) {
667 QTreeWidgetItem *child = item->child(i);
668 if (child->icon(0).isNull())
669 child->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
674 * I wanted a table to show what jobs meet the criterion and are being used to
675 * populate the directory tree and file and version tables.
677 void restoreTree::populateJobTable()
679 QBrush blackBrush(Qt::black);
680 QStringList headerlist = (QStringList() << "Job Id" << "End Time" << "Type");
682 jobTable->setColumnCount(headerlist.size());
683 jobTable->setHorizontalHeaderLabels(headerlist);
685 "SELECT Job.Jobid AS Id, Job.EndTime AS EndTime, Job.Level AS Level"
686 " FROM Job" + m_jobQueryPart +
687 " ORDER BY Job.EndTime DESC";
688 /* If Limit check box for limit records returned is checked */
689 if (limitCheckBox->checkState() == Qt::Checked) {
691 limit.setNum(limitSpinBox->value());
692 jobQuery += " LIMIT " + limit;
694 if (mainWin->m_sqlDebug) {
695 Pmsg1(000, "Query cmd : %s\n", jobQuery.toUtf8().data());
699 if (m_console->sql_cmd(jobQuery, results)) {
701 QTableWidgetItem* tableItem;
703 QStringList fieldlist;
704 jobTable->setRowCount(results.size());
707 /* Iterate through the record returned from the query */
708 foreach (QString resultline, results) {
709 fieldlist = resultline.split("\t");
711 /* remove directory */
712 if (fieldlist[0].trimmed() != "") {
713 /* Iterate through fields in the record */
714 foreach (field, fieldlist) {
715 field = field.trimmed(); /* strip leading & trailing spaces */
716 tableItem = new QTableWidgetItem(field, 1);
717 tableItem->setFlags(0);
718 tableItem->setForeground(blackBrush);
719 jobTable->setItem(row, column, tableItem);
721 Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsTristate;
722 tableItem->setFlags(flag);
723 tableItem->setCheckState(Qt::Checked);
724 tableItem->setBackground(Qt::green);
732 jobTable->resizeColumnsToContents();
733 jobTable->resizeRowsToContents();
734 jobTable->verticalHeader()->hide();
738 * When a directory item is "changed" check the state of the checkable item
739 * to see if it is different than what it was which is stored in Qt::UserRole
740 * of the 2nd column, column 1, of the tree widget.
742 void restoreTree::directoryItemChanged(QTreeWidgetItem *item, int /*column*/)
744 Qt::CheckState prevState = (Qt::CheckState)item->data(1, Qt::UserRole).toInt();
745 Qt::CheckState curState = item->checkState(0);
746 QTreeWidgetItem* parent = item->parent();
747 Qt::CheckState parState;
748 if (parent) parState = parent->checkState(0);
749 else parState = (Qt::CheckState)3;
750 if (mainWin->m_rtDirICDebug) {
751 QString msg = QString("directory item OBJECT has changed prev=%1 cur=%2 par=%3 dir=%4\n")
752 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
753 Pmsg1(000, "%s", msg.toUtf8().data()); }
754 /* I only care when the check state changes */
755 if (prevState == curState) {
756 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning Early\n");
760 if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (parState != Qt::Unchecked)) {
761 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::PartiallyChecked\n");
762 directoryTreeDisconnectedSet(item, Qt::PartiallyChecked);
763 curState = Qt::PartiallyChecked;
765 if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked)) {
766 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Disconnected Setting to Qt::Unchecked\n");
767 directoryTreeDisconnectedSet(item, Qt::Unchecked);
768 curState = Qt::Unchecked;
770 if (mainWin->m_rtDirICDebug) {
771 QString msg = QString("directory item CHECKSTATE has changed prev=%1 cur=%2 par=%3 dir=%4\n")
772 .arg(prevState).arg(curState).arg(parState).arg(item->text(0));
773 Pmsg1(000, "%s", msg.toUtf8().data()); }
775 item->setData(1, Qt::UserRole, QVariant(curState));
776 Qt::CheckState childState = curState;
777 if (childState == Qt::Checked)
778 childState = Qt::PartiallyChecked;
779 setCheckofChildren(item, childState);
781 /* Remove items from the exception lists. The multi exception list is my index
782 * of what exceptions can be removed when the directory is known*/
783 QString directory = item->data(0, Qt::UserRole).toString();
784 QStringList fullPathList = m_fileExceptionMulti.values(directory);
785 int fullPathListCount = fullPathList.count();
786 if ((mainWin->m_rtDirICDebug) && fullPathListCount) Pmsg2(000, "Will attempt to remove file exceptions for %s count %i\n", directory.toUtf8().data(), fullPathListCount);
787 foreach (QString fullPath, fullPathList) {
788 /* If there is no value in the hash for the key fullPath a value of 3 will be returned
789 * which will match no Qt::xxx values */
790 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
791 if (mainWin->m_rtDirICDebug) Pmsg2(000, "hashState=%i childState=%i\n", hashState, childState);
792 if (hashState == Qt::Unchecked) {
793 fileExceptionRemove(fullPath, directory);
794 m_versionExceptionHash.remove(fullPath);
795 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal A\n");
797 if (hashState == Qt::Checked) {
798 fileExceptionRemove(fullPath, directory);
799 m_versionExceptionHash.remove(fullPath);
800 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Attempted Removal B\n");
804 if (item == directoryTree->currentItem()) {
805 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Will attempt to update File Table Checks\n");
806 updateFileTableChecks();
807 versionTable->clear();
808 versionTable->setRowCount(0);
809 versionTable->setColumnCount(0);
811 if (mainWin->m_rtDirICDebug) Pmsg0(000, "Returning At End\n");
815 * When a directory item check state is changed, this function iterates through
816 * all subdirectories and sets all to the passed state, which is either partially
817 * checked or unchecked.
819 void restoreTree::setCheckofChildren(QTreeWidgetItem *item, Qt::CheckState state)
822 childCount = item->childCount();
823 for (int i=0; i<childCount; i++) {
824 QTreeWidgetItem *child = item->child(i);
825 child->setData(1, Qt::UserRole, QVariant(state));
826 child->setCheckState(0, state);
827 setCheckofChildren(child, state);
832 * When a File Table Item is "changed" check to see if the state of the checkable
833 * item has changed which is stored in m_fileCheckStateList
834 * If changed store in a hash m_fileExceptionHash that whether this file should be
836 * Called as a slot, connected after populated (after directory current changed called)
838 void restoreTree::fileTableItemChanged(QTableWidgetItem *item)
840 /* get the previous and current check states */
841 int row = fileTable->row(item);
842 Qt::CheckState prevState;
843 /* prevent a segfault */
844 prevState = m_fileCheckStateList[row];
845 Qt::CheckState curState = item->checkState();
847 /* deterimine the default state from the state of the directory */
848 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
849 Qt::CheckState dirState = (Qt::CheckState)dirTreeItem->data(1, Qt::UserRole).toInt();
850 Qt::CheckState defState = Qt::PartiallyChecked;
851 if (dirState == Qt::Unchecked) defState = Qt::Unchecked;
853 /* determine if it is already in the m_fileExceptionHash */
854 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
855 QString file = item->text();
856 QString fullPath = directory + file;
857 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
858 int verJobNum = m_versionExceptionHash.value(fullPath, 0);
860 if (mainWin->m_rtFileTabICDebug) {
861 QString msg = QString("filerow=%1 prev=%2 cur=%3 def=%4 hash=%5 dir=%6 verJobNum=%7\n")
862 .arg(row).arg(prevState).arg(curState).arg(defState).arg(hashState).arg(dirState).arg(verJobNum);
863 Pmsg1(000, "%s", msg.toUtf8().data()); }
865 /* Remove the hash if currently checked previously unchecked and directory is checked or partial */
866 if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (dirState == Qt::Unchecked)) {
867 /* it can behave as defaulted so current of unchecked is fine */
868 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
869 fileExceptionRemove(fullPath, directory);
870 m_versionExceptionHash.remove(fullPath);
871 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
872 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionInsert here\n");
873 fileExceptionInsert(fullPath, directory, Qt::Unchecked);
874 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0) && (defState == Qt::PartiallyChecked)) {
875 /* filerow=2 prev=0 cur=2 def=1 hash=0 dir=2 verJobNum=0 */
876 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove here\n");
877 fileExceptionRemove(fullPath, directory);
878 } else if ((prevState == Qt::Checked) && (curState == Qt::Unchecked) && (defState == Qt::PartiallyChecked) && (verJobNum != 0) && (hashState == Qt::Checked)) {
879 /* Check dir, check version, attempt uncheck in file
880 * filerow=4 prev=2 cur=0 def=1 hash=2 dir=2 verJobNum=53 */
881 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will fileExceptionRemove and m_versionExceptionHash.remove here\n");
882 fileExceptionRemove(fullPath, directory);
883 m_versionExceptionHash.remove(fullPath);
884 } else if ((prevState == Qt::Unchecked) && (curState == Qt::Checked) && (dirState != Qt::Unchecked) && (verJobNum == 0)) {
885 /* filerow=0 prev=0 cur=2 def=1 hash=0 dirState=2 verJobNum */
886 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, "Will Not remove here\n");
887 } else if (prevState != curState) {
888 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " THE STATE OF THE Check has changed, Setting StateList[%i] to %i\n", row, curState);
889 /* A user did not set the check state to Partially checked, ignore if so */
890 if (curState != Qt::PartiallyChecked) {
891 if ((defState == Qt::Unchecked) && (prevState == Qt::PartiallyChecked) && (curState == Qt::Unchecked)) {
892 if (mainWin->m_rtFileTabICDebug) Pmsg0(000, " got here\n");
894 if (mainWin->m_rtFileTabICDebug) Pmsg2(000, " Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
895 fileExceptionInsert(fullPath, directory, curState);
898 if (mainWin->m_rtFileTabICDebug) Pmsg1(000, "Removing version hash for %s\n", fullPath.toUtf8().data());
899 /* programattically been changed back to a default state of Qt::PartiallyChecked remove the version hash here */
900 m_versionExceptionHash.remove(fullPath);
904 updateFileTableChecks();
905 updateVersionTableChecks();
909 * function to insert keys and values to both m_fileExceptionHash and m_fileExceptionMulti
911 void restoreTree::fileExceptionInsert(QString &fullPath, QString &direcotry, Qt::CheckState state)
913 m_fileExceptionHash.insert(fullPath, state);
914 m_fileExceptionMulti.insert(direcotry, fullPath);
915 directoryIconStateInsert(fullPath, state);
919 * function to remove keys from both m_fileExceptionHash and m_fileExceptionMulti
921 void restoreTree::fileExceptionRemove(QString &fullPath, QString &directory)
923 m_fileExceptionHash.remove(fullPath);
924 /* pull the list of values in the multi */
925 QStringList fullPathList = m_fileExceptionMulti.values(directory);
926 /* get the index of the fullpath to remove */
927 int index = fullPathList.indexOf(fullPath);
929 /* remove the desired item in the list */
930 fullPathList.removeAt(index);
931 /* remove the entire list from the multi */
932 m_fileExceptionMulti.remove(directory);
933 /* readd the remaining */
934 foreach (QString fp, fullPathList) {
935 m_fileExceptionMulti.insert(directory, fp);
938 directoryIconStateRemove();
942 * Overloaded function to be called from the slot and from other places to set the state
943 * of the check marks in the version table
945 void restoreTree::versionTableItemChanged(QTableWidgetItem *item)
947 /* get the previous and current check states */
948 int row = versionTable->row(item);
949 QTableWidgetItem *colZeroItem = versionTable->item(row, 0);
950 Qt::CheckState prevState = m_versionCheckStateList[row];
951 Qt::CheckState curState = (Qt::CheckState)colZeroItem->checkState();
952 m_versionCheckStateList[row] = curState;
954 /* deterimine the default state from the state of the file */
955 QTableWidgetItem *fileTableItem = fileTable->currentItem();
956 Qt::CheckState fileState = (Qt::CheckState)fileTableItem->checkState();
958 /* determine the default state */
959 Qt::CheckState defState;
961 defState = Qt::PartiallyChecked;
962 if (fileState == Qt::Unchecked)
963 defState = Qt::Unchecked;
966 defState = Qt::Unchecked;
968 /* determine if it is already in the versionExceptionHash */
969 QString directory = directoryTree->currentItem()->data(0, Qt::UserRole).toString();
970 Qt::CheckState dirState = directoryTree->currentItem()->checkState(0);
971 QString file = fileTableItem->text();
972 QString fullPath = directory + file;
973 int thisJobNum = colZeroItem->text().toInt();
974 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
976 if (mainWin->m_rtVerTabICDebug) {
977 QString msg = QString("versrow=%1 prev=%2 cur=%3 def=%4 dir=%5 hashJobNum=%6 thisJobNum=%7 filestate=%8 fec=%9 vec=%10\n")
978 .arg(row).arg(prevState).arg(curState).arg(defState).arg(dirState).arg(hashJobNum).arg(thisJobNum).arg(fileState)
979 .arg(m_fileExceptionHash.count()).arg(m_versionExceptionHash.count());
980 Pmsg1(000, "%s", msg.toUtf8().data()); }
981 /* if changed from partially checked to checked, make it unchecked */
982 if ((curState == Qt::Checked) && (row == 0) && (fileState == Qt::Unchecked)) {
983 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "Setting to Qt::Checked\n");
984 fileTableItem->setCheckState(Qt::Checked);
985 } else if ((prevState == Qt::PartiallyChecked) && (curState == Qt::Checked) && (row == 0) && (fileState == Qt::Checked) && (dirState == Qt::Unchecked)) {
986 //versrow=0 prev=1 cur=2 def=1 dir=0 hashJobNum=0 thisJobNum=64 filestate=2 fec=1 vec=0
987 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "fileExceptionRemove %s, %i\n", fullPath.toUtf8().data());
988 fileExceptionRemove(fullPath, directory);
989 } else if ((curState == Qt::Checked) && (row == 0) && (hashJobNum != 0) && (dirState != Qt::Unchecked)) {
990 //versrow=0 prev=0 cur=2 def=1 dir=2 hashJobNum=53 thisJobNum=64 filestate=2 fec=1 vec=1
991 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
992 m_versionExceptionHash.remove(fullPath);
993 fileExceptionRemove(fullPath, directory);
994 } else if ((curState == Qt::Checked) && (row == 0)) {
995 if (mainWin->m_rtVerTabICDebug) Pmsg1(000, "m_versionExceptionHash.remove %s\n", fullPath.toUtf8().data());
996 m_versionExceptionHash.remove(fullPath);
997 } else if (prevState != curState) {
998 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, " THE STATE OF THE version Check has changed, Setting StateList[%i] to %i\n", row, curState);
999 if ((curState == Qt::Checked) || (curState == Qt::PartiallyChecked) && (row != 0)) {
1000 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_versionExceptionHash %s, %i\n", fullPath.toUtf8().data(), thisJobNum);
1001 m_versionExceptionHash.insert(fullPath, thisJobNum);
1002 if (fileState != Qt::Checked) {
1003 if (mainWin->m_rtVerTabICDebug) Pmsg2(000, "Inserting into m_fileExceptionHash %s, %i\n", fullPath.toUtf8().data(), curState);
1004 fileExceptionInsert(fullPath, directory, curState);
1007 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "got here\n");
1010 if (mainWin->m_rtVerTabICDebug) Pmsg0(000, "no conditions met\n");
1013 updateFileTableChecks();
1014 updateVersionTableChecks();
1018 * Simple function to set the check state in the file table by disconnecting the
1019 * signal/slot the setting then reconnecting the signal/slot
1021 void restoreTree::fileTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state, bool color)
1023 disconnect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1024 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1025 item->setCheckState(state);
1026 if (color) item->setBackground(Qt::yellow);
1027 else item->setBackground(Qt::white);
1028 connect(fileTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1029 this, SLOT(fileTableItemChanged(QTableWidgetItem *)));
1033 * Simple function to set the check state in the version table by disconnecting the
1034 * signal/slot the setting then reconnecting the signal/slot
1036 void restoreTree::versionTableDisconnectedSet(QTableWidgetItem *item, Qt::CheckState state)
1038 disconnect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1039 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1040 item->setCheckState(state);
1041 connect(versionTable, SIGNAL(itemChanged(QTableWidgetItem *)),
1042 this, SLOT(versionTableItemChanged(QTableWidgetItem *)));
1046 * Simple function to set the check state in the directory tree by disconnecting the
1047 * signal/slot the setting then reconnecting the signal/slot
1049 void restoreTree::directoryTreeDisconnectedSet(QTreeWidgetItem *item, Qt::CheckState state)
1051 disconnect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1052 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1053 item->setCheckState(0, state);
1054 connect(directoryTree, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
1055 this, SLOT(directoryItemChanged(QTreeWidgetItem *, int)));
1059 * Simplify the updating of the check state in the File table by iterating through
1060 * each item in the file table to determine it's appropriate state.
1061 * !! Will probably want to concoct a way to do this without iterating for the possibility
1062 * of the very large directories.
1064 void restoreTree::updateFileTableChecks()
1066 /* deterimine the default state from the state of the directory */
1067 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1068 Qt::CheckState dirState = dirTreeItem->checkState(0);
1070 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1072 /* Update the items in the version table */
1073 int rcnt = fileTable->rowCount();
1074 for (int row=0; row<rcnt; row++) {
1075 QTableWidgetItem* item = fileTable->item(row, 0);
1077 Qt::CheckState curState = item->checkState();
1078 Qt::CheckState newState = Qt::PartiallyChecked;
1079 if (dirState == Qt::Unchecked) newState = Qt::Unchecked;
1081 /* determine if it is already in the m_fileExceptionHash */
1082 QString file = item->text();
1083 QString fullPath = dirName + file;
1084 Qt::CheckState hashState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1085 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1087 if (hashState != 3) newState = hashState;
1089 if (mainWin->m_rtUpdateFTDebug) {
1090 QString msg = QString("file row=%1 cur=%2 hash=%3 new=%4 dirState=%5\n")
1091 .arg(row).arg(curState).arg(hashState).arg(newState).arg(dirState);
1092 Pmsg1(000, "%s", msg.toUtf8().data());
1095 bool docolor = false;
1096 if (hashJobNum != 0) docolor = true;
1097 bool isyellow = item->background().color() == QColor(Qt::yellow);
1098 if ((newState != curState) || (hashState == 3) || ((isyellow && !docolor) || (!isyellow && docolor)))
1099 fileTableDisconnectedSet(item, newState, docolor);
1100 m_fileCheckStateList[row] = newState;
1105 * Simplify the updating of the check state in the Version table by iterating through
1106 * each item in the file table to determine it's appropriate state.
1108 void restoreTree::updateVersionTableChecks()
1110 /* deterimine the default state from the state of the directory */
1111 QTreeWidgetItem *dirTreeItem = directoryTree->currentItem();
1112 Qt::CheckState dirState = dirTreeItem->checkState(0);
1113 QString dirName = dirTreeItem->data(0, Qt::UserRole).toString();
1115 /* deterimine the default state from the state of the file */
1116 QTableWidgetItem *fileTableItem = fileTable->item(fileTable->currentRow(), 0);
1117 Qt::CheckState fileState = fileTableItem->checkState();
1118 QString file = fileTableItem->text();
1119 QString fullPath = dirName + file;
1120 int hashJobNum = m_versionExceptionHash.value(fullPath, 0);
1122 /* Update the items in the version table */
1123 int cnt = versionTable->rowCount();
1124 for (int row=0; row<cnt; row++) {
1125 QTableWidgetItem* item = versionTable->item(row, 0);
1127 Qt::CheckState curState = item->checkState();
1128 Qt::CheckState newState = Qt::Unchecked;
1130 if ((row == 0) && (fileState != Qt::Unchecked) && (hashJobNum == 0))
1131 newState = Qt::PartiallyChecked;
1132 /* determine if it is already in the versionExceptionHash */
1134 int thisJobNum = item->text().toInt();
1135 if (thisJobNum == hashJobNum)
1136 newState = Qt::Checked;
1138 if (mainWin->m_rtChecksDebug) {
1139 QString msg = QString("ver row=%1 cur=%2 hashJobNum=%3 new=%4 dirState=%5\n")
1140 .arg(row).arg(curState).arg(hashJobNum).arg(newState).arg(dirState);
1141 Pmsg1(000, "%s", msg.toUtf8().data());
1143 if (newState != curState)
1144 versionTableDisconnectedSet(item, newState);
1145 m_versionCheckStateList[row] = newState;
1150 * Quick subroutine to "return via subPaths" a list of subpaths when passed a fullPath
1152 void restoreTree::fullPathtoSubPaths(QStringList &subPaths, QString &fullPath_in)
1156 QString fullPath = fullPath_in;
1157 QString direct, path;
1158 while (((index = m_slashregex.lastIndexIn(fullPath, -2)) != -1) && (!done)) {
1159 direct = path = fullPath;
1160 path.replace(index+1, fullPath.length()-index-1, "");
1161 direct.replace(0, index+1, "");
1163 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1164 .arg(fullPath.length()).arg(index).arg(path).arg(direct);
1165 Pmsg0(000, msg.toUtf8().data());
1168 subPaths.append(fullPath);
1173 * A Function to set the icon state and insert a record into
1174 * m_directoryIconStateHash when an exception is added by the user
1176 void restoreTree::directoryIconStateInsert(QString &fullPath, Qt::CheckState excpState)
1179 fullPathtoSubPaths(paths, fullPath);
1180 /* an exception that causes the item in the file table to be "Checked" has occured */
1181 if (excpState == Qt::Checked) {
1182 bool foundAsUnChecked = false;
1183 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1185 if (firstItem->checkState(0) == Qt::Unchecked)
1186 foundAsUnChecked = true;
1188 if (foundAsUnChecked) {
1189 /* as long as directory item is Unchecked, set icon state to "green check" */
1191 QListIterator<QString> siter(paths);
1192 while (siter.hasNext() && !done) {
1193 QString path = siter.next();
1194 QTreeWidgetItem *item = m_dirPaths.value(path);
1196 if (item->checkState(0) != Qt::Unchecked)
1199 directorySetIcon(1, FolderGreenChecked, path, item);
1200 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1205 /* if it is partially checked or fully checked insert green Check until a unchecked is found in the path */
1206 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert Aqua %s\n", paths[0].toUtf8().data());
1208 QListIterator<QString> siter(paths);
1209 while (siter.hasNext() && !done) {
1210 QString path = siter.next();
1211 QTreeWidgetItem *item = m_dirPaths.value(path);
1212 if (item) { /* if the directory item is checked, set icon state to unchecked "green check" */
1213 if (item->checkState(0) == Qt::Checked)
1215 directorySetIcon(1, FolderGreenChecked, path, item);
1216 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1221 /* an exception that causes the item in the file table to be "Unchecked" has occured */
1222 if (excpState == Qt::Unchecked) {
1224 QListIterator<QString> siter(paths);
1225 while (siter.hasNext() && !done) {
1226 QString path = siter.next();
1227 QTreeWidgetItem *item = m_dirPaths.value(path);
1228 if (item) { /* if the directory item is checked, set icon state to unchecked "white check" */
1229 if (item->checkState(0) == Qt::Checked)
1231 directorySetIcon(1, FolderWhiteChecked, path, item);
1232 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert boogie %s\n", path.toUtf8().data());
1239 * A function to set the icon state back to "folder" and to remove a record from
1240 * m_directoryIconStateHash when an exception is removed by a user.
1242 void restoreTree::directoryIconStateRemove()
1244 QHash<QString, int> shouldBeIconStateHash;
1245 /* First determine all paths with icons that should be checked with m_fileExceptionHash */
1246 /* Use iterator tera to iterate through m_fileExceptionHash */
1247 QHashIterator<QString, Qt::CheckState> tera(m_fileExceptionHash);
1248 while (tera.hasNext()) {
1250 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Alpha Key %s value %i\n", tera.key().toUtf8().data(), tera.value());
1252 QString keyPath = tera.key();
1253 Qt::CheckState state = tera.value();
1256 fullPathtoSubPaths(paths, keyPath);
1257 /* if the state of the item in m_fileExceptionHash is checked
1258 * each of the subpaths should be "Checked Green" */
1259 if (state == Qt::Checked) {
1261 bool foundAsUnChecked = false;
1262 QTreeWidgetItem *firstItem = m_dirPaths.value(paths[0]);
1264 if (firstItem->checkState(0) == Qt::Unchecked)
1265 foundAsUnChecked = true;
1267 if (foundAsUnChecked) {
1268 /* The right most directory is Unchecked, iterate leftwards
1269 * as long as directory item is Unchecked, set icon state to "green check" */
1271 QListIterator<QString> siter(paths);
1272 while (siter.hasNext() && !done) {
1273 QString path = siter.next();
1274 QTreeWidgetItem *item = m_dirPaths.value(path);
1276 if (item->checkState(0) != Qt::Unchecked)
1279 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1280 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "In restoreTree::directoryIconStateInsert inserting %s\n", path.toUtf8().data());
1286 /* The right most directory is Unchecked, iterate leftwards
1287 * until directory item is Checked, set icon state to "green check" */
1289 QListIterator<QString> siter(paths);
1290 while (siter.hasNext() && !done) {
1291 QString path = siter.next();
1292 QTreeWidgetItem *item = m_dirPaths.value(path);
1294 if (item->checkState(0) == Qt::Checked)
1296 shouldBeIconStateHash.insert(path, FolderGreenChecked);
1301 /* if the state of the item in m_fileExceptionHash is UNChecked
1302 * each of the subpaths should be "Checked white" until the tree item
1303 * which represents that path is Qt::Checked */
1304 if (state == Qt::Unchecked) {
1306 QListIterator<QString> siter(paths);
1307 while (siter.hasNext() && !done) {
1308 QString path = siter.next();
1309 QTreeWidgetItem *item = m_dirPaths.value(path);
1311 if (item->checkState(0) == Qt::Checked)
1313 shouldBeIconStateHash.insert(path, FolderWhiteChecked);
1318 /* now iterate through m_directoryIconStateHash which are the items that are checked
1319 * and remove all of those that are not in shouldBeIconStateHash */
1320 QHashIterator<QString, int> iter(m_directoryIconStateHash);
1321 while (iter.hasNext()) {
1323 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Beta Key %s value %i\n", iter.key().toUtf8().data(), iter.value());
1325 QString keyPath = iter.key();
1326 if (shouldBeIconStateHash.value(keyPath)) {
1327 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "WAS found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1328 //newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1329 int newval = shouldBeIconStateHash.value(keyPath);
1331 newval = newval & FolderBothChecked;
1332 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1334 directorySetIcon(0, newval, keyPath, item);
1336 if (mainWin->m_rtIconStateDebug) Pmsg1(000, "NOT found in shouldBeStateHash %s\n", keyPath.toUtf8().data());
1337 QTreeWidgetItem *item = m_dirPaths.value(keyPath);
1339 directorySetIcon(0, FolderBothChecked, keyPath, item);
1340 //item->setIcon(0,QIcon(QString::fromUtf8(":images/folder.png")));
1341 //m_directoryIconStateHash.remove(keyPath);
1346 void restoreTree::directorySetIcon(int operation, int change, QString &path, QTreeWidgetItem* item) {
1348 /* we are adding a check type white or green */
1349 if (operation > 0) {
1350 /* get the old val and "bitwise OR" with the change */
1351 newval = m_directoryIconStateHash.value(path, FolderUnchecked) | change;
1352 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1353 m_directoryIconStateHash.insert(path, newval);
1355 /* we are removing a check type white or green */
1356 newval = m_directoryIconStateHash.value(path, FolderUnchecked) & (~change);
1358 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Removing from m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1359 m_directoryIconStateHash.remove(path);
1362 if (mainWin->m_rtIconStateDebug) Pmsg2(000, "Inserting into m_directoryIconStateHash path=%s newval=%i\n", path.toUtf8().data(), newval);
1363 m_directoryIconStateHash.insert(path, newval);
1366 if (newval == FolderUnchecked)
1367 item->setIcon(0, QIcon(QString::fromUtf8(":images/folder.png")));
1368 else if (newval == FolderGreenChecked)
1369 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderchecked.png")));
1370 else if (newval == FolderWhiteChecked)
1371 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderunchecked.png")));
1372 else if (newval == FolderBothChecked)
1373 item->setIcon(0, QIcon(QString::fromUtf8(":images/folderbothchecked.png")));
1379 void restoreTree::restoreButtonPushed()
1381 /* Set progress bars and repaint */
1382 prLabel1->setVisible(true);
1383 prLabel1->setText("Task 1 of 3");
1384 prLabel2->setVisible(true);
1385 prLabel2->setText("Processing Checked directories");
1386 prBar1->setVisible(true);
1387 prBar1->setRange(0, 3);
1388 prBar1->setValue(0);
1389 prBar2->setVisible(true);
1390 prBar2->setRange(0, 0);
1392 QMultiHash<int, QString> versionFilesMulti;
1394 QHash <QString, bool> fullPathDone;
1395 QHash <QString, int> fileIndexHash;
1396 if ((mainWin->m_rtRestore1Debug) || (mainWin->m_rtRestore2Debug) || (mainWin->m_rtRestore3Debug))
1397 Pmsg0(000, "In restoreTree::restoreButtonPushed\n");
1398 /* Use a tree widget item iterator to count directories for the progress bar */
1399 QTreeWidgetItemIterator diterc(directoryTree, QTreeWidgetItemIterator::Checked);
1404 } /* while (*diterc) */
1405 prBar2->setRange(0, ditcount);
1406 prBar2->setValue(0);
1408 /* Use a tree widget item iterator filtering for Checked Items */
1409 QTreeWidgetItemIterator diter(directoryTree, QTreeWidgetItemIterator::Checked);
1411 QString directory = (*diter)->data(0, Qt::UserRole).toString();
1412 if (mainWin->m_rtRestore1Debug)
1413 Pmsg1(000, "Directory Checked=\"%s\"\n", directory.toUtf8().data());
1414 /* With a checked directory, query for the files in the directory */
1417 "SELECT t1.Filename AS Filename, t1.JobId AS JobId, File.FileIndex AS FileIndex"
1419 " ( SELECT Filename.Name AS Filename, MAX(Job.JobId) AS JobId"
1421 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1422 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1423 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1424 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1425 " AND Job.Jobid IN (" + m_jobQuery + ")"
1426 " GROUP BY Filename.Name"
1428 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1429 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1430 " INNER JOIN Job ON (Job.JobId=File.JobId)"
1432 " Path.Path='" + directory + "'"
1433 " AND Filename.Name=t1.Filename"
1434 " AND Job.Jobid=t1.JobId"
1435 " ORDER BY Filename";
1437 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1438 QStringList results;
1439 if (m_console->sql_cmd(cmd, results)) {
1440 QStringList fieldlist;
1443 /* Iterate through the record returned from the query */
1444 foreach (QString resultline, results) {
1445 /* Iterate through fields in the record */
1447 QString fullPath = "";
1448 Qt::CheckState fileExcpState = (Qt::CheckState)4;
1449 fieldlist = resultline.split("\t");
1452 foreach (QString field, fieldlist) {
1454 fullPath = directory + field;
1457 version = field.toInt();
1460 fileIndex = field.toInt();
1464 fileExcpState = m_fileExceptionHash.value(fullPath, (Qt::CheckState)3);
1466 int excpVersion = m_versionExceptionHash.value(fullPath, 0);
1467 if (fileExcpState != Qt::Unchecked) {
1469 if (excpVersion != 0) {
1470 debugtext = QString("*E* version=%1").arg(excpVersion);
1471 version = excpVersion;
1472 fileIndex = queryFileIndex(fullPath, excpVersion);
1474 debugtext = QString("___ version=%1").arg(version);
1475 if (mainWin->m_rtRestore1Debug)
1476 Pmsg2(000, "Restoring %s File %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1477 fullPathDone.insert(fullPath, 1);
1478 fileIndexHash.insert(fullPath, fileIndex);
1479 versionFilesMulti.insert(version, fullPath);
1486 prBar2->setValue(ditcount);
1488 } /* while (*diter) */
1489 prBar1->setValue(1);
1490 prLabel1->setText("Task 2 of 3");
1491 prLabel2->setText("Processing Exceptions");
1492 prBar2->setRange(0, 0);
1495 /* There may be some exceptions not accounted for yet with fullPathDone */
1496 QHashIterator<QString, Qt::CheckState> ftera(m_fileExceptionHash);
1497 while (ftera.hasNext()) {
1499 QString fullPath = ftera.key();
1500 Qt::CheckState state = ftera.value();
1502 /* now we don't want the ones already done */
1503 if (fullPathDone.value(fullPath, 0) == 0) {
1504 int version = m_versionExceptionHash.value(fullPath, 0);
1506 QString debugtext = "";
1508 fileIndex = queryFileIndex(fullPath, version);
1509 debugtext = QString("E1* version=%1 fileid=%2").arg(version).arg(fileIndex);
1511 version = mostRecentVersionfromFullPath(fullPath);
1513 fileIndex = queryFileIndex(fullPath, version);
1514 debugtext = QString("E2* version=%1 fileid=%2").arg(version).arg(fileIndex);
1516 debugtext = QString("Error det vers").arg(version);
1518 if (mainWin->m_rtRestore1Debug)
1519 Pmsg2(000, "Restoring %s file %s\n", debugtext.toUtf8().data(), fullPath.toUtf8().data());
1520 versionFilesMulti.insert(version, fullPath);
1522 fileIndexHash.insert(fullPath, fileIndex);
1523 } /* if fullPathDone.value(fullPath, 0) == 0 */
1524 } /* if state != 0 */
1525 } /* while ftera.hasNext */
1526 /* The progress bars for the next step */
1527 prBar1->setValue(2);
1528 prLabel1->setText("Task 3 of 3");
1529 prLabel2->setText("Filling Database Table");
1530 prBar2->setRange(0, vFMCounter);
1532 prBar2->setValue(vFMCounter);
1535 /* now for the final spit out of the versions and lists of files for each version */
1536 QHash<int, int> doneKeys;
1537 QHashIterator<int, QString> vFMiter(versionFilesMulti);
1538 QString tempTable = "";
1540 while (vFMiter.hasNext()) {
1542 int fversion = vFMiter.key();
1543 /* did not succeed in getting an iterator to work as expected on versionFilesMulti so use doneKeys */
1544 if (doneKeys.value(fversion, 0) == 0) {
1545 if (tempTable == "") {
1546 QSettings settings("www.bacula.org", "bat");
1547 settings.beginGroup("Restore");
1548 int counter = settings.value("Counter", 1).toInt();
1549 settings.setValue("Counter", counter+1);
1550 settings.endGroup();
1551 tempTable = "restore_" + QString("%1").arg(qrand()) + "_" + QString("%1").arg(counter);
1552 QString sqlcmd = "CREATE TEMPORARY TABLE " + tempTable + " (JobId INTEGER, FileIndex INTEGER)";
1553 if (mainWin->m_sqlDebug)
1554 Pmsg1(000, "Query cmd : %s ;\n", sqlcmd.toUtf8().data());
1555 QStringList results;
1556 if (!m_console->sql_cmd(sqlcmd, results))
1557 Pmsg1(000, "CREATE TABLE FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1560 if (mainWin->m_rtRestore2Debug) Pmsg1(000, "Version->%i\n", fversion);
1561 QStringList fullPathList = versionFilesMulti.values(fversion);
1562 /* create the command to perform the restore */
1563 foreach(QString ffullPath, fullPathList) {
1564 int fileIndex = fileIndexHash.value(ffullPath);
1565 if (mainWin->m_rtRestore2Debug) Pmsg2(000, " file->%s id %i\n", ffullPath.toUtf8().data(), fileIndex);
1566 QString sqlcmd = "INSERT INTO " + tempTable + " (JobId, FileIndex) VALUES (" + QString("%1").arg(fversion) + ", " + QString("%1").arg(fileIndex) + ")";
1567 if (mainWin->m_rtRestore3Debug)
1568 Pmsg1(000, "Insert cmd : %s\n", sqlcmd.toUtf8().data());
1569 QStringList results;
1570 if (!m_console->sql_cmd(sqlcmd, results))
1571 Pmsg1(000, "INSERT INTO FAILED!!!! %s\n", sqlcmd.toUtf8().data());
1572 prBar2->setValue(++vFMCounter);
1573 } /* foreach fullPathList */
1574 doneKeys.insert(fversion,1);
1575 jobList.append(fversion);
1576 } /* if (doneKeys.value(fversion, 0) == 0) */
1577 } /* while (vFMiter.hasNext()) */
1578 if (tempTable != "") {
1579 /* a table was made, lets run the job */
1580 QString jobOption = " jobid=\"";
1582 /* create a list of jobs comma separated */
1583 foreach (int job, jobList) {
1584 if (first) first = false;
1585 else jobOption += ",";
1586 jobOption += QString("%1").arg(job);
1589 QString cmd = QString("restore");
1591 " file=\"?" + tempTable + "\" done";
1592 if (mainWin->m_commandDebug)
1593 Pmsg1(000, "preRestore command \'%s\'\n", cmd.toUtf8().data());
1594 consoleCommand(cmd);
1596 /* turn off the progress widgets */
1597 prBar1->setVisible(false);
1598 prBar2->setVisible(false);
1599 prLabel1->setVisible(false);
1600 prLabel2->setVisible(false);
1603 int restoreTree::mostRecentVersionfromFullPath(QString &fullPath)
1606 QString directory, fileName;
1607 int index = m_slashregex.lastIndexIn(fullPath, -2);
1609 directory = fileName = fullPath;
1610 directory.replace(index+1, fullPath.length()-index-1, "");
1611 fileName.replace(0, index+1, "");
1613 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1614 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1615 Pmsg0(000, msg.toUtf8().data());
1617 /* so now we need the latest version from the database */
1619 "SELECT MAX(Job.JobId)"
1621 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1622 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1623 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1624 " WHERE Path.Path='" + directory + "' AND Filename.Name!=''"
1625 " AND Job.Jobid IN (" + m_jobQuery + ")"
1626 " AND Filename.Name='" + fileName + "'"
1627 " GROUP BY Filename.Name";
1629 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1630 QStringList results;
1631 if (m_console->sql_cmd(cmd, results)) {
1632 QStringList fieldlist;
1634 /* Iterate through the record returned from the query */
1635 foreach (QString resultline, results) {
1636 /* Iterate through fields in the record */
1638 fieldlist = resultline.split("\t");
1639 foreach (QString field, fieldlist) {
1641 qversion = field.toInt();
1648 } /* if (index != -1) */
1653 int restoreTree::queryFileIndex(QString &fullPath, int jobId)
1656 QString directory, fileName;
1657 int index = m_slashregex.lastIndexIn(fullPath, -2);
1659 directory = fileName = fullPath;
1660 directory.replace(index+1, fullPath.length()-index-1, "");
1661 fileName.replace(0, index+1, "");
1663 QString msg = QString("length = \"%1\" index = \"%2\" Considering \"%3\" \"%4\"\n")
1664 .arg(fullPath.length()).arg(index).arg(fileName).arg(directory);
1665 Pmsg0(000, msg.toUtf8().data());
1667 /* so now we need the latest version from the database */
1672 " INNER JOIN Filename on (Filename.FilenameId=File.FilenameId)"
1673 " INNER JOIN Path ON (Path.PathId=File.PathId)"
1674 " INNER JOIN Job ON (File.JobId=Job.JobId)"
1676 " Path.Path='" + directory + "'"
1677 " AND Filename.Name='" + fileName + "'"
1678 " AND Job.Jobid='" + QString("%1").arg(jobId) + "'"
1679 " GROUP BY File.FileIndex";
1681 if (mainWin->m_sqlDebug) Pmsg1(000, "Query cmd : %s\n", cmd.toUtf8().data());
1682 QStringList results;
1683 if (m_console->sql_cmd(cmd, results)) {
1684 QStringList fieldlist;
1686 /* Iterate through the record returned from the query */
1687 foreach (QString resultline, results) {
1688 /* Iterate through fields in the record */
1690 fieldlist = resultline.split("\t");
1691 foreach (QString field, fieldlist) {
1693 qfileIndex = field.toInt();
1700 } /* if (index != -1) */