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