]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
Riccardo' patch for formatting text.
[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->setSelectionBehavior(QAbstractItemView::SelectRows);
141    mp_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
142
143    if (mainWin->m_sqlDebug) {
144       Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
145    }
146
147    QStringList results;
148    if (m_console->sql_cmd(query, results)) {
149       m_resultCount = results.count();
150
151       QStringList fieldlist;
152       mp_tableWidget->setRowCount(results.size());
153
154       int row = 0;
155       /* Iterate through the record returned from the query */
156       QString resultline;
157       foreach (resultline, results) {
158          fieldlist = resultline.split("\t");
159          if (fieldlist.size() < 12)
160             continue; // some fields missing, ignore row
161
162          TableItemFormatter jobitem(*mp_tableWidget, row);
163   
164          /* Iterate through fields in the record */
165          QStringListIterator fld(fieldlist);
166          int col = 0;
167
168          /* job id */
169          jobitem.setNumericFld(col++, fld.next());
170
171          /* job name */
172          jobitem.setTextFld(col++, fld.next());
173
174          /* client */
175          jobitem.setTextFld(col++, fld.next());
176
177          /* job starttime */
178          jobitem.setTextFld(col++, fld.next(), true);
179
180          /* job type */
181          jobitem.setJobTypeFld(col++, fld.next());
182
183          /* job level */
184          jobitem.setJobLevelFld(col++, fld.next());
185
186          /* job files */
187          jobitem.setNumericFld(col++, fld.next());
188
189          /* job bytes */
190          jobitem.setBytesFld(col++, fld.next());
191
192          /* job status */
193          QString shortstatus(fld.next());
194          QString longstatus(fld.next());
195          jobitem.setJobStatusFld(col++, shortstatus, longstatus);
196
197          /* purged */
198          if (fld.next().toInt())
199             jobitem.setTextFld(col++, tr("IS"), true);
200          else
201             jobitem.setTextFld(col++, tr("NOT"), true);
202
203          /* fileset */
204          jobitem.setTextFld(col++, fld.next());
205
206          row++;
207       }
208    } 
209    /* Resize the columns */
210    mp_tableWidget->resizeColumnsToContents();
211    mp_tableWidget->resizeRowsToContents();
212    mp_tableWidget->verticalHeader()->hide();
213    if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
214       /* for context sensitive searches, let the user know if there were no
215        * results */
216       QMessageBox::warning(this, "Bat",
217           tr("The Jobs query returned no results.\n"
218          "Press OK to continue?"), QMessageBox::Ok );
219    }
220 }
221
222 void JobList::prepareFilterWidgets()
223 {
224    if (!m_populated) {
225       clientComboBox->addItem(tr("Any"));
226       clientComboBox->addItems(m_console->client_list);
227       int clientIndex = clientComboBox->findText(m_clientName, Qt::MatchExactly);
228       if (clientIndex != -1)
229          clientComboBox->setCurrentIndex(clientIndex);
230
231       QStringList volumeList;
232       m_console->getVolumeList(volumeList);
233       volumeComboBox->addItem(tr("Any"));
234       volumeComboBox->addItems(volumeList);
235       int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
236       if (volumeIndex != -1) {
237          volumeComboBox->setCurrentIndex(volumeIndex);
238       }
239       jobComboBox->addItem(tr("Any"));
240       jobComboBox->addItems(m_console->job_list);
241       int jobIndex = jobComboBox->findText(m_jobName, Qt::MatchExactly);
242       if (jobIndex != -1) {
243          jobComboBox->setCurrentIndex(jobIndex);
244       }
245       levelComboBox->addItem(tr("Any"));
246       levelComboBox->addItems( QStringList() << "F" << "D" << "I");
247       purgedComboBox->addItem(tr("Any"));
248       purgedComboBox->addItems( QStringList() << "0" << "1");
249       fileSetComboBox->addItem(tr("Any"));
250       fileSetComboBox->addItems(m_console->fileset_list);
251       int filesetIndex = fileSetComboBox->findText(m_filesetName, Qt::MatchExactly);
252       if (filesetIndex != -1) {
253          fileSetComboBox->setCurrentIndex(filesetIndex);
254       }
255       QStringList statusLongList;
256       m_console->getStatusList(statusLongList);
257       statusComboBox->addItem(tr("Any"));
258       statusComboBox->addItems(statusLongList);
259    }
260 }
261
262 void JobList::fillQueryString(QString &query)
263 {
264    query = "";
265    int volumeIndex = volumeComboBox->currentIndex();
266    if (volumeIndex != -1)
267       m_mediaName = volumeComboBox->itemText(volumeIndex);
268    QString distinct = "";
269    if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
270    query += "SELECT " + distinct + "Job.Jobid AS Id, Job.Name AS JobName, " 
271             " Client.Name AS Client,"
272             " Job.Starttime AS JobStart, Job.Type AS JobType,"
273             " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
274             " Job.JobBytes AS Bytes,"
275             " Job.JobStatus AS Status, Status.JobStatusLong AS StatusLong,"
276             " Job.PurgedFiles AS Purged, FileSet.FileSet"
277             " FROM Job"
278             " JOIN Client ON (Client.ClientId=Job.ClientId)"
279             " JOIN Status ON (Job.JobStatus=Status.JobStatus)"
280             " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) ";
281    QStringList conditions;
282    if (m_mediaName != tr("Any")) {
283       query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
284                " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
285       conditions.append("Media.VolumeName='" + m_mediaName + "'");
286    }
287    int clientIndex = clientComboBox->currentIndex();
288    if (clientIndex != -1)
289       m_clientName = clientComboBox->itemText(clientIndex);
290    if (m_clientName != tr("Any")) {
291       conditions.append("Client.Name='" + m_clientName + "'");
292    }
293    int jobIndex = jobComboBox->currentIndex();
294    if (jobIndex != -1)
295       m_jobName = jobComboBox->itemText(jobIndex);
296    if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != tr("Any"))) {
297       conditions.append("Job.Name='" + jobComboBox->itemText(jobIndex) + "'");
298    }
299    int levelIndex = levelComboBox->currentIndex();
300    if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != tr("Any"))) {
301       conditions.append("Job.Level='" + levelComboBox->itemText(levelIndex) + "'");
302    }
303    int statusIndex = statusComboBox->currentIndex();
304    if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != tr("Any"))) {
305       conditions.append("Status.JobStatusLong='" + statusComboBox->itemText(statusIndex) + "'");
306    }
307    int purgedIndex = purgedComboBox->currentIndex();
308    if ((purgedIndex != -1) && (purgedComboBox->itemText(purgedIndex) != tr("Any"))) {
309       conditions.append("Job.PurgedFiles='" + purgedComboBox->itemText(purgedIndex) + "'");
310    }
311    int fileSetIndex = fileSetComboBox->currentIndex();
312    if (fileSetIndex != -1)
313       m_filesetName = fileSetComboBox->itemText(fileSetIndex);
314    if ((fileSetIndex != -1) && (fileSetComboBox->itemText(fileSetIndex) != tr("Any"))) {
315       conditions.append("FileSet.FileSet='" + fileSetComboBox->itemText(fileSetIndex) + "'");
316    }
317    /* If Limit check box For limit by days is checked  */
318    if (daysCheckBox->checkState() == Qt::Checked) {
319       QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
320       QString since = stamp.toString(Qt::ISODate);
321       conditions.append("Job.Starttime>'" + since + "'");
322    }
323    bool first = true;
324    foreach (QString condition, conditions) {
325       if (first) {
326          query += " WHERE " + condition;
327          first = false;
328       } else {
329          query += " AND " + condition;
330       }
331    }
332    /* Descending */
333    query += " ORDER BY Job.Starttime=0 DESC, Job.Starttime DESC, Job.JobId DESC";
334    /* If Limit check box for limit records returned is checked  */
335    if (limitCheckBox->checkState() == Qt::Checked) {
336       QString limit;
337       limit.setNum(limitSpinBox->value());
338       query += " LIMIT " + limit;
339    }
340 }
341
342 /*
343  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
344  * The tree has been populated.
345  */
346 void JobList::PgSeltreeWidgetClicked()
347 {
348    if (!m_populated) {
349       populateTable();
350       m_populated=true;
351    }
352 }
353
354 /*
355  *  Virtual function override of pages function which is called when this page
356  *  is visible on the stack
357  */
358 void JobList::currentStackItem()
359 {
360    populateTable();
361    if (!m_populated) {
362       m_populated=true;
363    }
364 }
365
366 /*
367  * Virtual Function to return the name for the medialist tree widget
368  */
369 void JobList::treeWidgetName(QString &desc)
370 {
371    if ((m_mediaName == "") && (m_clientName == "") && (m_jobName == "") && (m_filesetName == "")) {
372       desc = "JobList";
373    } else {
374       desc = "JobList ";
375       if (m_mediaName != "" ) {
376          desc += "of Volume " + m_mediaName;
377       }
378       if (m_clientName != "" ) {
379          desc += "of Client " + m_clientName;
380       }
381       if (m_jobName != "" ) {
382          desc += "of Job " + m_jobName;
383       }
384       if (m_filesetName != "" ) {
385          desc += "of fileset " + m_filesetName;
386       }
387    }
388 }
389
390 /*
391  * This functions much line tableItemChanged for trees like the page selector,
392  * but I will do much less here
393  */
394 void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/)
395 {
396    if (m_checkCurrentWidget) {
397       int row = currentItem->row();
398       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
399       m_currentJob = jobitem->text();
400       selectedJobsGet();
401
402       /* include purged action or not */
403       jobitem = mp_tableWidget->item(row, m_purgedIndex);
404       QString purged = jobitem->text();
405       mp_tableWidget->removeAction(actionPurgeFiles);
406       if (purged == "NOT") {
407          mp_tableWidget->addAction(actionPurgeFiles);
408       }
409       /* include restore from time and job action or not */
410       jobitem = mp_tableWidget->item(row, m_typeIndex);
411       QString type = jobitem->text();
412       mp_tableWidget->removeAction(actionRestoreFromJob);
413       mp_tableWidget->removeAction(actionRestoreFromTime);
414       if (type == "Backup") {
415          mp_tableWidget->addAction(actionRestoreFromJob);
416          mp_tableWidget->addAction(actionRestoreFromTime);
417       }
418       /* include cancel action or not */
419       jobitem = mp_tableWidget->item(row, m_statusIndex);
420       QString status = jobitem->text();
421       mp_tableWidget->removeAction(actionCancelJob);
422       if (status == "Running") {
423          mp_tableWidget->addAction(actionCancelJob);
424       }
425    }
426 }
427
428 /*
429  * Function to create connections for context sensitive menu for this and
430  * the page selector
431  */
432 void JobList::createConnections()
433 {
434    /* connect to the action specific to this pages class that shows up in the 
435     * page selector tree */
436    connect(actionRefreshJobList, SIGNAL(triggered()), this,
437                 SLOT(populateTable()));
438    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
439 #ifdef HAVE_QWT
440    connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
441 #else
442    graphButton->setEnabled(false);
443 #endif
444    /* for the tableItemChanged to maintain m_currentJob */
445    connect(mp_tableWidget, SIGNAL(
446            currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
447            this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
448
449    /* Do what is required for the local context sensitive menu */
450
451
452    /* setContextMenuPolicy is required */
453    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
454
455    /* Add Actions */
456    mp_tableWidget->addAction(actionRefreshJobList);
457    mp_tableWidget->addAction(actionListJobid);
458    mp_tableWidget->addAction(actionListFilesOnJob);
459    mp_tableWidget->addAction(actionListJobMedia);
460    mp_tableWidget->addAction(actionListVolumes);
461    mp_tableWidget->addAction(actionDeleteJob);
462    mp_tableWidget->addAction(actionPurgeFiles);
463    mp_tableWidget->addAction(actionRestoreFromJob);
464    mp_tableWidget->addAction(actionRestoreFromTime);
465    mp_tableWidget->addAction(actionShowLogForJob);
466
467    /* Make Connections */
468    connect(actionListJobid, SIGNAL(triggered()), this,
469                 SLOT(consoleListJobid()));
470    connect(actionListFilesOnJob, SIGNAL(triggered()), this,
471                 SLOT(consoleListFilesOnJob()));
472    connect(actionListJobMedia, SIGNAL(triggered()), this,
473                 SLOT(consoleListJobMedia()));
474    connect(actionListVolumes, SIGNAL(triggered()), this,
475                 SLOT(consoleListVolumes()));
476    connect(actionDeleteJob, SIGNAL(triggered()), this,
477                 SLOT(consoleDeleteJob()));
478    connect(actionPurgeFiles, SIGNAL(triggered()), this,
479                 SLOT(consolePurgeFiles()));
480    connect(actionRestoreFromJob, SIGNAL(triggered()), this,
481                 SLOT(preRestoreFromJob()));
482    connect(actionRestoreFromTime, SIGNAL(triggered()), this,
483                 SLOT(preRestoreFromTime()));
484    connect(actionShowLogForJob, SIGNAL(triggered()), this,
485                 SLOT(showLogForJob()));
486    connect(actionCancelJob, SIGNAL(triggered()), this,
487                 SLOT(consoleCancelJob()));
488    connect(actionListJobTotals, SIGNAL(triggered()), this,
489                 SLOT(consoleListJobTotals()));
490
491    m_contextActions.append(actionRefreshJobList);
492    m_contextActions.append(actionListJobTotals);
493 }
494
495 /*
496  * Functions to respond to local context sensitive menu sending console commands
497  * If I could figure out how to make these one function passing a string, Yaaaaaa
498  */
499 void JobList::consoleListJobid()
500 {
501    QString cmd("list jobid=");
502    cmd += m_currentJob;
503    if (mainWin->m_longList) { cmd.prepend("l"); }
504    consoleCommand(cmd);
505 }
506 void JobList::consoleListFilesOnJob()
507 {
508    QString cmd("list files jobid=");
509    cmd += m_currentJob;
510    if (mainWin->m_longList) { cmd.prepend("l"); }
511    consoleCommand(cmd);
512 }
513 void JobList::consoleListJobMedia()
514 {
515    QString cmd("list jobmedia jobid=");
516    cmd += m_currentJob;
517    if (mainWin->m_longList) { cmd.prepend("l"); }
518    consoleCommand(cmd);
519 }
520 void JobList::consoleListVolumes()
521 {
522    QString cmd("list volumes jobid=");
523    cmd += m_currentJob;
524    if (mainWin->m_longList) { cmd.prepend("l"); }
525    consoleCommand(cmd);
526 }
527 void JobList::consoleListJobTotals()
528 {
529    QString cmd("list jobtotals");
530    if (mainWin->m_longList) { cmd.prepend("l"); }
531    consoleCommand(cmd);
532 }
533 void JobList::consoleDeleteJob()
534 {
535    if (QMessageBox::warning(this, "Bat",
536       tr("Are you sure you want to delete??  !!!.\n"
537 "This delete command is used to delete a Job record and all associated catalog"
538 " records that were created. This command operates only on the Catalog"
539 " database and has no effect on the actual data written to a Volume. This"
540 " command can be dangerous and we strongly recommend that you do not use"
541 " it unless you know what you are doing.  The Job and all its associated"
542 " records (File and JobMedia) will be deleted from the catalog."
543       "Press OK to proceed with delete operation.?"),
544       QMessageBox::Ok | QMessageBox::Cancel)
545       == QMessageBox::Cancel) { return; }
546
547    QString cmd("delete job jobid=");
548    cmd += m_selectedJobs;
549    consoleCommand(cmd);
550 }
551 void JobList::consolePurgeFiles()
552 {
553    if (QMessageBox::warning(this, "Bat",
554       tr("Are you sure you want to purge ??  !!!.\n"
555 "The Purge command will delete associated Catalog database records from Jobs and"
556 " Volumes without considering the retention period. Purge  works only on the"
557 " Catalog database and does not affect data written to Volumes. This command can"
558 " be dangerous because you can delete catalog records associated with current"
559 " backups of files, and we recommend that you do not use it unless you know what"
560 " you are doing.\n"
561       "Press OK to proceed with the purge operation?"),
562       QMessageBox::Ok | QMessageBox::Cancel)
563       == QMessageBox::Cancel) { return; }
564
565    QString cmd("purge files jobid=");
566    cmd += m_currentJob;
567    consoleCommand(cmd);
568 }
569
570 /*
571  * Subroutine to call preRestore to restore from a select job
572  */
573 void JobList::preRestoreFromJob()
574 {
575    new prerestorePage(m_currentJob, R_JOBIDLIST);
576 }
577
578 /*
579  * Subroutine to call preRestore to restore from a select job
580  */
581 void JobList::preRestoreFromTime()
582 {
583    new prerestorePage(m_currentJob, R_JOBDATETIME);
584 }
585
586 /*
587  * Subroutine to call class to show the log in the database from that job
588  */
589 void JobList::showLogForJob()
590 {
591    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
592    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
593 }
594
595 /*
596  * Cancel a running job
597  */
598 void JobList::consoleCancelJob()
599 {
600    QString cmd("cancel jobid=");
601    cmd += m_currentJob;
602    consoleCommand(cmd);
603 }
604
605 /*
606  * Graph this table
607  */
608 #ifdef HAVE_QWT
609 void JobList::graphTable()
610 {
611    JobPlotPass pass;
612    pass.recordLimitCheck = limitCheckBox->checkState();
613    pass.daysLimitCheck = daysCheckBox->checkState();
614    pass.recordLimitSpin = limitSpinBox->value();
615    pass.daysLimitSpin = daysSpinBox->value();
616    pass.jobCombo = jobComboBox->currentText();
617    pass.clientCombo = clientComboBox->currentText();
618    pass.volumeCombo = volumeComboBox->currentText();
619    pass.fileSetCombo = fileSetComboBox->currentText();
620    pass.purgedCombo = purgedComboBox->currentText();
621    pass.levelCombo = levelComboBox->currentText();
622    pass.statusCombo = statusComboBox->currentText();
623    pass.use = true;
624    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
625    new JobPlot(pageSelectorTreeWidgetItem, pass);
626 }
627 #endif
628
629 /*
630  * Save user settings associated with this page
631  */
632 void JobList::writeSettings()
633 {
634    QSettings settings(m_console->m_dir->name(), "bat");
635    settings.beginGroup(m_groupText);
636    settings.setValue(m_splitText, m_splitter->saveState());
637    settings.endGroup();
638 }
639
640 /*
641  * Read and restore user settings associated with this page
642  */
643 void JobList::readSettings()
644 {
645    m_groupText = "JobListPage";
646    m_splitText = "splitterSizes_1";
647    QSettings settings(m_console->m_dir->name(), "bat");
648    settings.beginGroup(m_groupText);
649    m_splitter->restoreState(settings.value(m_splitText).toByteArray());
650    settings.endGroup();
651 }
652
653 /*
654  * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
655  */
656 void JobList::selectedJobsGet()
657 {
658    QList<int> rowList;
659    QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
660    foreach (QTableWidgetItem *sitem, sitems) {
661       int row = sitem->row();
662       if (!rowList.contains(row)) {
663          rowList.append(row);
664       }
665    }
666
667    m_selectedJobs = "";
668    bool first = true;
669    foreach(int row, rowList) {
670       QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
671       if (!first) m_selectedJobs.append(",");
672       else first = false;
673       m_selectedJobs.append(sitem->text());
674    }
675    m_selectedJobsCount = rowList.count();
676    if (m_selectedJobsCount > 1) {
677       QString text = QString("Delete list of %1 Jobs").arg(m_selectedJobsCount);
678       actionDeleteJob->setText(text);
679    } else {
680       actionDeleteJob->setText("Delete Single Job");
681    }
682 }