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