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