]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
This is a patch from Riccardo. It is for updating translations.
[bacula/bacula] / bacula / src / qt-console / joblist / joblist.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *   Version $Id$
30  *
31  *   Dirk Bartley, March 2007
32  */
33  
34 #include <QAbstractEventDispatcher>
35 #include <QTableWidgetItem>
36 #include "bat.h"
37 #include "joblist.h"
38 #include "restore.h"
39 #include "joblog/joblog.h"
40 #ifdef HAVE_QWT
41 #include "jobgraphs/jobplot.h"
42 #endif
43 #include "util/fmtwidgetitem.h"
44
45 /*
46  * Constructor for the class
47  */
48 JobList::JobList(const QString &mediaName, const QString &clientName,
49           const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
50 {
51    setupUi(this);
52    m_name = ""; /* treeWidgetName has a virtual override in this class */
53    m_mediaName = mediaName;
54    m_clientName = clientName;
55    m_jobName = jobName;
56    m_filesetName = filesetName;
57    m_filesetName = filesetName;
58    pgInitialize(parentTreeWidgetItem);
59    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
60    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
61
62    m_resultCount = 0;
63    m_populated = false;
64    m_closeable = false;
65    if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != ""))
66       m_closeable=true;
67    m_checkCurrentWidget = true;
68    createConnections();
69
70    /* Set Defaults for check and spin for limits */
71    limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
72    limitSpinBox->setValue(mainWin->m_recordLimitVal);
73    daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
74    daysSpinBox->setValue(mainWin->m_daysLimitVal);
75    dockPage();
76
77    QGridLayout *gridLayout = new QGridLayout(this);
78    gridLayout->setSpacing(6);
79    gridLayout->setMargin(9);
80    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
81
82    m_splitter = new QSplitter(Qt::Vertical, this);
83    QScrollArea *area = new QScrollArea();
84    area->setObjectName(QString::fromUtf8("area"));
85    area->setWidget(frame);
86    area->setWidgetResizable(true);
87    m_splitter->addWidget(mp_tableWidget);
88    m_splitter->addWidget(area);
89
90    gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
91    readSettings();
92 }
93
94 /*
95  * Write the m_splitter settings in the destructor
96  */
97 JobList::~JobList()
98 {
99    writeSettings();
100 }
101
102 /*
103  * The Meat of the class.
104  * This function will populate the QTableWidget, mp_tablewidget, with
105  * QTableWidgetItems representing the results of a query for what jobs exist on
106  * the media name passed from the constructor stored in m_mediaName.
107  */
108 void JobList::populateTable()
109 {
110    if (!m_console->preventInUseConnect())
111        return;
112
113    /* Can't do this in constructor because not neccesarily conected in constructor */
114    prepareFilterWidgets();
115
116    /* Set up query */
117    QString query;
118    fillQueryString(query);
119
120    /* Set up the Header for the table */
121    QStringList headerlist = (QStringList()
122       << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime") 
123       << tr("Job Type") << tr("Job Level") << tr("Job Files") 
124       << tr("Job Bytes") << tr("Job Status")  << tr("Purged") << tr("File Set"));
125
126    m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
127    m_purgedIndex = headerlist.indexOf(tr("Purged"));
128    m_typeIndex = headerlist.indexOf(tr("Job Type"));
129    m_statusIndex = headerlist.indexOf(tr("Job Status"));
130    m_startIndex = headerlist.indexOf(tr("Job Starttime"));
131    m_filesIndex = headerlist.indexOf(tr("Job Files"));
132    m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
133
134    /* Initialize the QTableWidget */
135    m_checkCurrentWidget = false;
136    mp_tableWidget->clear();
137    m_checkCurrentWidget = true;
138    mp_tableWidget->setColumnCount(headerlist.size());
139    mp_tableWidget->setHorizontalHeaderLabels(headerlist);
140    mp_tableWidget->horizontalHeader()->setHighlightSections(false);
141    mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
142    mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
143
144    if (mainWin->m_sqlDebug) {
145       Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
146    }
147
148    QStringList results;
149    if (m_console->sql_cmd(query, results)) {
150       m_resultCount = results.count();
151
152       QStringList fieldlist;
153       mp_tableWidget->setRowCount(results.size());
154
155       int row = 0;
156       /* Iterate through the record returned from the query */
157       QString resultline;
158       foreach (resultline, results) {
159          fieldlist = resultline.split("\t");
160          if (fieldlist.size() < 12)
161             continue; /* some fields missing, ignore row */
162
163          TableItemFormatter jobitem(*mp_tableWidget, row);
164   
165          /* Iterate through fields in the record */
166          QStringListIterator fld(fieldlist);
167          int col = 0;
168
169          /* job id */
170          jobitem.setNumericFld(col++, fld.next());
171
172          /* job name */
173          jobitem.setTextFld(col++, fld.next());
174
175          /* client */
176          jobitem.setTextFld(col++, fld.next());
177
178          /* job starttime */
179          jobitem.setTextFld(col++, fld.next(), true);
180
181          /* job type */
182          jobitem.setJobTypeFld(col++, fld.next());
183
184          /* job level */
185          jobitem.setJobLevelFld(col++, fld.next());
186
187          /* job files */
188          jobitem.setNumericFld(col++, fld.next());
189
190          /* job bytes */
191          jobitem.setBytesFld(col++, fld.next());
192
193          /* job status */
194          QString shortstatus(fld.next());
195          QString longstatus(fld.next());
196          jobitem.setJobStatusFld(col++, shortstatus, longstatus);
197
198          /* purged */
199          jobitem.setBoolFld(col++, fld.next());
200
201          /* fileset */
202          jobitem.setTextFld(col++, fld.next());
203
204          row++;
205       }
206    } 
207    /* set default sorting */
208    mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder);
209    mp_tableWidget->setSortingEnabled(true);
210    
211    /* Resize the columns */
212    mp_tableWidget->resizeColumnsToContents();
213    mp_tableWidget->resizeRowsToContents();
214    mp_tableWidget->verticalHeader()->hide();
215    if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
216       /* for context sensitive searches, let the user know if there were no
217        * results */
218       QMessageBox::warning(this, "Bat",
219           tr("The Jobs query returned no results.\n"
220          "Press OK to continue?"), QMessageBox::Ok );
221    }
222 }
223
224 void JobList::prepareFilterWidgets()
225 {
226    if (!m_populated) {
227       clientComboBox->addItem(tr("Any"));
228       clientComboBox->addItems(m_console->client_list);
229       int clientIndex = clientComboBox->findText(m_clientName, Qt::MatchExactly);
230       if (clientIndex != -1)
231          clientComboBox->setCurrentIndex(clientIndex);
232
233       QStringList volumeList;
234       m_console->getVolumeList(volumeList);
235       volumeComboBox->addItem(tr("Any"));
236       volumeComboBox->addItems(volumeList);
237       int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
238       if (volumeIndex != -1) {
239          volumeComboBox->setCurrentIndex(volumeIndex);
240       }
241       jobComboBox->addItem(tr("Any"));
242       jobComboBox->addItems(m_console->job_list);
243       int jobIndex = jobComboBox->findText(m_jobName, Qt::MatchExactly);
244       if (jobIndex != -1) {
245          jobComboBox->setCurrentIndex(jobIndex);
246       }
247
248       levelComboBox->addItem(tr("Any"));
249       levelComboBox->addItem(job_level_to_str(L_FULL), L_FULL);
250       levelComboBox->addItem(job_level_to_str(L_INCREMENTAL), L_INCREMENTAL);
251       levelComboBox->addItem(job_level_to_str(L_DIFFERENTIAL), L_DIFFERENTIAL);
252       levelComboBox->addItem(job_level_to_str(L_SINCE), L_SINCE);
253       levelComboBox->addItem(job_level_to_str(L_VERIFY_CATALOG), L_VERIFY_CATALOG);
254       levelComboBox->addItem(job_level_to_str(L_VERIFY_INIT), L_VERIFY_INIT);
255       levelComboBox->addItem(job_level_to_str(L_VERIFY_VOLUME_TO_CATALOG), L_VERIFY_VOLUME_TO_CATALOG);
256       levelComboBox->addItem(job_level_to_str(L_VERIFY_DISK_TO_CATALOG), L_VERIFY_DISK_TO_CATALOG);
257       levelComboBox->addItem(job_level_to_str(L_VERIFY_DATA), L_VERIFY_DATA);
258       /* levelComboBox->addItem(job_level_to_str(L_BASE), L_BASE);  base jobs ignored */ 
259
260       purgedComboBox->addItem(tr("Any"), -1);
261       purgedComboBox->addItem(tr("No"), 0);
262       purgedComboBox->addItem(tr("Yes"), 1);
263
264       fileSetComboBox->addItem(tr("Any"));
265       fileSetComboBox->addItems(m_console->fileset_list);
266       int filesetIndex = fileSetComboBox->findText(m_filesetName, Qt::MatchExactly);
267       if (filesetIndex != -1) {
268          fileSetComboBox->setCurrentIndex(filesetIndex);
269       }
270       QStringList statusLongList;
271       m_console->getStatusList(statusLongList);
272       statusComboBox->addItem(tr("Any"));
273       statusComboBox->addItems(statusLongList);
274    }
275 }
276
277 void JobList::fillQueryString(QString &query)
278 {
279    query = "";
280    int volumeIndex = volumeComboBox->currentIndex();
281    if (volumeIndex != -1)
282       m_mediaName = volumeComboBox->itemText(volumeIndex);
283    QString distinct = "";
284    if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
285    query += "SELECT " + distinct + "Job.Jobid AS Id, Job.Name AS JobName, " 
286             " Client.Name AS Client,"
287             " Job.Starttime AS JobStart, Job.Type AS JobType,"
288             " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
289             " Job.JobBytes AS Bytes,"
290             " Job.JobStatus AS Status, Status.JobStatusLong AS StatusLong,"
291             " Job.PurgedFiles AS Purged, FileSet.FileSet"
292             " FROM Job"
293             " JOIN Client ON (Client.ClientId=Job.ClientId)"
294             " JOIN Status ON (Job.JobStatus=Status.JobStatus)"
295             " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) ";
296    QStringList conditions;
297    if (m_mediaName != tr("Any")) {
298       query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
299                " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
300       conditions.append("Media.VolumeName='" + m_mediaName + "'");
301    }
302    int clientIndex = clientComboBox->currentIndex();
303    if (clientIndex != -1)
304       m_clientName = clientComboBox->itemText(clientIndex);
305    if (m_clientName != tr("Any")) {
306       conditions.append("Client.Name='" + m_clientName + "'");
307    }
308    int jobIndex = jobComboBox->currentIndex();
309    if (jobIndex != -1)
310       m_jobName = jobComboBox->itemText(jobIndex);
311    if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != tr("Any"))) {
312       conditions.append("Job.Name='" + jobComboBox->itemText(jobIndex) + "'");
313    }
314    int levelIndex = levelComboBox->currentIndex();
315    if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != tr("Any"))) {
316       conditions.append( QString("Job.Level='%1'").arg(levelComboBox->itemData(levelIndex).toChar()) );
317    }
318    int statusIndex = statusComboBox->currentIndex();
319    if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != tr("Any"))) {
320       conditions.append("Status.JobStatusLong='" + statusComboBox->itemText(statusIndex) + "'");
321    }
322    int purgedIndex = purgedComboBox->currentIndex();
323    if (purgedIndex != -1 && purgedComboBox->itemData(purgedIndex).toInt() >= 0 ) {
324       conditions.append("Job.PurgedFiles='" + purgedComboBox->itemData(purgedIndex).toString() + "'");
325    }
326    int fileSetIndex = fileSetComboBox->currentIndex();
327    if (fileSetIndex != -1)
328       m_filesetName = fileSetComboBox->itemText(fileSetIndex);
329    if ((fileSetIndex != -1) && (fileSetComboBox->itemText(fileSetIndex) != tr("Any"))) {
330       conditions.append("FileSet.FileSet='" + fileSetComboBox->itemText(fileSetIndex) + "'");
331    }
332    /* If Limit check box For limit by days is checked  */
333    if (daysCheckBox->checkState() == Qt::Checked) {
334       QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
335       QString since = stamp.toString(Qt::ISODate);
336       conditions.append("Job.Starttime>'" + since + "'");
337    }
338    bool first = true;
339    foreach (QString condition, conditions) {
340       if (first) {
341          query += " WHERE " + condition;
342          first = false;
343       } else {
344          query += " AND " + condition;
345       }
346    }
347    /* Descending */
348    query += " ORDER BY Job.JobId DESC";
349    /* If Limit check box for limit records returned is checked  */
350    if (limitCheckBox->checkState() == Qt::Checked) {
351       QString limit;
352       limit.setNum(limitSpinBox->value());
353       query += " LIMIT " + limit;
354    }
355 }
356
357 /*
358  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
359  * The tree has been populated.
360  */
361 void JobList::PgSeltreeWidgetClicked()
362 {
363    if (!m_populated) {
364       populateTable();
365       m_populated=true;
366    }
367 }
368
369 /*
370  *  Virtual function override of pages function which is called when this page
371  *  is visible on the stack
372  */
373 void JobList::currentStackItem()
374 {
375    populateTable();
376    if (!m_populated) {
377       m_populated=true;
378    }
379 }
380
381 /*
382  * Virtual Function to return the name for the medialist tree widget
383  */
384 void JobList::treeWidgetName(QString &desc)
385 {
386    if (m_mediaName != "" ) {
387      desc = tr("JobList of Volume %1").arg(m_mediaName);
388    } else if (m_clientName != "" ) {
389      desc = tr("JobList of Client %1").arg(m_clientName);
390    } else if (m_jobName != "" ) {
391      desc = tr("JobList of Job %1").arg(m_jobName);
392    } else if (m_filesetName != "" ) {
393      desc = tr("JobList of fileset %1").arg(m_filesetName);
394    } else {
395      desc = tr("JobList");
396    }
397 }
398
399 /*
400  * This functions much line tableItemChanged for trees like the page selector,
401  * but I will do much less here
402  */
403 void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/)
404 {
405    if (m_checkCurrentWidget) {
406       int row = currentItem->row();
407       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
408       m_currentJob = jobitem->text();
409
410       /* include purged action or not */
411       jobitem = mp_tableWidget->item(row, m_purgedIndex);
412       QString purged = jobitem->text();
413       mp_tableWidget->removeAction(actionPurgeFiles);
414       if (purged == tr("No") ) {
415          mp_tableWidget->addAction(actionPurgeFiles);
416       }
417       /* include restore from time and job action or not */
418       jobitem = mp_tableWidget->item(row, m_typeIndex);
419       QString type = jobitem->text();
420       mp_tableWidget->removeAction(actionRestoreFromJob);
421       mp_tableWidget->removeAction(actionRestoreFromTime);
422       if (type == tr("Backup")) {
423          mp_tableWidget->addAction(actionRestoreFromJob);
424          mp_tableWidget->addAction(actionRestoreFromTime);
425       }
426       /* include cancel action or not */
427       jobitem = mp_tableWidget->item(row, m_statusIndex);
428       QString status = jobitem->text();
429       mp_tableWidget->removeAction(actionCancelJob);
430       if (status == tr("Running")) {
431          mp_tableWidget->addAction(actionCancelJob);
432       }
433    }
434 }
435
436 /*
437  * Function to create connections for context sensitive menu for this and
438  * the page selector
439  */
440 void JobList::createConnections()
441 {
442    /* connect to the action specific to this pages class that shows up in the 
443     * page selector tree */
444    connect(actionRefreshJobList, SIGNAL(triggered()), this,
445                 SLOT(populateTable()));
446    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
447 #ifdef HAVE_QWT
448    connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
449 #else
450    graphButton->setEnabled(false);
451 #endif
452    /* for the tableItemChanged to maintain m_currentJob */
453    connect(mp_tableWidget, SIGNAL(
454            currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
455            this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
456
457    /* for the tableItemChanged to maintain a delete selection */
458    connect(mp_tableWidget, SIGNAL( itemSelectionChanged()),
459            this, SLOT(selectedJobsGet()) );
460
461    /* Do what is required for the local context sensitive menu */
462
463
464    /* setContextMenuPolicy is required */
465    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
466
467    /* Add Actions */
468    mp_tableWidget->addAction(actionRefreshJobList);
469    mp_tableWidget->addAction(actionListJobid);
470    mp_tableWidget->addAction(actionListFilesOnJob);
471    mp_tableWidget->addAction(actionListJobMedia);
472    mp_tableWidget->addAction(actionListVolumes);
473    mp_tableWidget->addAction(actionDeleteJob);
474    mp_tableWidget->addAction(actionPurgeFiles);
475    mp_tableWidget->addAction(actionRestoreFromJob);
476    mp_tableWidget->addAction(actionRestoreFromTime);
477    mp_tableWidget->addAction(actionShowLogForJob);
478
479    /* Make Connections */
480    connect(actionListJobid, SIGNAL(triggered()), this,
481                 SLOT(consoleListJobid()));
482    connect(actionListFilesOnJob, SIGNAL(triggered()), this,
483                 SLOT(consoleListFilesOnJob()));
484    connect(actionListJobMedia, SIGNAL(triggered()), this,
485                 SLOT(consoleListJobMedia()));
486    connect(actionListVolumes, SIGNAL(triggered()), this,
487                 SLOT(consoleListVolumes()));
488    connect(actionDeleteJob, SIGNAL(triggered()), this,
489                 SLOT(consoleDeleteJob()));
490    connect(actionPurgeFiles, SIGNAL(triggered()), this,
491                 SLOT(consolePurgeFiles()));
492    connect(actionRestoreFromJob, SIGNAL(triggered()), this,
493                 SLOT(preRestoreFromJob()));
494    connect(actionRestoreFromTime, SIGNAL(triggered()), this,
495                 SLOT(preRestoreFromTime()));
496    connect(actionShowLogForJob, SIGNAL(triggered()), this,
497                 SLOT(showLogForJob()));
498    connect(actionCancelJob, SIGNAL(triggered()), this,
499                 SLOT(consoleCancelJob()));
500    connect(actionListJobTotals, SIGNAL(triggered()), this,
501                 SLOT(consoleListJobTotals()));
502
503    m_contextActions.append(actionRefreshJobList);
504    m_contextActions.append(actionListJobTotals);
505 }
506
507 /*
508  * Functions to respond to local context sensitive menu sending console commands
509  * If I could figure out how to make these one function passing a string, Yaaaaaa
510  */
511 void JobList::consoleListJobid()
512 {
513    QString cmd("list jobid=");
514    cmd += m_currentJob;
515    if (mainWin->m_longList) { cmd.prepend("l"); }
516    consoleCommand(cmd);
517 }
518 void JobList::consoleListFilesOnJob()
519 {
520    QString cmd("list files jobid=");
521    cmd += m_currentJob;
522    if (mainWin->m_longList) { cmd.prepend("l"); }
523    consoleCommand(cmd);
524 }
525 void JobList::consoleListJobMedia()
526 {
527    QString cmd("list jobmedia jobid=");
528    cmd += m_currentJob;
529    if (mainWin->m_longList) { cmd.prepend("l"); }
530    consoleCommand(cmd);
531 }
532 void JobList::consoleListVolumes()
533 {
534    QString cmd("list volumes jobid=");
535    cmd += m_currentJob;
536    if (mainWin->m_longList) { cmd.prepend("l"); }
537    consoleCommand(cmd);
538 }
539 void JobList::consoleListJobTotals()
540 {
541    QString cmd("list jobtotals");
542    if (mainWin->m_longList) { cmd.prepend("l"); }
543    consoleCommand(cmd);
544 }
545 void JobList::consoleDeleteJob()
546 {
547    if (QMessageBox::warning(this, "Bat",
548       tr("Are you sure you want to delete??  !!!.\n"
549 "This delete command is used to delete a Job record and all associated catalog"
550 " records that were created. This command operates only on the Catalog"
551 " database and has no effect on the actual data written to a Volume. This"
552 " command can be dangerous and we strongly recommend that you do not use"
553 " it unless you know what you are doing.  The Job and all its associated"
554 " records (File and JobMedia) will be deleted from the catalog."
555       "Press OK to proceed with delete operation.?"),
556       QMessageBox::Ok | QMessageBox::Cancel)
557       == QMessageBox::Cancel) { return; }
558
559    QString cmd("delete job jobid=");
560    cmd += m_selectedJobs;
561    consoleCommand(cmd);
562 }
563 void JobList::consolePurgeFiles()
564 {
565    if (QMessageBox::warning(this, "Bat",
566       tr("Are you sure you want to purge ??  !!!.\n"
567 "The Purge command will delete associated Catalog database records from Jobs and"
568 " Volumes without considering the retention period. Purge  works only on the"
569 " Catalog database and does not affect data written to Volumes. This command can"
570 " be dangerous because you can delete catalog records associated with current"
571 " backups of files, and we recommend that you do not use it unless you know what"
572 " you are doing.\n"
573       "Press OK to proceed with the purge operation?"),
574       QMessageBox::Ok | QMessageBox::Cancel)
575       == QMessageBox::Cancel) { return; }
576
577    QString cmd("purge files jobid=");
578    cmd += m_currentJob;
579    consoleCommand(cmd);
580 }
581
582 /*
583  * Subroutine to call preRestore to restore from a select job
584  */
585 void JobList::preRestoreFromJob()
586 {
587    new prerestorePage(m_currentJob, R_JOBIDLIST);
588 }
589
590 /*
591  * Subroutine to call preRestore to restore from a select job
592  */
593 void JobList::preRestoreFromTime()
594 {
595    new prerestorePage(m_currentJob, R_JOBDATETIME);
596 }
597
598 /*
599  * Subroutine to call class to show the log in the database from that job
600  */
601 void JobList::showLogForJob()
602 {
603    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
604    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
605 }
606
607 /*
608  * Cancel a running job
609  */
610 void JobList::consoleCancelJob()
611 {
612    QString cmd("cancel jobid=");
613    cmd += m_currentJob;
614    consoleCommand(cmd);
615 }
616
617 /*
618  * Graph this table
619  */
620 #ifdef HAVE_QWT
621 void JobList::graphTable()
622 {
623    JobPlotPass pass;
624    pass.recordLimitCheck = limitCheckBox->checkState();
625    pass.daysLimitCheck = daysCheckBox->checkState();
626    pass.recordLimitSpin = limitSpinBox->value();
627    pass.daysLimitSpin = daysSpinBox->value();
628    pass.jobCombo = jobComboBox->currentText();
629    pass.clientCombo = clientComboBox->currentText();
630    pass.volumeCombo = volumeComboBox->currentText();
631    pass.fileSetCombo = fileSetComboBox->currentText();
632    pass.purgedCombo = purgedComboBox->currentText();
633    pass.levelCombo = levelComboBox->currentText();
634    pass.statusCombo = statusComboBox->currentText();
635    pass.use = true;
636    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
637    new JobPlot(pageSelectorTreeWidgetItem, pass);
638 }
639 #endif
640
641 /*
642  * Save user settings associated with this page
643  */
644 void JobList::writeSettings()
645 {
646    QSettings settings(m_console->m_dir->name(), "bat");
647    settings.beginGroup(m_groupText);
648    settings.setValue(m_splitText, m_splitter->saveState());
649    settings.endGroup();
650 }
651
652 /*
653  * Read and restore user settings associated with this page
654  */
655 void JobList::readSettings()
656 {
657    m_groupText = "JobListPage";
658    m_splitText = "splitterSizes_1";
659    QSettings settings(m_console->m_dir->name(), "bat");
660    settings.beginGroup(m_groupText);
661    m_splitter->restoreState(settings.value(m_splitText).toByteArray());
662    settings.endGroup();
663 }
664
665 /*
666  * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
667  */
668 void JobList::selectedJobsGet()
669 {
670    QList<int> rowList;
671    QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
672    foreach (QTableWidgetItem *sitem, sitems) {
673       int row = sitem->row();
674       if (!rowList.contains(row)) {
675          rowList.append(row);
676       }
677    }
678
679    m_selectedJobs = "";
680    bool first = true;
681    foreach(int row, rowList) {
682       QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
683       if (!first) m_selectedJobs.append(",");
684       else first = false;
685       m_selectedJobs.append(sitem->text());
686    }
687    m_selectedJobsCount = rowList.count();
688    if (m_selectedJobsCount > 1) {
689      QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
690        actionDeleteJob->setText(text);
691    } else {
692      actionDeleteJob->setText(tr("Delete Single Job"));
693    }
694 }