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