]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
Merge branch 'master' of ssh://ricozz@bacula.git.sourceforge.net/gitroot/bacula/bacula
[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    mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
235 }
236
237 void JobList::prepareFilterWidgets()
238 {
239    if (!m_populated) {
240       clientComboBox->addItem(tr("Any"));
241       clientComboBox->addItems(m_console->client_list);
242       comboSel(clientComboBox, m_clientName);
243
244       QStringList volumeList;
245       getVolumeList(volumeList);
246       volumeComboBox->addItem(tr("Any"));
247       volumeComboBox->addItems(volumeList);
248       comboSel(volumeComboBox, m_mediaName);
249
250       jobComboBox->addItem(tr("Any"));
251       jobComboBox->addItems(m_console->job_list);
252       comboSel(jobComboBox, m_jobName);
253
254       levelComboFill(levelComboBox);
255
256       boolComboFill(purgedComboBox);
257
258       fileSetComboBox->addItem(tr("Any"));
259       fileSetComboBox->addItems(m_console->fileset_list);
260       comboSel(fileSetComboBox, m_filesetName);
261
262       poolComboBox->addItem(tr("Any"));
263       poolComboBox->addItems(m_console->pool_list);
264
265       jobStatusComboFill(statusComboBox);
266    }
267 }
268
269 void JobList::fillQueryString(QString &query)
270 {
271    query = "";
272    int volumeIndex = volumeComboBox->currentIndex();
273    if (volumeIndex != -1)
274       m_mediaName = volumeComboBox->itemText(volumeIndex);
275    QString distinct = "";
276    if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
277    query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, " 
278             " Client.Name AS Client,"
279             " Job.Starttime AS JobStart, Job.Type AS JobType,"
280             " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
281             " Job.JobBytes AS Bytes, Job.JobStatus AS Status,"
282             " Job.PurgedFiles AS Purged, FileSet.FileSet,"
283             " Pool.Name AS Pool,"
284             " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume,"
285             " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes"
286             " FROM Job"
287             " JOIN Client ON (Client.ClientId=Job.ClientId)"
288             " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) "
289             " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId ";
290    QStringList conditions;
291    if (m_mediaName != tr("Any")) {
292       query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
293                " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
294       conditions.append("Media.VolumeName='" + m_mediaName + "'");
295    }
296
297    comboCond(conditions, clientComboBox, "Client.Name");
298    comboCond(conditions, jobComboBox, "Job.Name");
299    levelComboCond(conditions, levelComboBox, "Job.Level");
300    jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus");
301    boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles");
302    comboCond(conditions, fileSetComboBox, "FileSet.FileSet");
303    comboCond(conditions, poolComboBox, "Pool.Name");
304
305    /* If Limit check box For limit by days is checked  */
306    if (daysCheckBox->checkState() == Qt::Checked) {
307       QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
308       QString since = stamp.toString(Qt::ISODate);
309       conditions.append("Job.Starttime > '" + since + "'");
310    }
311    if (filterCopyCheckBox->checkState() == Qt::Checked) {
312       conditions.append("Job.Type != 'c'" );
313    }
314    if (filterMigrationCheckBox->checkState() == Qt::Checked) {
315       conditions.append("Job.Type != 'g'" );
316    }
317    bool first = true;
318    foreach (QString condition, conditions) {
319       if (first) {
320          query += " WHERE " + condition;
321          first = false;
322       } else {
323          query += " AND " + condition;
324       }
325    }
326    /* Descending */
327    query += " ORDER BY Job.JobId DESC";
328    /* If Limit check box for limit records returned is checked  */
329    if (limitCheckBox->checkState() == Qt::Checked) {
330       QString limit;
331       limit.setNum(limitSpinBox->value());
332       query += " LIMIT " + limit;
333    }
334 }
335
336 /*
337  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
338  * The tree has been populated.
339  */
340 void JobList::PgSeltreeWidgetClicked()
341 {
342    if (!m_populated) {
343       populateTable();
344       /* Lets make sure the splitter is not all the way to size index 0 == 0 */
345       QList<int> sizes = m_splitter->sizes();
346       if (sizes[0] == 0) {
347          int frameMax = frame->maximumHeight();
348          int sizeSum = 0;
349          foreach(int size, sizes) { sizeSum += size; }
350          int tabHeight = mainWin->tabWidget->geometry().height();
351          sizes[0] = frameMax;
352          sizes[1] = tabHeight - frameMax;
353          m_splitter->setSizes(sizes);
354       }
355    }
356    dockPage();
357 }
358
359 /*
360  *  Virtual function override of pages function which is called when this page
361  *  is visible on the stack
362  */
363 void JobList::currentStackItem()
364 {
365 /*   if (!m_populated) populate every time user comes back to this object */
366       populateTable();
367 }
368
369 /*
370  * Virtual Function to return the name for the medialist tree widget
371  */
372 void JobList::treeWidgetName(QString &desc)
373 {
374    if (m_mediaName != "" ) {
375      desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
376    } else if (m_clientName != "" ) {
377      desc = tr("Jobs Run from Client %1").arg(m_clientName);
378    } else if (m_jobName != "" ) {
379      desc = tr("Jobs Run of Job %1").arg(m_jobName);
380    } else if (m_filesetName != "" ) {
381      desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
382    } else {
383      desc = tr("Jobs Run");
384    }
385 }
386
387 /*
388  * Function to create connections for context sensitive menu for this and
389  * the page selector
390  */
391 void JobList::createConnections()
392 {
393    /* connect to the action specific to this pages class that shows up in the 
394     * page selector tree */
395    connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable()));
396    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
397 #ifdef HAVE_QWT
398    connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
399 #else
400    graphButton->setEnabled(false);
401    graphButton->setVisible(false);
402 #endif
403    /* for the selectionChanged to maintain m_currentJob and a delete selection */
404    connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
405    connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
406
407    /* Do what is required for the local context sensitive menu */
408
409
410    /* setContextMenuPolicy is required */
411    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
412
413    connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
414    connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
415    connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
416    connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
417    connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
418    connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
419    connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
420    connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
421    connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
422    connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
423    connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
424
425    m_contextActions.append(actionRefreshJobList);
426    m_contextActions.append(actionListJobTotals);
427 }
428
429 /*
430  * Functions to respond to local context sensitive menu sending console commands
431  * If I could figure out how to make these one function passing a string, Yaaaaaa
432  */
433 void JobList::consoleListFilesOnJob()
434 {
435    QString cmd("list files jobid=");
436    cmd += m_currentJob;
437    if (mainWin->m_longList) { cmd.prepend("l"); }
438    consoleCommand(cmd);
439 }
440 void JobList::consoleListJobMedia()
441 {
442    QString cmd("list jobmedia jobid=");
443    cmd += m_currentJob;
444    if (mainWin->m_longList) { cmd.prepend("l"); }
445    consoleCommand(cmd);
446 }
447
448 void JobList::consoleListJobTotals()
449 {
450    QString cmd("list jobtotals");
451    if (mainWin->m_longList) { cmd.prepend("l"); }
452    consoleCommand(cmd);
453 }
454 void JobList::consoleDeleteJob()
455 {
456    if (QMessageBox::warning(this, "Bat",
457       tr("Are you sure you want to delete??  !!!.\n"
458 "This delete command is used to delete a Job record and all associated catalog"
459 " records that were created. This command operates only on the Catalog"
460 " database and has no effect on the actual data written to a Volume. This"
461 " command can be dangerous and we strongly recommend that you do not use"
462 " it unless you know what you are doing.  The Job and all its associated"
463 " records (File and JobMedia) will be deleted from the catalog."
464       "Press OK to proceed with delete operation.?"),
465       QMessageBox::Ok | QMessageBox::Cancel)
466       == QMessageBox::Cancel) { return; }
467
468    QString cmd("delete job jobid=");
469    cmd += m_selectedJobs;
470    consoleCommand(cmd, false);
471    populateTable();
472 }
473 void JobList::consolePurgeFiles()
474 {
475    if (QMessageBox::warning(this, "Bat",
476       tr("Are you sure you want to purge ??  !!!.\n"
477 "The Purge command will delete associated Catalog database records from Jobs and"
478 " Volumes without considering the retention period. Purge  works only on the"
479 " Catalog database and does not affect data written to Volumes. This command can"
480 " be dangerous because you can delete catalog records associated with current"
481 " backups of files, and we recommend that you do not use it unless you know what"
482 " you are doing.\n"
483       "Press OK to proceed with the purge operation?"),
484       QMessageBox::Ok | QMessageBox::Cancel)
485       == QMessageBox::Cancel) { return; }
486
487    m_console->m_warningPrevent = true;
488    foreach(QString job, m_selectedJobsList) {
489       QString cmd("purge files jobid=");
490       cmd += job;
491       consoleCommand(cmd, false);
492    }
493    m_console->m_warningPrevent = false;
494    populateTable();
495 }
496
497 /*
498  * Subroutine to call preRestore to restore from a select job
499  */
500 void JobList::preRestoreFromJob()
501 {
502    new prerestorePage(m_currentJob, R_JOBIDLIST);
503 }
504
505 /*
506  * Subroutine to call preRestore to restore from a select job
507  */
508 void JobList::preRestoreFromTime()
509 {
510    new prerestorePage(m_currentJob, R_JOBDATETIME);
511 }
512
513 /*
514  * Subroutine to call class to show the log in the database from that job
515  */
516 void JobList::showLogForJob()
517 {
518    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
519    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
520 }
521
522 /*
523  * Subroutine to call class to show the log in the database from that job
524  */
525 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
526 {
527    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
528    new Job(m_currentJob, pageSelectorTreeWidgetItem);
529 }
530
531 /*
532  * Cancel a running job
533  */
534 void JobList::consoleCancelJob()
535 {
536    QString cmd("cancel jobid=");
537    cmd += m_currentJob;
538    consoleCommand(cmd);
539 }
540
541 /*
542  * Graph this table
543  */
544 void JobList::graphTable()
545 {
546 #ifdef HAVE_QWT
547    JobPlotPass pass;
548    pass.recordLimitCheck = limitCheckBox->checkState();
549    pass.daysLimitCheck = daysCheckBox->checkState();
550    pass.recordLimitSpin = limitSpinBox->value();
551    pass.daysLimitSpin = daysSpinBox->value();
552    pass.jobCombo = jobComboBox->currentText();
553    pass.clientCombo = clientComboBox->currentText();
554    pass.volumeCombo = volumeComboBox->currentText();
555    pass.fileSetCombo = fileSetComboBox->currentText();
556    pass.purgedCombo = purgedComboBox->currentText();
557    pass.levelCombo = levelComboBox->currentText();
558    pass.statusCombo = statusComboBox->currentText();
559    pass.use = true;
560    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
561    new JobPlot(pageSelectorTreeWidgetItem, pass);
562 #endif
563 }
564
565 /*
566  * Save user settings associated with this page
567  */
568 void JobList::writeSettings()
569 {
570    QSettings settings(m_console->m_dir->name(), "bat");
571    settings.beginGroup(m_groupText);
572    settings.setValue(m_splitText, m_splitter->saveState());
573    settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
574    settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
575    settings.endGroup();
576 }
577
578 /*
579  * Read and restore user settings associated with this page
580  */
581 void JobList::readSettings()
582 {
583    m_groupText = "JobListPage";
584    m_splitText = "splitterSizes_2";
585    QSettings settings(m_console->m_dir->name(), "bat");
586    settings.beginGroup(m_groupText);
587    if (settings.contains(m_splitText)) {
588       m_splitter->restoreState(settings.value(m_splitText).toByteArray());
589    }
590    filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
591    filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
592    settings.endGroup();
593 }
594
595 /*
596  * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
597  */
598 void JobList::selectionChanged()
599 {
600    QList<int> rowList;
601    QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
602    foreach (QTableWidgetItem *sitem, sitems) {
603       int row = sitem->row();
604       if (!rowList.contains(row)) {
605          rowList.append(row);
606       }
607    }
608
609    m_selectedJobs = "";
610    m_selectedJobsList.clear();
611    bool first = true;
612    foreach(int row, rowList) {
613       QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
614       if (!first) m_selectedJobs.append(",");
615       else first = false;
616       m_selectedJobs.append(sitem->text());
617       m_selectedJobsList.append(sitem->text());
618    }
619    m_selectedJobsCount = rowList.count();
620    if (m_selectedJobsCount > 1) {
621       QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
622       actionDeleteJob->setText(text);
623       text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
624       actionPurgeFiles->setText(text);
625    } else {
626       actionDeleteJob->setText(tr("Delete Single Job"));
627       actionPurgeFiles->setText(tr("Purge Files from single job"));
628    }
629
630    /* remove all actions */
631    foreach(QAction* mediaAction, mp_tableWidget->actions()) {
632       mp_tableWidget->removeAction(mediaAction);
633    }
634
635    /* Add Actions */
636    mp_tableWidget->addAction(actionRefreshJobList);
637    if (m_selectedJobsCount == 1) {
638       mp_tableWidget->addAction(actionListFilesOnJob);
639       mp_tableWidget->addAction(actionListJobMedia);
640       mp_tableWidget->addAction(actionRestoreFromJob);
641       mp_tableWidget->addAction(actionRestoreFromTime);
642       mp_tableWidget->addAction(actionShowLogForJob);
643       mp_tableWidget->addAction(actionShowInfoForJob);
644    }
645    if (m_selectedJobsCount >= 1) {
646       mp_tableWidget->addAction(actionDeleteJob);
647       mp_tableWidget->addAction(actionPurgeFiles);
648    }
649
650    /* Make Connections */
651    if (m_checkCurrentWidget) {
652       int row = mp_tableWidget->currentRow();
653       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
654       m_currentJob = jobitem->text();
655
656       /* include purged action or not */
657       jobitem = mp_tableWidget->item(row, m_purgedIndex);
658       QString purged = jobitem->text();
659 /*      mp_tableWidget->removeAction(actionPurgeFiles);
660       if (purged == tr("No") ) {
661          mp_tableWidget->addAction(actionPurgeFiles);
662       }*/
663       /* include restore from time and job action or not */
664       jobitem = mp_tableWidget->item(row, m_typeIndex);
665       QString type = jobitem->text();
666       if (m_selectedJobsCount == 1) {
667          mp_tableWidget->removeAction(actionRestoreFromJob);
668          mp_tableWidget->removeAction(actionRestoreFromTime);
669          if (type == tr("Backup")) {
670             mp_tableWidget->addAction(actionRestoreFromJob);
671             mp_tableWidget->addAction(actionRestoreFromTime);
672          }
673       }
674       /* include cancel action or not */
675       jobitem = mp_tableWidget->item(row, m_statusIndex);
676       QString status = jobitem->text();
677       mp_tableWidget->removeAction(actionCancelJob);
678       if (status == tr("Running") || status == tr("Created, not yet running")) {
679          mp_tableWidget->addAction(actionCancelJob);
680       }
681    }
682 }
683
684 /*
685  *  Function to prevent the splitter from making index 0 of the size larger than it
686  *  needs to be
687  */
688 void JobList::splitterMoved(int /*pos*/, int /*index*/)
689 {
690    int frameMax = frame->maximumHeight();
691    QList<int> sizes = m_splitter->sizes();
692    int sizeSum = 0;
693    foreach(int size, sizes) { sizeSum += size; }
694    if (sizes[0] > frameMax) {
695       sizes[0] = frameMax;
696       sizes[1] = sizeSum - frameMax;
697       m_splitter->setSizes(sizes);
698    }
699 }