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