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