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