X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fqt-console%2Fjoblist%2Fjoblist.cpp;h=2cffc47ef170edfa342e8811ded318836f76dd04;hb=38a8c834529d9d02032fbf7db2afd79ed6089121;hp=fcfe9025021a4432b8ba29fcb76bb48914b3df86;hpb=430a16b9b38bd0aa79068abbb1c974375de192c1;p=bacula%2Fbacula diff --git a/bacula/src/qt-console/joblist/joblist.cpp b/bacula/src/qt-console/joblist/joblist.cpp index fcfe902502..2cffc47ef1 100644 --- a/bacula/src/qt-console/joblist/joblist.cpp +++ b/bacula/src/qt-console/joblist/joblist.cpp @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2007 Free Software Foundation Europe e.V. + Copyright (C) 2007-2009 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public + modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. @@ -15,12 +15,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -31,13 +31,18 @@ * Dirk Bartley, March 2007 */ +#include "bat.h" #include #include -#include "bat.h" #include "joblist.h" #include "restore.h" +#include "job/job.h" #include "joblog/joblog.h" +#ifdef HAVE_QWT #include "jobgraphs/jobplot.h" +#endif +#include "util/fmtwidgetitem.h" +#include "util/comboutil.h" /* * Constructor for the class @@ -46,30 +51,28 @@ JobList::JobList(const QString &mediaName, const QString &clientName, const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem) { setupUi(this); - m_name = ""; /* treeWidgetName has a virtual override in this class */ + m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */ m_mediaName = mediaName; m_clientName = clientName; m_jobName = jobName; m_filesetName = filesetName; - m_filesetName = filesetName; - pgInitialize(parentTreeWidgetItem); + pgInitialize("", parentTreeWidgetItem); QTreeWidgetItem* thisitem = mainWin->getFromHash(this); thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png"))); m_resultCount = 0; m_populated = false; m_closeable = false; - if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) + if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) { m_closeable=true; + } m_checkCurrentWidget = true; - createConnections(); /* Set Defaults for check and spin for limits */ limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked); limitSpinBox->setValue(mainWin->m_recordLimitVal); daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked); daysSpinBox->setValue(mainWin->m_daysLimitVal); - dockPage(); QGridLayout *gridLayout = new QGridLayout(this); gridLayout->setSpacing(6); @@ -81,11 +84,13 @@ JobList::JobList(const QString &mediaName, const QString &clientName, area->setObjectName(QString::fromUtf8("area")); area->setWidget(frame); area->setWidgetResizable(true); - m_splitter->addWidget(mp_tableWidget); m_splitter->addWidget(area); + m_splitter->addWidget(mp_tableWidget); gridLayout->addWidget(m_splitter, 0, 0, 1, 1); + createConnections(); readSettings(); + if (m_closeable) { dockPage(); } } /* @@ -104,136 +109,34 @@ JobList::~JobList() */ void JobList::populateTable() { - QStringList results; - QString resultline; - QBrush blackBrush(Qt::black); - - if (!m_console->preventInUseConnect()) - return; - /* Can't do this in constructor because not neccesarily conected in constructor */ - if (!m_populated) { - clientComboBox->addItem("Any"); - clientComboBox->addItems(m_console->client_list); - int clientIndex = clientComboBox->findText(m_clientName, Qt::MatchExactly); - if (clientIndex != -1) - clientComboBox->setCurrentIndex(clientIndex); + prepareFilterWidgets(); + m_populated = true; - QStringList volumeList; - m_console->getVolumeList(volumeList); - volumeComboBox->addItem("Any"); - volumeComboBox->addItems(volumeList); - int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly); - if (volumeIndex != -1) { - volumeComboBox->setCurrentIndex(volumeIndex); - } - jobComboBox->addItem("Any"); - jobComboBox->addItems(m_console->job_list); - int jobIndex = jobComboBox->findText(m_jobName, Qt::MatchExactly); - if (jobIndex != -1) { - jobComboBox->setCurrentIndex(jobIndex); - } - levelComboBox->addItem("Any"); - levelComboBox->addItems( QStringList() << "F" << "D" << "I"); - purgedComboBox->addItem("Any"); - purgedComboBox->addItems( QStringList() << "0" << "1"); - fileSetComboBox->addItem("Any"); - fileSetComboBox->addItems(m_console->fileset_list); - int filesetIndex = fileSetComboBox->findText(m_filesetName, Qt::MatchExactly); - if (filesetIndex != -1) { - fileSetComboBox->setCurrentIndex(filesetIndex); - } - QStringList statusLongList; - m_console->getStatusList(statusLongList); - statusComboBox->addItem("Any"); - statusComboBox->addItems(statusLongList); - } + Freeze frz(*mp_tableWidget); /* disable updating*/ /* Set up query */ - QString query(""); - int volumeIndex = volumeComboBox->currentIndex(); - if (volumeIndex != -1) - m_mediaName = volumeComboBox->itemText(volumeIndex); - query += "SELECT DISTINCT Job.Jobid AS Id, Job.Name AS JobName, Client.Name AS Client," - " Job.Starttime AS JobStart, Job.Type AS JobType," - " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount," - " Job.JobBytes AS Bytes," - " Job.JobStatus AS Status, Status.JobStatusLong AS StatusLong," - " Job.PurgedFiles AS Purged, FileSet.FileSet" - " FROM Job" - " LEFT OUTER JOIN Client ON (Client.ClientId=Job.ClientId)" - " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId)" - " LEFT OUTER JOIN Status ON (Job.JobStatus=Status.JobStatus)" - " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId)" - " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId)"; - QStringList conditions; - if (m_mediaName != "Any") { - conditions.append("Media.VolumeName='" + m_mediaName + "'"); - } - int clientIndex = clientComboBox->currentIndex(); - if (clientIndex != -1) - m_clientName = clientComboBox->itemText(clientIndex); - if (m_clientName != "Any") { - conditions.append("Client.Name='" + m_clientName + "'"); - } - int jobIndex = jobComboBox->currentIndex(); - if (jobIndex != -1) - m_jobName = jobComboBox->itemText(jobIndex); - if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != "Any")) { - conditions.append("Job.Name='" + jobComboBox->itemText(jobIndex) + "'"); - } - int levelIndex = levelComboBox->currentIndex(); - if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != "Any")) { - conditions.append("Job.Level='" + levelComboBox->itemText(levelIndex) + "'"); - } - int statusIndex = statusComboBox->currentIndex(); - if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != "Any")) { - conditions.append("Status.JobStatusLong='" + statusComboBox->itemText(statusIndex) + "'"); - } - int purgedIndex = purgedComboBox->currentIndex(); - if ((purgedIndex != -1) && (purgedComboBox->itemText(purgedIndex) != "Any")) { - conditions.append("Job.PurgedFiles='" + purgedComboBox->itemText(purgedIndex) + "'"); - } - int fileSetIndex = fileSetComboBox->currentIndex(); - if (fileSetIndex != -1) - m_filesetName = fileSetComboBox->itemText(fileSetIndex); - if ((fileSetIndex != -1) && (fileSetComboBox->itemText(fileSetIndex) != "Any")) { - conditions.append("FileSet.FileSet='" + fileSetComboBox->itemText(fileSetIndex) + "'"); - } - /* If Limit check box For limit by days is checked */ - if (daysCheckBox->checkState() == Qt::Checked) { - QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value()); - QString since = stamp.toString(Qt::ISODate); - conditions.append("Job.Starttime>'" + since + "'"); - } - bool first = true; - foreach (QString condition, conditions) { - if (first) { - query += " WHERE " + condition; - first = false; - } else { - query += " AND " + condition; - } - } - /* Descending */ - query += " ORDER BY Job.Starttime DESC, Job.JobId DESC"; - /* If Limit check box for limit records returned is checked */ - if (limitCheckBox->checkState() == Qt::Checked) { - QString limit; - limit.setNum(limitSpinBox->value()); - query += " LIMIT " + limit; - } + QString query; + fillQueryString(query); /* Set up the Header for the table */ QStringList headerlist = (QStringList() - << "Job Id" << "Job Name" << "Client" << "Job Starttime" << "Job Type" - << "Job Level" << "Job Files" << "Job Bytes" << "Job Status" << "Purged" << "File Set" ); - m_purgedIndex = headerlist.indexOf("Purged"); - m_typeIndex = headerlist.indexOf("Job Type"); - m_statusIndex = headerlist.indexOf("Job Status"); - m_startIndex = headerlist.indexOf("Job Starttime"); - m_filesIndex = headerlist.indexOf("Job Files"); - m_bytesIndex = headerlist.indexOf("Job Bytes"); + << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime") + << tr("Job Type") << tr("Job Level") << tr("Job Files") + << tr("Job Bytes") << tr("Job Status") << tr("Purged") << tr("File Set") + << tr("Pool Name") << tr("First Volume") << tr("VolCount")); + + m_jobIdIndex = headerlist.indexOf(tr("Job Id")); + m_purgedIndex = headerlist.indexOf(tr("Purged")); + m_typeIndex = headerlist.indexOf(tr("Job Type")); + m_statusIndex = headerlist.indexOf(tr("Job Status")); + m_startIndex = headerlist.indexOf(tr("Job Starttime")); + m_filesIndex = headerlist.indexOf(tr("Job Files")); + m_bytesIndex = headerlist.indexOf(tr("Job Bytes")); + m_levelIndex = headerlist.indexOf(tr("Job Level")); + m_nameIndex = headerlist.indexOf(tr("Job Name")); + m_filesetIndex = headerlist.indexOf(tr("File Set")); + m_clientIndex = headerlist.indexOf(tr("Client")); /* Initialize the QTableWidget */ m_checkCurrentWidget = false; @@ -241,68 +144,195 @@ void JobList::populateTable() m_checkCurrentWidget = true; mp_tableWidget->setColumnCount(headerlist.size()); mp_tableWidget->setHorizontalHeaderLabels(headerlist); + mp_tableWidget->horizontalHeader()->setHighlightSections(false); + mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */ if (mainWin->m_sqlDebug) { Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data()); } + + QStringList results; if (m_console->sql_cmd(query, results)) { m_resultCount = results.count(); - QTableWidgetItem* p_tableitem; - QString field; QStringList fieldlist; mp_tableWidget->setRowCount(results.size()); int row = 0; /* Iterate through the record returned from the query */ + QString resultline; foreach (resultline, results) { fieldlist = resultline.split("\t"); - int column = 0; - bool m_statusIndexDone = false; - QString statusCode(""); + if (fieldlist.size() < 13) + continue; /* some fields missing, ignore row */ + + TableItemFormatter jobitem(*mp_tableWidget, row); + /* Iterate through fields in the record */ - foreach (field, fieldlist) { - field = field.trimmed(); /* strip leading & trailing spaces */ - if ((column == m_statusIndex) && (!m_statusIndexDone)){ - m_statusIndexDone = true; - statusCode = field; - } else { - p_tableitem = new QTableWidgetItem(field,1); - p_tableitem->setFlags(0); - p_tableitem->setForeground(blackBrush); - mp_tableWidget->setItem(row, column, p_tableitem); - if (column == m_statusIndex) - setStatusColor(p_tableitem, statusCode); - column++; - } - } + QStringListIterator fld(fieldlist); + int col = 0; + + /* job id */ + jobitem.setNumericFld(col++, fld.next()); + + /* job name */ + jobitem.setTextFld(col++, fld.next()); + + /* client */ + jobitem.setTextFld(col++, fld.next()); + + /* job starttime */ + jobitem.setTextFld(col++, fld.next(), true); + + /* job type */ + jobitem.setJobTypeFld(col++, fld.next()); + + /* job level */ + jobitem.setJobLevelFld(col++, fld.next()); + + /* job files */ + jobitem.setNumericFld(col++, fld.next()); + + /* job bytes */ + jobitem.setBytesFld(col++, fld.next()); + + /* job status */ + jobitem.setJobStatusFld(col++, fld.next()); + + /* purged */ + jobitem.setBoolFld(col++, fld.next()); + + /* fileset */ + jobitem.setTextFld(col++, fld.next()); + + /* pool name */ + jobitem.setTextFld(col++, fld.next()); + + /* First Media */ + jobitem.setTextFld(col++, fld.next()); + + /* Medias count */ + jobitem.setNumericFld(col++, fld.next()); row++; } } + /* set default sorting */ + mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder); + mp_tableWidget->setSortingEnabled(true); + /* Resize the columns */ mp_tableWidget->resizeColumnsToContents(); mp_tableWidget->resizeRowsToContents(); mp_tableWidget->verticalHeader()->hide(); - if ((m_mediaName != "Any") && (m_resultCount == 0)){ + if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){ /* for context sensitive searches, let the user know if there were no * results */ - QMessageBox::warning(this, tr("Bat"), + QMessageBox::warning(this, "Bat", tr("The Jobs query returned no results.\n" "Press OK to continue?"), QMessageBox::Ok ); } + + /* make read only */ + mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); } -void JobList::setStatusColor(QTableWidgetItem *item, QString &field) +void JobList::prepareFilterWidgets() { - QString greenchars("TCR"); - QString redchars("BEf"); - QString yellowchars("eDAFSMmsjdctp"); - if (greenchars.contains(field, Qt::CaseSensitive)) { - item->setBackground(Qt::green); - } else if (redchars.contains(field, Qt::CaseSensitive)) { - item->setBackground(Qt::red); - } else if (yellowchars.contains(field, Qt::CaseSensitive)){ - item->setBackground(Qt::yellow); + if (!m_populated) { + clientComboBox->addItem(tr("Any")); + clientComboBox->addItems(m_console->client_list); + comboSel(clientComboBox, m_clientName); + + QStringList volumeList; + getVolumeList(volumeList); + volumeComboBox->addItem(tr("Any")); + volumeComboBox->addItems(volumeList); + comboSel(volumeComboBox, m_mediaName); + + jobComboBox->addItem(tr("Any")); + jobComboBox->addItems(m_console->job_list); + comboSel(jobComboBox, m_jobName); + + levelComboFill(levelComboBox); + + boolComboFill(purgedComboBox); + + fileSetComboBox->addItem(tr("Any")); + fileSetComboBox->addItems(m_console->fileset_list); + comboSel(fileSetComboBox, m_filesetName); + + poolComboBox->addItem(tr("Any")); + poolComboBox->addItems(m_console->pool_list); + + jobStatusComboFill(statusComboBox); + } +} + +void JobList::fillQueryString(QString &query) +{ + query = ""; + int volumeIndex = volumeComboBox->currentIndex(); + if (volumeIndex != -1) + m_mediaName = volumeComboBox->itemText(volumeIndex); + QString distinct = ""; + if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; } + query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, " + " Client.Name AS Client," + " Job.Starttime AS JobStart, Job.Type AS JobType," + " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount," + " Job.JobBytes AS Bytes, Job.JobStatus AS Status," + " Job.PurgedFiles AS Purged, FileSet.FileSet," + " Pool.Name AS Pool," + " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume," + " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes" + " FROM Job" + " JOIN Client ON (Client.ClientId=Job.ClientId)" + " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) " + " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId "; + QStringList conditions; + if (m_mediaName != tr("Any")) { + query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) " + " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) "; + conditions.append("Media.VolumeName='" + m_mediaName + "'"); + } + + comboCond(conditions, clientComboBox, "Client.Name"); + comboCond(conditions, jobComboBox, "Job.Name"); + levelComboCond(conditions, levelComboBox, "Job.Level"); + jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus"); + boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles"); + comboCond(conditions, fileSetComboBox, "FileSet.FileSet"); + comboCond(conditions, poolComboBox, "Pool.Name"); + + /* If Limit check box For limit by days is checked */ + if (daysCheckBox->checkState() == Qt::Checked) { + QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value()); + QString since = stamp.toString(Qt::ISODate); + conditions.append("Job.Starttime > '" + since + "'"); + } + if (filterCopyCheckBox->checkState() == Qt::Checked) { + conditions.append("Job.Type != 'c'" ); + } + if (filterMigrationCheckBox->checkState() == Qt::Checked) { + conditions.append("Job.Type != 'g'" ); + } + bool first = true; + foreach (QString condition, conditions) { + if (first) { + query += " WHERE " + condition; + first = false; + } else { + query += " AND " + condition; + } + } + /* Descending */ + query += " ORDER BY Job.JobId DESC"; + /* If Limit check box for limit records returned is checked */ + if (limitCheckBox->checkState() == Qt::Checked) { + QString limit; + limit.setNum(limitSpinBox->value()); + query += " LIMIT " + limit; } } @@ -314,7 +344,20 @@ void JobList::PgSeltreeWidgetClicked() { if (!m_populated) { populateTable(); - m_populated=true; + /* Lets make sure the splitter is not all the way to size index 0 == 0 */ + QList sizes = m_splitter->sizes(); + if (sizes[0] == 0) { + int frameMax = frame->maximumHeight(); + int sizeSum = 0; + foreach(int size, sizes) { sizeSum += size; } + int tabHeight = mainWin->tabWidget->geometry().height(); + sizes[0] = frameMax; + sizes[1] = tabHeight - frameMax; + m_splitter->setSizes(sizes); + } + } + if (!isOnceDocked()) { + dockPage(); } } @@ -324,10 +367,8 @@ void JobList::PgSeltreeWidgetClicked() */ void JobList::currentStackItem() { - populateTable(); - if (!m_populated) { - m_populated=true; - } +/* if (!m_populated) populate every time user comes back to this object */ + populateTable(); } /* @@ -335,59 +376,16 @@ void JobList::currentStackItem() */ void JobList::treeWidgetName(QString &desc) { - if ((m_mediaName == "") && (m_clientName == "") && (m_jobName == "") && (m_filesetName == "")) { - desc = "JobList"; + if (m_mediaName != "" ) { + desc = tr("Jobs Run on Volume %1").arg(m_mediaName); + } else if (m_clientName != "" ) { + desc = tr("Jobs Run from Client %1").arg(m_clientName); + } else if (m_jobName != "" ) { + desc = tr("Jobs Run of Job %1").arg(m_jobName); + } else if (m_filesetName != "" ) { + desc = tr("Jobs Run with fileset %1").arg(m_filesetName); } else { - desc = "JobList "; - if (m_mediaName != "" ) { - desc += "of Volume " + m_mediaName; - } - if (m_clientName != "" ) { - desc += "of Client " + m_clientName; - } - if (m_jobName != "" ) { - desc += "of Job " + m_jobName; - } - if (m_filesetName != "" ) { - desc += "of fileset " + m_filesetName; - } - } -} - -/* - * This functions much line tableItemChanged for trees like the page selector, - * but I will do much less here - */ -void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/) -{ - if (m_checkCurrentWidget) { - int row = currentItem->row(); - QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0); - m_currentJob = jobitem->text(); - - /* include purged action or not */ - jobitem = mp_tableWidget->item(row, m_purgedIndex); - QString purged = jobitem->text(); - mp_tableWidget->removeAction(actionPurgeFiles); - if (purged == "0") { - mp_tableWidget->addAction(actionPurgeFiles); - } - /* include restore from time and job action or not */ - jobitem = mp_tableWidget->item(row, m_typeIndex); - QString type = jobitem->text(); - mp_tableWidget->removeAction(actionRestoreFromJob); - mp_tableWidget->removeAction(actionRestoreFromTime); - if (type == "B") { - mp_tableWidget->addAction(actionRestoreFromJob); - mp_tableWidget->addAction(actionRestoreFromTime); - } - /* include cancel action or not */ - jobitem = mp_tableWidget->item(row, m_statusIndex); - QString status = jobitem->text(); - mp_tableWidget->removeAction(actionCancelJob); - if (status == "Running") { - mp_tableWidget->addAction(actionCancelJob); - } + desc = tr("Jobs Run"); } } @@ -399,14 +397,17 @@ void JobList::createConnections() { /* connect to the action specific to this pages class that shows up in the * page selector tree */ - connect(actionRefreshJobList, SIGNAL(triggered()), this, - SLOT(populateTable())); + connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable())); connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable())); +#ifdef HAVE_QWT connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable())); - /* for the tableItemChanged to maintain m_currentJob */ - connect(mp_tableWidget, SIGNAL( - currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)), - this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *))); +#else + graphButton->setEnabled(false); + graphButton->setVisible(false); +#endif + /* for the selectionChanged to maintain m_currentJob and a delete selection */ + connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); + connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob())); /* Do what is required for the local context sensitive menu */ @@ -414,41 +415,18 @@ void JobList::createConnections() /* setContextMenuPolicy is required */ mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu); - /* Add Actions */ - mp_tableWidget->addAction(actionRefreshJobList); - mp_tableWidget->addAction(actionListJobid); - mp_tableWidget->addAction(actionListFilesOnJob); - mp_tableWidget->addAction(actionListJobMedia); - mp_tableWidget->addAction(actionListVolumes); - mp_tableWidget->addAction(actionDeleteJob); - mp_tableWidget->addAction(actionPurgeFiles); - mp_tableWidget->addAction(actionRestoreFromJob); - mp_tableWidget->addAction(actionRestoreFromTime); - mp_tableWidget->addAction(actionShowLogForJob); - - /* Make Connections */ - connect(actionListJobid, SIGNAL(triggered()), this, - SLOT(consoleListJobid())); - connect(actionListFilesOnJob, SIGNAL(triggered()), this, - SLOT(consoleListFilesOnJob())); - connect(actionListJobMedia, SIGNAL(triggered()), this, - SLOT(consoleListJobMedia())); - connect(actionListVolumes, SIGNAL(triggered()), this, - SLOT(consoleListVolumes())); - connect(actionDeleteJob, SIGNAL(triggered()), this, - SLOT(consoleDeleteJob())); - connect(actionPurgeFiles, SIGNAL(triggered()), this, - SLOT(consolePurgeFiles())); - connect(actionRestoreFromJob, SIGNAL(triggered()), this, - SLOT(preRestoreFromJob())); - connect(actionRestoreFromTime, SIGNAL(triggered()), this, - SLOT(preRestoreFromTime())); - connect(actionShowLogForJob, SIGNAL(triggered()), this, - SLOT(showLogForJob())); - connect(actionCancelJob, SIGNAL(triggered()), this, - SLOT(consoleCancelJob())); - connect(actionListJobTotals, SIGNAL(triggered()), this, - SLOT(consoleListJobTotals())); + connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob())); + connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia())); + connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob())); + connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob())); + connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles())); + connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob())); + connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime())); + connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob())); + connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob())); + connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob())); + connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals())); + connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int))); m_contextActions.append(actionRefreshJobList); m_contextActions.append(actionListJobTotals); @@ -458,13 +436,6 @@ void JobList::createConnections() * Functions to respond to local context sensitive menu sending console commands * If I could figure out how to make these one function passing a string, Yaaaaaa */ -void JobList::consoleListJobid() -{ - QString cmd("list jobid="); - cmd += m_currentJob; - if (mainWin->m_longList) { cmd.prepend("l"); } - consoleCommand(cmd); -} void JobList::consoleListFilesOnJob() { QString cmd("list files jobid="); @@ -479,23 +450,17 @@ void JobList::consoleListJobMedia() if (mainWin->m_longList) { cmd.prepend("l"); } consoleCommand(cmd); } -void JobList::consoleListVolumes() -{ - QString cmd("list volumes jobid="); - cmd += m_currentJob; - if (mainWin->m_longList) { cmd.prepend("l"); } - consoleCommand(cmd); -} + void JobList::consoleListJobTotals() { QString cmd("list jobtotals"); - cmd += m_currentJob; if (mainWin->m_longList) { cmd.prepend("l"); } consoleCommand(cmd); } + void JobList::consoleDeleteJob() { - if (QMessageBox::warning(this, tr("Bat"), + if (QMessageBox::warning(this, "Bat", tr("Are you sure you want to delete?? !!!.\n" "This delete command is used to delete a Job record and all associated catalog" " records that were created. This command operates only on the Catalog" @@ -508,12 +473,30 @@ void JobList::consoleDeleteJob() == QMessageBox::Cancel) { return; } QString cmd("delete job jobid="); - cmd += m_currentJob; - consoleCommand(cmd); + cmd += m_selectedJobs; + consoleCommand(cmd, false); + populateTable(); } + +void JobList::consoleRestartJob() +{ + QString cmd; + + cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName); + if (m_filesetName != "" && m_filesetName != "*None*") { + cmd += tr(" fileset=\"%1\"").arg(m_filesetName); + } + + if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data()); + consoleCommand(cmd, false); + populateTable(); +} + + + void JobList::consolePurgeFiles() { - if (QMessageBox::warning(this, tr("Bat"), + if (QMessageBox::warning(this, "Bat", tr("Are you sure you want to purge ?? !!!.\n" "The Purge command will delete associated Catalog database records from Jobs and" " Volumes without considering the retention period. Purge works only on the" @@ -525,9 +508,14 @@ void JobList::consolePurgeFiles() QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { return; } - QString cmd("purge files jobid="); - cmd += m_currentJob; - consoleCommand(cmd); + m_console->m_warningPrevent = true; + foreach(QString job, m_selectedJobsList) { + QString cmd("purge files jobid="); + cmd += job; + consoleCommand(cmd, false); + } + m_console->m_warningPrevent = false; + populateTable(); } /* @@ -555,6 +543,15 @@ void JobList::showLogForJob() new JobLog(m_currentJob, pageSelectorTreeWidgetItem); } +/* + * Subroutine to call class to show the log in the database from that job + */ +void JobList::showInfoForJob(QTableWidgetItem * /*item*/) +{ + QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this); + new Job(m_currentJob, pageSelectorTreeWidgetItem); +} + /* * Cancel a running job */ @@ -570,6 +567,7 @@ void JobList::consoleCancelJob() */ void JobList::graphTable() { +#ifdef HAVE_QWT JobPlotPass pass; pass.recordLimitCheck = limitCheckBox->checkState(); pass.daysLimitCheck = daysCheckBox->checkState(); @@ -585,7 +583,9 @@ void JobList::graphTable() pass.use = true; QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this); new JobPlot(pageSelectorTreeWidgetItem, pass); +#endif } + /* * Save user settings associated with this page */ @@ -594,6 +594,8 @@ void JobList::writeSettings() QSettings settings(m_console->m_dir->name(), "bat"); settings.beginGroup(m_groupText); settings.setValue(m_splitText, m_splitter->saveState()); + settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState()); + settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState()); settings.endGroup(); } @@ -603,9 +605,134 @@ void JobList::writeSettings() void JobList::readSettings() { m_groupText = "JobListPage"; - m_splitText = "splitterSizes_1"; + m_splitText = "splitterSizes_2"; QSettings settings(m_console->m_dir->name(), "bat"); settings.beginGroup(m_groupText); - m_splitter->restoreState(settings.value(m_splitText).toByteArray()); + if (settings.contains(m_splitText)) { + m_splitter->restoreState(settings.value(m_splitText).toByteArray()); + } + filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt()); + filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt()); settings.endGroup(); } + +/* + * Function to fill m_selectedJobsCount and m_selectedJobs with selected values + */ +void JobList::selectionChanged() +{ + QList rowList; + QList sitems = mp_tableWidget->selectedItems(); + foreach (QTableWidgetItem *sitem, sitems) { + int row = sitem->row(); + if (!rowList.contains(row)) { + rowList.append(row); + } + } + + m_selectedJobs = ""; + m_selectedJobsList.clear(); + bool first = true; + foreach(int row, rowList) { + QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex); + if (!first) m_selectedJobs.append(","); + else first = false; + m_selectedJobs.append(sitem->text()); + m_selectedJobsList.append(sitem->text()); + } + m_selectedJobsCount = rowList.count(); + if (m_selectedJobsCount > 1) { + QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount); + actionDeleteJob->setText(text); + text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount); + actionPurgeFiles->setText(text); + } else { + actionDeleteJob->setText(tr("Delete Single Job")); + actionPurgeFiles->setText(tr("Purge Files from single job")); + } + + /* remove all actions */ + foreach(QAction* mediaAction, mp_tableWidget->actions()) { + mp_tableWidget->removeAction(mediaAction); + } + + /* Add Actions */ + mp_tableWidget->addAction(actionRefreshJobList); + if (m_selectedJobsCount == 1) { + mp_tableWidget->addAction(actionListFilesOnJob); + mp_tableWidget->addAction(actionListJobMedia); + mp_tableWidget->addAction(actionRestartJob); + mp_tableWidget->addAction(actionRestoreFromJob); + mp_tableWidget->addAction(actionRestoreFromTime); + mp_tableWidget->addAction(actionShowLogForJob); + mp_tableWidget->addAction(actionShowInfoForJob); + } + if (m_selectedJobsCount >= 1) { + mp_tableWidget->addAction(actionDeleteJob); + mp_tableWidget->addAction(actionPurgeFiles); + } + + /* Make Connections */ + if (m_checkCurrentWidget) { + int row = mp_tableWidget->currentRow(); + QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0); + m_currentJob = jobitem->text(); /* get JobId */ + jobitem = mp_tableWidget->item(row, m_clientIndex); + m_clientName = jobitem->text(); /* get Client Name */ + jobitem = mp_tableWidget->item(row, m_nameIndex); + m_jobName = jobitem->text(); /* get Job Name */ + jobitem = mp_tableWidget->item(row, m_levelIndex); + m_levelName = jobitem->text(); /* get level */ + jobitem = mp_tableWidget->item(row, m_filesetIndex); + if (jobitem) { + m_filesetName = jobitem->text(); /* get FileSet Name */ + } else { + m_filesetName = ""; + } + + /* include purged action or not */ + jobitem = mp_tableWidget->item(row, m_purgedIndex); + QString purged = jobitem->text(); +/* mp_tableWidget->removeAction(actionPurgeFiles); + if (purged == tr("No") ) { + mp_tableWidget->addAction(actionPurgeFiles); + }*/ + + /* include restore from time and job action or not */ + jobitem = mp_tableWidget->item(row, m_typeIndex); + QString type = jobitem->text(); + if (m_selectedJobsCount == 1) { + mp_tableWidget->removeAction(actionRestoreFromJob); + mp_tableWidget->removeAction(actionRestoreFromTime); + if (type == tr("Backup")) { + mp_tableWidget->addAction(actionRestoreFromJob); + mp_tableWidget->addAction(actionRestoreFromTime); + } + } + + /* include cancel action or not */ + jobitem = mp_tableWidget->item(row, m_statusIndex); + QString status = jobitem->text(); + mp_tableWidget->removeAction(actionCancelJob); + if (status == tr("Running") || status == tr("Created, not yet running")) { + mp_tableWidget->addAction(actionCancelJob); + } + } +} + +/* + * Function to prevent the splitter from making index 0 of the size larger than it + * needs to be + */ +void JobList::splitterMoved(int /*pos*/, int /*index*/) +{ + int frameMax = frame->maximumHeight(); + QList sizes = m_splitter->sizes(); + int sizeSum = 0; + foreach(int size, sizes) { sizeSum += size; } + if (sizes[0] > frameMax) { + sizes[0] = frameMax; + sizes[1] = sizeSum - frameMax; + m_splitter->setSizes(sizes); + } +}