2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Dirk Bartley, March 2007
25 #include <QAbstractEventDispatcher>
26 #include <QTableWidgetItem>
30 #include "joblog/joblog.h"
32 #include "jobgraphs/jobplot.h"
34 #include "util/fmtwidgetitem.h"
35 #include "util/comboutil.h"
38 * Constructor for the class
40 JobList::JobList(const QString &mediaName, const QString &clientName,
41 const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
45 m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */
46 m_mediaName = mediaName;
47 m_clientName = clientName;
49 m_filesetName = filesetName;
50 pgInitialize("", parentTreeWidgetItem);
51 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
52 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
57 if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) {
60 m_checkCurrentWidget = true;
62 /* Set Defaults for check and spin for limits */
63 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
64 limitSpinBox->setValue(mainWin->m_recordLimitVal);
65 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
66 daysSpinBox->setValue(mainWin->m_daysLimitVal);
68 QGridLayout *gridLayout = new QGridLayout(this);
69 gridLayout->setSpacing(6);
70 gridLayout->setMargin(9);
71 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
73 m_splitter = new QSplitter(Qt::Vertical, this);
74 QScrollArea *area = new QScrollArea();
75 area->setObjectName(QString::fromUtf8("area"));
76 area->setWidget(frame);
77 area->setWidgetResizable(true);
78 m_splitter->addWidget(area);
79 m_splitter->addWidget(mp_tableWidget);
81 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
84 if (m_closeable) { dockPage(); }
88 * Write the m_splitter settings in the destructor
96 * The Meat of the class.
97 * This function will populate the QTableWidget, mp_tablewidget, with
98 * QTableWidgetItems representing the results of a query for what jobs exist on
99 * the media name passed from the constructor stored in m_mediaName.
101 void JobList::populateTable()
103 /* Can't do this in constructor because not neccesarily conected in constructor */
104 prepareFilterWidgets();
107 Freeze frz(*mp_tableWidget); /* disable updating*/
111 fillQueryString(query);
113 /* Set up the Header for the table */
114 QStringList headerlist = (QStringList()
115 << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime")
116 << tr("Job Type") << tr("Job Level") << tr("Job Files")
117 << tr("Job Bytes") << tr("Job Status") << tr("Purged") << tr("File Set")
118 << tr("Pool Name") << tr("First Volume") << tr("VolCount"));
120 m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
121 m_purgedIndex = headerlist.indexOf(tr("Purged"));
122 m_typeIndex = headerlist.indexOf(tr("Job Type"));
123 m_statusIndex = headerlist.indexOf(tr("Job Status"));
124 m_startIndex = headerlist.indexOf(tr("Job Starttime"));
125 m_filesIndex = headerlist.indexOf(tr("Job Files"));
126 m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
127 m_levelIndex = headerlist.indexOf(tr("Job Level"));
128 m_nameIndex = headerlist.indexOf(tr("Job Name"));
129 m_filesetIndex = headerlist.indexOf(tr("File Set"));
130 m_clientIndex = headerlist.indexOf(tr("Client"));
132 /* Initialize the QTableWidget */
133 m_checkCurrentWidget = false;
134 mp_tableWidget->clear();
135 m_checkCurrentWidget = true;
136 mp_tableWidget->setColumnCount(headerlist.size());
137 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
138 mp_tableWidget->horizontalHeader()->setHighlightSections(false);
139 mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
140 mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
142 if (mainWin->m_sqlDebug) {
143 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
147 if (m_console->sql_cmd(query, results)) {
148 m_resultCount = results.count();
150 QStringList fieldlist;
151 mp_tableWidget->setRowCount(results.size());
154 /* Iterate through the record returned from the query */
156 foreach (resultline, results) {
157 fieldlist = resultline.split("\t");
158 if (fieldlist.size() < 13)
159 continue; /* some fields missing, ignore row */
161 TableItemFormatter jobitem(*mp_tableWidget, row);
163 /* Iterate through fields in the record */
164 QStringListIterator fld(fieldlist);
168 jobitem.setNumericFld(col++, fld.next());
171 jobitem.setTextFld(col++, fld.next());
174 jobitem.setTextFld(col++, fld.next());
177 jobitem.setTextFld(col++, fld.next(), true);
180 jobitem.setJobTypeFld(col++, fld.next());
183 jobitem.setJobLevelFld(col++, fld.next());
186 jobitem.setNumericFld(col++, fld.next());
189 jobitem.setBytesFld(col++, fld.next());
192 jobitem.setJobStatusFld(col++, fld.next());
195 jobitem.setBoolFld(col++, fld.next());
198 jobitem.setTextFld(col++, fld.next());
201 jobitem.setTextFld(col++, fld.next());
204 jobitem.setTextFld(col++, fld.next());
207 jobitem.setNumericFld(col++, fld.next());
211 /* set default sorting */
212 mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder);
213 mp_tableWidget->setSortingEnabled(true);
215 /* Resize the columns */
216 mp_tableWidget->resizeColumnsToContents();
217 mp_tableWidget->resizeRowsToContents();
218 mp_tableWidget->verticalHeader()->hide();
219 if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
220 /* for context sensitive searches, let the user know if there were no
222 QMessageBox::warning(this, "Bat",
223 tr("The Jobs query returned no results.\n"
224 "Press OK to continue?"), QMessageBox::Ok );
228 mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
231 void JobList::prepareFilterWidgets()
234 clientComboBox->addItem(tr("Any"));
235 clientComboBox->addItems(m_console->client_list);
236 comboSel(clientComboBox, m_clientName);
238 QStringList volumeList;
239 getVolumeList(volumeList);
240 volumeComboBox->addItem(tr("Any"));
241 volumeComboBox->addItems(volumeList);
242 comboSel(volumeComboBox, m_mediaName);
244 jobComboBox->addItem(tr("Any"));
245 jobComboBox->addItems(m_console->job_list);
246 comboSel(jobComboBox, m_jobName);
248 levelComboFill(levelComboBox);
250 boolComboFill(purgedComboBox);
252 fileSetComboBox->addItem(tr("Any"));
253 fileSetComboBox->addItems(m_console->fileset_list);
254 comboSel(fileSetComboBox, m_filesetName);
256 poolComboBox->addItem(tr("Any"));
257 poolComboBox->addItems(m_console->pool_list);
259 jobStatusComboFill(statusComboBox);
263 void JobList::fillQueryString(QString &query)
266 int volumeIndex = volumeComboBox->currentIndex();
267 if (volumeIndex != -1)
268 m_mediaName = volumeComboBox->itemText(volumeIndex);
269 QString distinct = "";
270 if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
271 query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, "
272 " Client.Name AS Client,"
273 " Job.Starttime AS JobStart, Job.Type AS JobType,"
274 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
275 " Job.JobBytes AS Bytes, Job.JobStatus AS Status,"
276 " Job.PurgedFiles AS Purged, FileSet.FileSet,"
277 " Pool.Name AS Pool,"
278 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume,"
279 " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes"
281 " JOIN Client ON (Client.ClientId=Job.ClientId)"
282 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) "
283 " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId ";
284 QStringList conditions;
285 if (m_mediaName != tr("Any")) {
286 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
287 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
288 conditions.append("Media.VolumeName='" + m_mediaName + "'");
291 comboCond(conditions, clientComboBox, "Client.Name");
292 comboCond(conditions, jobComboBox, "Job.Name");
293 levelComboCond(conditions, levelComboBox, "Job.Level");
294 jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus");
295 boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles");
296 comboCond(conditions, fileSetComboBox, "FileSet.FileSet");
297 comboCond(conditions, poolComboBox, "Pool.Name");
299 /* If Limit check box For limit by days is checked */
300 if (daysCheckBox->checkState() == Qt::Checked) {
301 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
302 QString since = stamp.toString(Qt::ISODate);
303 conditions.append("Job.Starttime > '" + since + "'");
305 if (filterCopyCheckBox->checkState() == Qt::Checked) {
306 conditions.append("Job.Type != 'c'" );
308 if (filterMigrationCheckBox->checkState() == Qt::Checked) {
309 conditions.append("Job.Type != 'g'" );
312 foreach (QString condition, conditions) {
314 query += " WHERE " + condition;
317 query += " AND " + condition;
321 query += " ORDER BY Job.JobId DESC";
322 /* If Limit check box for limit records returned is checked */
323 if (limitCheckBox->checkState() == Qt::Checked) {
325 limit.setNum(limitSpinBox->value());
326 query += " LIMIT " + limit;
331 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
332 * The tree has been populated.
334 void JobList::PgSeltreeWidgetClicked()
338 /* Lets make sure the splitter is not all the way to size index 0 == 0 */
339 QList<int> sizes = m_splitter->sizes();
341 int frameMax = frame->maximumHeight();
343 foreach(int size, sizes) { sizeSum += size; }
344 int tabHeight = mainWin->tabWidget->geometry().height();
346 sizes[1] = tabHeight - frameMax;
347 m_splitter->setSizes(sizes);
350 if (!isOnceDocked()) {
356 * Virtual function override of pages function which is called when this page
357 * is visible on the stack
359 void JobList::currentStackItem()
361 /* if (!m_populated) populate every time user comes back to this object */
366 * Virtual Function to return the name for the medialist tree widget
368 void JobList::treeWidgetName(QString &desc)
370 if (m_mediaName != "" ) {
371 desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
372 } else if (m_clientName != "" ) {
373 desc = tr("Jobs Run from Client %1").arg(m_clientName);
374 } else if (m_jobName != "" ) {
375 desc = tr("Jobs Run of Job %1").arg(m_jobName);
376 } else if (m_filesetName != "" ) {
377 desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
379 desc = tr("Jobs Run");
384 * Function to create connections for context sensitive menu for this and
387 void JobList::createConnections()
389 /* connect to the action specific to this pages class that shows up in the
390 * page selector tree */
391 connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable()));
392 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
394 connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
396 graphButton->setEnabled(false);
397 graphButton->setVisible(false);
399 /* for the selectionChanged to maintain m_currentJob and a delete selection */
400 connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
401 connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
403 /* Do what is required for the local context sensitive menu */
406 /* setContextMenuPolicy is required */
407 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
409 connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
410 connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
411 connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
412 connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob()));
413 connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
414 connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
415 connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
416 connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
417 connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
418 connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
419 connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
420 connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
422 m_contextActions.append(actionRefreshJobList);
423 m_contextActions.append(actionListJobTotals);
427 * Functions to respond to local context sensitive menu sending console commands
428 * If I could figure out how to make these one function passing a string, Yaaaaaa
430 void JobList::consoleListFilesOnJob()
432 QString cmd("list files jobid=");
434 if (mainWin->m_longList) { cmd.prepend("l"); }
437 void JobList::consoleListJobMedia()
439 QString cmd("list jobmedia jobid=");
441 if (mainWin->m_longList) { cmd.prepend("l"); }
445 void JobList::consoleListJobTotals()
447 QString cmd("list jobtotals");
448 if (mainWin->m_longList) { cmd.prepend("l"); }
452 void JobList::consoleDeleteJob()
454 if (QMessageBox::warning(this, "Bat",
455 tr("Are you sure you want to delete?? !!!.\n"
456 "This delete command is used to delete a Job record and all associated catalog"
457 " records that were created. This command operates only on the Catalog"
458 " database and has no effect on the actual data written to a Volume. This"
459 " command can be dangerous and we strongly recommend that you do not use"
460 " it unless you know what you are doing. The Job and all its associated"
461 " records (File and JobMedia) will be deleted from the catalog."
462 "Press OK to proceed with delete operation.?"),
463 QMessageBox::Ok | QMessageBox::Cancel)
464 == QMessageBox::Cancel) { return; }
466 QString cmd("delete job jobid=");
467 cmd += m_selectedJobs;
468 consoleCommand(cmd, false);
472 void JobList::consoleRestartJob()
476 cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName);
477 if (m_filesetName != "" && m_filesetName != "*None*") {
478 cmd += tr(" fileset=\"%1\"").arg(m_filesetName);
481 if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data());
482 consoleCommand(cmd, false);
488 void JobList::consolePurgeFiles()
490 if (QMessageBox::warning(this, "Bat",
491 tr("Are you sure you want to purge ?? !!!.\n"
492 "The Purge command will delete associated Catalog database records from Jobs and"
493 " Volumes without considering the retention period. Purge works only on the"
494 " Catalog database and does not affect data written to Volumes. This command can"
495 " be dangerous because you can delete catalog records associated with current"
496 " backups of files, and we recommend that you do not use it unless you know what"
498 "Press OK to proceed with the purge operation?"),
499 QMessageBox::Ok | QMessageBox::Cancel)
500 == QMessageBox::Cancel) { return; }
502 m_console->m_warningPrevent = true;
503 foreach(QString job, m_selectedJobsList) {
504 QString cmd("purge files jobid=");
506 consoleCommand(cmd, false);
508 m_console->m_warningPrevent = false;
513 * Subroutine to call preRestore to restore from a select job
515 void JobList::preRestoreFromJob()
517 new prerestorePage(m_currentJob, R_JOBIDLIST);
521 * Subroutine to call preRestore to restore from a select job
523 void JobList::preRestoreFromTime()
525 new prerestorePage(m_currentJob, R_JOBDATETIME);
529 * Subroutine to call class to show the log in the database from that job
531 void JobList::showLogForJob()
533 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
534 new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
538 * Subroutine to call class to show the log in the database from that job
540 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
542 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
543 new Job(m_currentJob, pageSelectorTreeWidgetItem);
547 * Cancel a running job
549 void JobList::consoleCancelJob()
551 QString cmd("cancel jobid=");
559 void JobList::graphTable()
563 pass.recordLimitCheck = limitCheckBox->checkState();
564 pass.daysLimitCheck = daysCheckBox->checkState();
565 pass.recordLimitSpin = limitSpinBox->value();
566 pass.daysLimitSpin = daysSpinBox->value();
567 pass.jobCombo = jobComboBox->currentText();
568 pass.clientCombo = clientComboBox->currentText();
569 pass.volumeCombo = volumeComboBox->currentText();
570 pass.fileSetCombo = fileSetComboBox->currentText();
571 pass.purgedCombo = purgedComboBox->currentText();
572 pass.levelCombo = levelComboBox->currentText();
573 pass.statusCombo = statusComboBox->currentText();
575 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
576 new JobPlot(pageSelectorTreeWidgetItem, pass);
581 * Save user settings associated with this page
583 void JobList::writeSettings()
585 QSettings settings(m_console->m_dir->name(), "bat");
586 settings.beginGroup(m_groupText);
587 settings.setValue(m_splitText, m_splitter->saveState());
588 settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
589 settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
594 * Read and restore user settings associated with this page
596 void JobList::readSettings()
598 m_groupText = "JobListPage";
599 m_splitText = "splitterSizes_2";
600 QSettings settings(m_console->m_dir->name(), "bat");
601 settings.beginGroup(m_groupText);
602 if (settings.contains(m_splitText)) {
603 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
605 filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
606 filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
611 * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
613 void JobList::selectionChanged()
616 QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
617 foreach (QTableWidgetItem *sitem, sitems) {
618 int row = sitem->row();
619 if (!rowList.contains(row)) {
625 m_selectedJobsList.clear();
627 foreach(int row, rowList) {
628 QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
629 if (!first) m_selectedJobs.append(",");
631 m_selectedJobs.append(sitem->text());
632 m_selectedJobsList.append(sitem->text());
634 m_selectedJobsCount = rowList.count();
635 if (m_selectedJobsCount > 1) {
636 QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
637 actionDeleteJob->setText(text);
638 text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
639 actionPurgeFiles->setText(text);
641 actionDeleteJob->setText(tr("Delete Single Job"));
642 actionPurgeFiles->setText(tr("Purge Files from single job"));
645 /* remove all actions */
646 foreach(QAction* mediaAction, mp_tableWidget->actions()) {
647 mp_tableWidget->removeAction(mediaAction);
651 mp_tableWidget->addAction(actionRefreshJobList);
652 if (m_selectedJobsCount == 1) {
653 mp_tableWidget->addAction(actionListFilesOnJob);
654 mp_tableWidget->addAction(actionListJobMedia);
655 mp_tableWidget->addAction(actionRestartJob);
656 mp_tableWidget->addAction(actionRestoreFromJob);
657 mp_tableWidget->addAction(actionRestoreFromTime);
658 mp_tableWidget->addAction(actionShowLogForJob);
659 mp_tableWidget->addAction(actionShowInfoForJob);
661 if (m_selectedJobsCount >= 1) {
662 mp_tableWidget->addAction(actionDeleteJob);
663 mp_tableWidget->addAction(actionPurgeFiles);
666 /* Make Connections */
667 if (m_checkCurrentWidget) {
668 int row = mp_tableWidget->currentRow();
669 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
670 m_currentJob = jobitem->text(); /* get JobId */
671 jobitem = mp_tableWidget->item(row, m_clientIndex);
672 m_clientName = jobitem->text(); /* get Client Name */
673 jobitem = mp_tableWidget->item(row, m_nameIndex);
674 m_jobName = jobitem->text(); /* get Job Name */
675 jobitem = mp_tableWidget->item(row, m_levelIndex);
676 m_levelName = jobitem->text(); /* get level */
677 jobitem = mp_tableWidget->item(row, m_filesetIndex);
679 m_filesetName = jobitem->text(); /* get FileSet Name */
684 /* include purged action or not */
685 jobitem = mp_tableWidget->item(row, m_purgedIndex);
686 QString purged = jobitem->text();
687 /* mp_tableWidget->removeAction(actionPurgeFiles);
688 if (purged == tr("No") ) {
689 mp_tableWidget->addAction(actionPurgeFiles);
692 /* include restore from time and job action or not */
693 jobitem = mp_tableWidget->item(row, m_typeIndex);
694 QString type = jobitem->text();
695 if (m_selectedJobsCount == 1) {
696 mp_tableWidget->removeAction(actionRestoreFromJob);
697 mp_tableWidget->removeAction(actionRestoreFromTime);
698 if (type == tr("Backup")) {
699 mp_tableWidget->addAction(actionRestoreFromJob);
700 mp_tableWidget->addAction(actionRestoreFromTime);
704 /* include cancel action or not */
705 jobitem = mp_tableWidget->item(row, m_statusIndex);
706 QString status = jobitem->text();
707 mp_tableWidget->removeAction(actionCancelJob);
708 if (status == tr("Running") || status == tr("Created, not yet running")) {
709 mp_tableWidget->addAction(actionCancelJob);
715 * Function to prevent the splitter from making index 0 of the size larger than it
718 void JobList::splitterMoved(int /*pos*/, int /*index*/)
720 int frameMax = frame->maximumHeight();
721 QList<int> sizes = m_splitter->sizes();
723 foreach(int size, sizes) { sizeSum += size; }
724 if (sizes[0] > frameMax) {
726 sizes[1] = sizeSum - frameMax;
727 m_splitter->setSizes(sizes);