]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
Correct a misspelling in a relatively trivial spot.
[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 "joblog/joblog.h"
40 #ifdef HAVE_QWT
41 #include "jobgraphs/jobplot.h"
42 #endif
43 #include "util/fmtwidgetitem.h"
44 #include "util/comboutil.h"
45
46 /*
47  * Constructor for the class
48  */
49 JobList::JobList(const QString &mediaName, const QString &clientName,
50           const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
51 {
52    setupUi(this);
53    m_name = ""; /* treeWidgetName has a virtual override in this class */
54    m_mediaName = mediaName;
55    m_clientName = clientName;
56    m_jobName = jobName;
57    m_filesetName = filesetName;
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    m_checkCurrentWidget = true;
69    createConnections();
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    dockPage();
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(mp_tableWidget);
89    m_splitter->addWidget(area);
90
91    gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
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    }
352 }
353
354 /*
355  *  Virtual function override of pages function which is called when this page
356  *  is visible on the stack
357  */
358 void JobList::currentStackItem()
359 {
360 /*   if (!m_populated) populate every time user comes back to this object */
361       populateTable();
362 }
363
364 /*
365  * Virtual Function to return the name for the medialist tree widget
366  */
367 void JobList::treeWidgetName(QString &desc)
368 {
369    if (m_mediaName != "" ) {
370      desc = tr("JobList of Volume %1").arg(m_mediaName);
371    } else if (m_clientName != "" ) {
372      desc = tr("JobList of Client %1").arg(m_clientName);
373    } else if (m_jobName != "" ) {
374      desc = tr("JobList of Job %1").arg(m_jobName);
375    } else if (m_filesetName != "" ) {
376      desc = tr("JobList of fileset %1").arg(m_filesetName);
377    } else {
378      desc = tr("JobList");
379    }
380 }
381
382 /*
383  * Function to create connections for context sensitive menu for this and
384  * the page selector
385  */
386 void JobList::createConnections()
387 {
388    /* connect to the action specific to this pages class that shows up in the 
389     * page selector tree */
390    connect(actionRefreshJobList, SIGNAL(triggered()), this,
391                 SLOT(populateTable()));
392    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
393 #ifdef HAVE_QWT
394    connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
395 #else
396    graphButton->setEnabled(false);
397    graphButton->setVisible(false);
398 #endif
399    /* for the selectionChanged to maintain m_currentJob and a delete selection */
400    connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
401
402    /* Do what is required for the local context sensitive menu */
403
404
405    /* setContextMenuPolicy is required */
406    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
407
408    connect(actionListJobid, SIGNAL(triggered()), this,
409                 SLOT(consoleListJobid()));
410    connect(actionListFilesOnJob, SIGNAL(triggered()), this,
411                 SLOT(consoleListFilesOnJob()));
412    connect(actionListJobMedia, SIGNAL(triggered()), this,
413                 SLOT(consoleListJobMedia()));
414    connect(actionListVolumes, SIGNAL(triggered()), this,
415                 SLOT(consoleListVolumes()));
416    connect(actionDeleteJob, SIGNAL(triggered()), this,
417                 SLOT(consoleDeleteJob()));
418    connect(actionPurgeFiles, SIGNAL(triggered()), this,
419                 SLOT(consolePurgeFiles()));
420    connect(actionRestoreFromJob, SIGNAL(triggered()), this,
421                 SLOT(preRestoreFromJob()));
422    connect(actionRestoreFromTime, SIGNAL(triggered()), this,
423                 SLOT(preRestoreFromTime()));
424    connect(actionShowLogForJob, SIGNAL(triggered()), this,
425                 SLOT(showLogForJob()));
426    connect(actionCancelJob, SIGNAL(triggered()), this,
427                 SLOT(consoleCancelJob()));
428    connect(actionListJobTotals, SIGNAL(triggered()), this,
429                 SLOT(consoleListJobTotals()));
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::consoleListJobid()
440 {
441    QString cmd("list jobid=");
442    cmd += m_currentJob;
443    if (mainWin->m_longList) { cmd.prepend("l"); }
444    consoleCommand(cmd);
445 }
446 void JobList::consoleListFilesOnJob()
447 {
448    QString cmd("list files jobid=");
449    cmd += m_currentJob;
450    if (mainWin->m_longList) { cmd.prepend("l"); }
451    consoleCommand(cmd);
452 }
453 void JobList::consoleListJobMedia()
454 {
455    QString cmd("list jobmedia jobid=");
456    cmd += m_currentJob;
457    if (mainWin->m_longList) { cmd.prepend("l"); }
458    consoleCommand(cmd);
459 }
460 void JobList::consoleListVolumes()
461 {
462    QString cmd("list volumes jobid=");
463    cmd += m_currentJob;
464    if (mainWin->m_longList) { cmd.prepend("l"); }
465    consoleCommand(cmd);
466 }
467 void JobList::consoleListJobTotals()
468 {
469    QString cmd("list jobtotals");
470    if (mainWin->m_longList) { cmd.prepend("l"); }
471    consoleCommand(cmd);
472 }
473 void JobList::consoleDeleteJob()
474 {
475    if (QMessageBox::warning(this, "Bat",
476       tr("Are you sure you want to delete??  !!!.\n"
477 "This delete command is used to delete a Job record and all associated catalog"
478 " records that were created. This command operates only on the Catalog"
479 " database and has no effect on the actual data written to a Volume. This"
480 " command can be dangerous and we strongly recommend that you do not use"
481 " it unless you know what you are doing.  The Job and all its associated"
482 " records (File and JobMedia) will be deleted from the catalog."
483       "Press OK to proceed with delete operation.?"),
484       QMessageBox::Ok | QMessageBox::Cancel)
485       == QMessageBox::Cancel) { return; }
486
487    QString cmd("delete job jobid=");
488    cmd += m_selectedJobs;
489    consoleCommand(cmd, false);
490    populateTable();
491 }
492 void JobList::consolePurgeFiles()
493 {
494    if (QMessageBox::warning(this, "Bat",
495       tr("Are you sure you want to purge ??  !!!.\n"
496 "The Purge command will delete associated Catalog database records from Jobs and"
497 " Volumes without considering the retention period. Purge  works only on the"
498 " Catalog database and does not affect data written to Volumes. This command can"
499 " be dangerous because you can delete catalog records associated with current"
500 " backups of files, and we recommend that you do not use it unless you know what"
501 " you are doing.\n"
502       "Press OK to proceed with the purge operation?"),
503       QMessageBox::Ok | QMessageBox::Cancel)
504       == QMessageBox::Cancel) { return; }
505
506    foreach(QString job, m_selectedJobsList) {
507       QString cmd("purge files jobid=");
508       cmd += job;
509       consoleCommand(cmd, false);
510    }
511    populateTable();
512 }
513
514 /*
515  * Subroutine to call preRestore to restore from a select job
516  */
517 void JobList::preRestoreFromJob()
518 {
519    new prerestorePage(m_currentJob, R_JOBIDLIST);
520 }
521
522 /*
523  * Subroutine to call preRestore to restore from a select job
524  */
525 void JobList::preRestoreFromTime()
526 {
527    new prerestorePage(m_currentJob, R_JOBDATETIME);
528 }
529
530 /*
531  * Subroutine to call class to show the log in the database from that job
532  */
533 void JobList::showLogForJob()
534 {
535    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
536    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
537 }
538
539 /*
540  * Cancel a running job
541  */
542 void JobList::consoleCancelJob()
543 {
544    QString cmd("cancel jobid=");
545    cmd += m_currentJob;
546    consoleCommand(cmd);
547 }
548
549 /*
550  * Graph this table
551  */
552 void JobList::graphTable()
553 {
554 #ifdef HAVE_QWT
555    JobPlotPass pass;
556    pass.recordLimitCheck = limitCheckBox->checkState();
557    pass.daysLimitCheck = daysCheckBox->checkState();
558    pass.recordLimitSpin = limitSpinBox->value();
559    pass.daysLimitSpin = daysSpinBox->value();
560    pass.jobCombo = jobComboBox->currentText();
561    pass.clientCombo = clientComboBox->currentText();
562    pass.volumeCombo = volumeComboBox->currentText();
563    pass.fileSetCombo = fileSetComboBox->currentText();
564    pass.purgedCombo = purgedComboBox->currentText();
565    pass.levelCombo = levelComboBox->currentText();
566    pass.statusCombo = statusComboBox->currentText();
567    pass.use = true;
568    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
569    new JobPlot(pageSelectorTreeWidgetItem, pass);
570 #endif
571 }
572
573 /*
574  * Save user settings associated with this page
575  */
576 void JobList::writeSettings()
577 {
578    QSettings settings(m_console->m_dir->name(), "bat");
579    settings.beginGroup(m_groupText);
580    settings.setValue(m_splitText, m_splitter->saveState());
581    settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
582    settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
583    settings.endGroup();
584 }
585
586 /*
587  * Read and restore user settings associated with this page
588  */
589 void JobList::readSettings()
590 {
591    m_groupText = "JobListPage";
592    m_splitText = "splitterSizes_1";
593    QSettings settings(m_console->m_dir->name(), "bat");
594    settings.beginGroup(m_groupText);
595    m_splitter->restoreState(settings.value(m_splitText).toByteArray());
596    filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
597    filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
598    settings.endGroup();
599 }
600
601 /*
602  * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
603  */
604 void JobList::selectionChanged()
605 {
606    QList<int> rowList;
607    QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
608    foreach (QTableWidgetItem *sitem, sitems) {
609       int row = sitem->row();
610       if (!rowList.contains(row)) {
611          rowList.append(row);
612       }
613    }
614
615    m_selectedJobs = "";
616    m_selectedJobsList.clear();
617    bool first = true;
618    foreach(int row, rowList) {
619       QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
620       if (!first) m_selectedJobs.append(",");
621       else first = false;
622       m_selectedJobs.append(sitem->text());
623       m_selectedJobsList.append(sitem->text());
624    }
625    m_selectedJobsCount = rowList.count();
626    if (m_selectedJobsCount > 1) {
627       QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
628       actionDeleteJob->setText(text);
629       text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
630       actionPurgeFiles->setText(text);
631    } else {
632       actionDeleteJob->setText(tr("Delete Single Job"));
633       actionPurgeFiles->setText(tr("Purge Files from single job"));
634    }
635
636    /* remove all actions */
637    foreach(QAction* mediaAction, mp_tableWidget->actions()) {
638       mp_tableWidget->removeAction(mediaAction);
639    }
640
641    /* Add Actions */
642    mp_tableWidget->addAction(actionRefreshJobList);
643    if (m_selectedJobsCount == 1) {
644       mp_tableWidget->addAction(actionListJobid);
645       mp_tableWidget->addAction(actionListFilesOnJob);
646       mp_tableWidget->addAction(actionListJobMedia);
647       mp_tableWidget->addAction(actionListVolumes);
648       mp_tableWidget->addAction(actionRestoreFromJob);
649       mp_tableWidget->addAction(actionRestoreFromTime);
650       mp_tableWidget->addAction(actionShowLogForJob);
651    }
652    if (m_selectedJobsCount >= 1) {
653       mp_tableWidget->addAction(actionDeleteJob);
654       mp_tableWidget->addAction(actionPurgeFiles);
655    }
656
657    /* Make Connections */
658    if (m_checkCurrentWidget) {
659       int row = mp_tableWidget->currentRow();
660       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
661       m_currentJob = jobitem->text();
662
663       /* include purged action or not */
664       jobitem = mp_tableWidget->item(row, m_purgedIndex);
665       QString purged = jobitem->text();
666 /*      mp_tableWidget->removeAction(actionPurgeFiles);
667       if (purged == tr("No") ) {
668          mp_tableWidget->addAction(actionPurgeFiles);
669       }*/
670       /* include restore from time and job action or not */
671       jobitem = mp_tableWidget->item(row, m_typeIndex);
672       QString type = jobitem->text();
673       if (m_selectedJobsCount == 1) {
674          mp_tableWidget->removeAction(actionRestoreFromJob);
675          mp_tableWidget->removeAction(actionRestoreFromTime);
676          if (type == tr("Backup")) {
677             mp_tableWidget->addAction(actionRestoreFromJob);
678             mp_tableWidget->addAction(actionRestoreFromTime);
679          }
680       }
681       /* include cancel action or not */
682       jobitem = mp_tableWidget->item(row, m_statusIndex);
683       QString status = jobitem->text();
684       mp_tableWidget->removeAction(actionCancelJob);
685       if (status == tr("Running") || status == tr("Created, not yet running")) {
686          mp_tableWidget->addAction(actionCancelJob);
687       }
688    }
689 }