]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
bat: fix compiler warning for unreferenced argument
[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(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
425    connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
426    connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
427    connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
428    connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
429    connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
430    connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
431    connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
432    connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
433
434    m_contextActions.append(actionRefreshJobList);
435    m_contextActions.append(actionListJobTotals);
436 }
437
438 /*
439  * Functions to respond to local context sensitive menu sending console commands
440  * If I could figure out how to make these one function passing a string, Yaaaaaa
441  */
442 void JobList::consoleListFilesOnJob()
443 {
444    QString cmd("list files jobid=");
445    cmd += m_currentJob;
446    if (mainWin->m_longList) { cmd.prepend("l"); }
447    consoleCommand(cmd);
448 }
449 void JobList::consoleListJobMedia()
450 {
451    QString cmd("list jobmedia jobid=");
452    cmd += m_currentJob;
453    if (mainWin->m_longList) { cmd.prepend("l"); }
454    consoleCommand(cmd);
455 }
456
457 void JobList::consoleListJobTotals()
458 {
459    QString cmd("list jobtotals");
460    if (mainWin->m_longList) { cmd.prepend("l"); }
461    consoleCommand(cmd);
462 }
463 void JobList::consoleDeleteJob()
464 {
465    if (QMessageBox::warning(this, "Bat",
466       tr("Are you sure you want to delete??  !!!.\n"
467 "This delete command is used to delete a Job record and all associated catalog"
468 " records that were created. This command operates only on the Catalog"
469 " database and has no effect on the actual data written to a Volume. This"
470 " command can be dangerous and we strongly recommend that you do not use"
471 " it unless you know what you are doing.  The Job and all its associated"
472 " records (File and JobMedia) will be deleted from the catalog."
473       "Press OK to proceed with delete operation.?"),
474       QMessageBox::Ok | QMessageBox::Cancel)
475       == QMessageBox::Cancel) { return; }
476
477    QString cmd("delete job jobid=");
478    cmd += m_selectedJobs;
479    consoleCommand(cmd, false);
480    populateTable();
481 }
482 void JobList::consolePurgeFiles()
483 {
484    if (QMessageBox::warning(this, "Bat",
485       tr("Are you sure you want to purge ??  !!!.\n"
486 "The Purge command will delete associated Catalog database records from Jobs and"
487 " Volumes without considering the retention period. Purge  works only on the"
488 " Catalog database and does not affect data written to Volumes. This command can"
489 " be dangerous because you can delete catalog records associated with current"
490 " backups of files, and we recommend that you do not use it unless you know what"
491 " you are doing.\n"
492       "Press OK to proceed with the purge operation?"),
493       QMessageBox::Ok | QMessageBox::Cancel)
494       == QMessageBox::Cancel) { return; }
495
496    m_console->m_warningPrevent = true;
497    foreach(QString job, m_selectedJobsList) {
498       QString cmd("purge files jobid=");
499       cmd += job;
500       consoleCommand(cmd, false);
501    }
502    m_console->m_warningPrevent = false;
503    populateTable();
504 }
505
506 /*
507  * Subroutine to call preRestore to restore from a select job
508  */
509 void JobList::preRestoreFromJob()
510 {
511    new prerestorePage(m_currentJob, R_JOBIDLIST);
512 }
513
514 /*
515  * Subroutine to call preRestore to restore from a select job
516  */
517 void JobList::preRestoreFromTime()
518 {
519    new prerestorePage(m_currentJob, R_JOBDATETIME);
520 }
521
522 /*
523  * Subroutine to call class to show the log in the database from that job
524  */
525 void JobList::showLogForJob()
526 {
527    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
528    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
529 }
530
531 /*
532  * Subroutine to call class to show the log in the database from that job
533  */
534 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
535 {
536    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
537    new Job(m_currentJob, pageSelectorTreeWidgetItem);
538 }
539
540 /*
541  * Cancel a running job
542  */
543 void JobList::consoleCancelJob()
544 {
545    QString cmd("cancel jobid=");
546    cmd += m_currentJob;
547    consoleCommand(cmd);
548 }
549
550 /*
551  * Graph this table
552  */
553 void JobList::graphTable()
554 {
555 #ifdef HAVE_QWT
556    JobPlotPass pass;
557    pass.recordLimitCheck = limitCheckBox->checkState();
558    pass.daysLimitCheck = daysCheckBox->checkState();
559    pass.recordLimitSpin = limitSpinBox->value();
560    pass.daysLimitSpin = daysSpinBox->value();
561    pass.jobCombo = jobComboBox->currentText();
562    pass.clientCombo = clientComboBox->currentText();
563    pass.volumeCombo = volumeComboBox->currentText();
564    pass.fileSetCombo = fileSetComboBox->currentText();
565    pass.purgedCombo = purgedComboBox->currentText();
566    pass.levelCombo = levelComboBox->currentText();
567    pass.statusCombo = statusComboBox->currentText();
568    pass.use = true;
569    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
570    new JobPlot(pageSelectorTreeWidgetItem, pass);
571 #endif
572 }
573
574 /*
575  * Save user settings associated with this page
576  */
577 void JobList::writeSettings()
578 {
579    QSettings settings(m_console->m_dir->name(), "bat");
580    settings.beginGroup(m_groupText);
581    settings.setValue(m_splitText, m_splitter->saveState());
582    settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
583    settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
584    settings.endGroup();
585 }
586
587 /*
588  * Read and restore user settings associated with this page
589  */
590 void JobList::readSettings()
591 {
592    m_groupText = "JobListPage";
593    m_splitText = "splitterSizes_2";
594    QSettings settings(m_console->m_dir->name(), "bat");
595    settings.beginGroup(m_groupText);
596    if (settings.contains(m_splitText)) {
597       m_splitter->restoreState(settings.value(m_splitText).toByteArray());
598    }
599    filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
600    filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
601    settings.endGroup();
602 }
603
604 /*
605  * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
606  */
607 void JobList::selectionChanged()
608 {
609    QList<int> rowList;
610    QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
611    foreach (QTableWidgetItem *sitem, sitems) {
612       int row = sitem->row();
613       if (!rowList.contains(row)) {
614          rowList.append(row);
615       }
616    }
617
618    m_selectedJobs = "";
619    m_selectedJobsList.clear();
620    bool first = true;
621    foreach(int row, rowList) {
622       QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
623       if (!first) m_selectedJobs.append(",");
624       else first = false;
625       m_selectedJobs.append(sitem->text());
626       m_selectedJobsList.append(sitem->text());
627    }
628    m_selectedJobsCount = rowList.count();
629    if (m_selectedJobsCount > 1) {
630       QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
631       actionDeleteJob->setText(text);
632       text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
633       actionPurgeFiles->setText(text);
634    } else {
635       actionDeleteJob->setText(tr("Delete Single Job"));
636       actionPurgeFiles->setText(tr("Purge Files from single job"));
637    }
638
639    /* remove all actions */
640    foreach(QAction* mediaAction, mp_tableWidget->actions()) {
641       mp_tableWidget->removeAction(mediaAction);
642    }
643
644    /* Add Actions */
645    mp_tableWidget->addAction(actionRefreshJobList);
646    if (m_selectedJobsCount == 1) {
647       mp_tableWidget->addAction(actionListFilesOnJob);
648       mp_tableWidget->addAction(actionListJobMedia);
649       mp_tableWidget->addAction(actionRestoreFromJob);
650       mp_tableWidget->addAction(actionRestoreFromTime);
651       mp_tableWidget->addAction(actionShowLogForJob);
652       mp_tableWidget->addAction(actionShowInfoForJob);
653    }
654    if (m_selectedJobsCount >= 1) {
655       mp_tableWidget->addAction(actionDeleteJob);
656       mp_tableWidget->addAction(actionPurgeFiles);
657    }
658
659    /* Make Connections */
660    if (m_checkCurrentWidget) {
661       int row = mp_tableWidget->currentRow();
662       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
663       m_currentJob = jobitem->text();
664
665       /* include purged action or not */
666       jobitem = mp_tableWidget->item(row, m_purgedIndex);
667       QString purged = jobitem->text();
668 /*      mp_tableWidget->removeAction(actionPurgeFiles);
669       if (purged == tr("No") ) {
670          mp_tableWidget->addAction(actionPurgeFiles);
671       }*/
672       /* include restore from time and job action or not */
673       jobitem = mp_tableWidget->item(row, m_typeIndex);
674       QString type = jobitem->text();
675       if (m_selectedJobsCount == 1) {
676          mp_tableWidget->removeAction(actionRestoreFromJob);
677          mp_tableWidget->removeAction(actionRestoreFromTime);
678          if (type == tr("Backup")) {
679             mp_tableWidget->addAction(actionRestoreFromJob);
680             mp_tableWidget->addAction(actionRestoreFromTime);
681          }
682       }
683       /* include cancel action or not */
684       jobitem = mp_tableWidget->item(row, m_statusIndex);
685       QString status = jobitem->text();
686       mp_tableWidget->removeAction(actionCancelJob);
687       if (status == tr("Running") || status == tr("Created, not yet running")) {
688          mp_tableWidget->addAction(actionCancelJob);
689       }
690    }
691 }
692
693 /*
694  *  Function to prevent the splitter from making index 0 of the size larger than it
695  *  needs to be
696  */
697 void JobList::splitterMoved(int /*pos*/, int /*index*/)
698 {
699    int frameMax = frame->maximumHeight();
700    QList<int> sizes = m_splitter->sizes();
701    int sizeSum = 0;
702    foreach(int size, sizes) { sizeSum += size; }
703    if (sizes[0] > frameMax) {
704       sizes[0] = frameMax;
705       sizes[1] = sizeSum - frameMax;
706       m_splitter->setSizes(sizes);
707    }
708 }