2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Dirk Bartley, March 2007
24 #include <QAbstractEventDispatcher>
25 #include <QTableWidgetItem>
29 #include "joblog/joblog.h"
31 #include "jobgraphs/jobplot.h"
33 #include "util/fmtwidgetitem.h"
34 #include "util/comboutil.h"
37 * Constructor for the class
39 JobList::JobList(const QString &mediaName, const QString &clientName,
40 const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
44 m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */
45 m_mediaName = mediaName;
46 m_clientName = clientName;
48 m_filesetName = filesetName;
49 pgInitialize("", parentTreeWidgetItem);
50 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
51 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
56 if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) {
59 m_checkCurrentWidget = true;
61 /* Set Defaults for check and spin for limits */
62 limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
63 limitSpinBox->setValue(mainWin->m_recordLimitVal);
64 daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
65 daysSpinBox->setValue(mainWin->m_daysLimitVal);
67 QGridLayout *gridLayout = new QGridLayout(this);
68 gridLayout->setSpacing(6);
69 gridLayout->setMargin(9);
70 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
72 m_splitter = new QSplitter(Qt::Vertical, this);
73 QScrollArea *area = new QScrollArea();
74 area->setObjectName(QString::fromUtf8("area"));
75 area->setWidget(frame);
76 area->setWidgetResizable(true);
77 m_splitter->addWidget(area);
78 m_splitter->addWidget(mp_tableWidget);
80 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
83 if (m_closeable) { dockPage(); }
87 * Write the m_splitter settings in the destructor
95 * The Meat of the class.
96 * This function will populate the QTableWidget, mp_tablewidget, with
97 * QTableWidgetItems representing the results of a query for what jobs exist on
98 * the media name passed from the constructor stored in m_mediaName.
100 void JobList::populateTable()
102 /* Can't do this in constructor because not neccesarily conected in constructor */
103 prepareFilterWidgets();
106 Freeze frz(*mp_tableWidget); /* disable updating*/
110 fillQueryString(query);
112 /* Set up the Header for the table */
113 QStringList headerlist = (QStringList()
114 << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime")
115 << tr("Job Type") << tr("Job Level") << tr("Job Files")
116 << tr("Job Bytes") << tr("Job Status") << tr("Purged") << tr("File Set")
117 << tr("Pool Name") << tr("First Volume") << tr("VolCount"));
119 m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
120 m_purgedIndex = headerlist.indexOf(tr("Purged"));
121 m_typeIndex = headerlist.indexOf(tr("Job Type"));
122 m_statusIndex = headerlist.indexOf(tr("Job Status"));
123 m_startIndex = headerlist.indexOf(tr("Job Starttime"));
124 m_filesIndex = headerlist.indexOf(tr("Job Files"));
125 m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
126 m_levelIndex = headerlist.indexOf(tr("Job Level"));
127 m_nameIndex = headerlist.indexOf(tr("Job Name"));
128 m_filesetIndex = headerlist.indexOf(tr("File Set"));
129 m_clientIndex = headerlist.indexOf(tr("Client"));
131 /* Initialize the QTableWidget */
132 m_checkCurrentWidget = false;
133 mp_tableWidget->clear();
134 m_checkCurrentWidget = true;
135 mp_tableWidget->setColumnCount(headerlist.size());
136 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
137 mp_tableWidget->horizontalHeader()->setHighlightSections(false);
138 mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
139 mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
141 if (mainWin->m_sqlDebug) {
142 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
146 if (m_console->sql_cmd(query, results)) {
147 m_resultCount = results.count();
149 QStringList fieldlist;
150 mp_tableWidget->setRowCount(results.size());
153 /* Iterate through the record returned from the query */
155 foreach (resultline, results) {
156 fieldlist = resultline.split("\t");
157 if (fieldlist.size() < 13)
158 continue; /* some fields missing, ignore row */
160 TableItemFormatter jobitem(*mp_tableWidget, row);
162 /* Iterate through fields in the record */
163 QStringListIterator fld(fieldlist);
167 jobitem.setNumericFld(col++, fld.next());
170 jobitem.setTextFld(col++, fld.next());
173 jobitem.setTextFld(col++, fld.next());
176 jobitem.setTextFld(col++, fld.next(), true);
179 jobitem.setJobTypeFld(col++, fld.next());
182 jobitem.setJobLevelFld(col++, fld.next());
185 jobitem.setNumericFld(col++, fld.next());
188 jobitem.setBytesFld(col++, fld.next());
191 jobitem.setJobStatusFld(col++, fld.next());
194 jobitem.setBoolFld(col++, fld.next());
197 jobitem.setTextFld(col++, fld.next());
200 jobitem.setTextFld(col++, fld.next());
203 jobitem.setTextFld(col++, fld.next());
206 jobitem.setNumericFld(col++, fld.next());
210 /* set default sorting */
211 mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder);
212 mp_tableWidget->setSortingEnabled(true);
214 /* Resize the columns */
215 mp_tableWidget->resizeColumnsToContents();
216 mp_tableWidget->resizeRowsToContents();
217 mp_tableWidget->verticalHeader()->hide();
218 if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
219 /* for context sensitive searches, let the user know if there were no
221 QMessageBox::warning(this, "Bat",
222 tr("The Jobs query returned no results.\n"
223 "Press OK to continue?"), QMessageBox::Ok );
227 mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
230 void JobList::prepareFilterWidgets()
233 clientComboBox->addItem(tr("Any"));
234 clientComboBox->addItems(m_console->client_list);
235 comboSel(clientComboBox, m_clientName);
237 QStringList volumeList;
238 getVolumeList(volumeList);
239 volumeComboBox->addItem(tr("Any"));
240 volumeComboBox->addItems(volumeList);
241 comboSel(volumeComboBox, m_mediaName);
243 jobComboBox->addItem(tr("Any"));
244 jobComboBox->addItems(m_console->job_list);
245 comboSel(jobComboBox, m_jobName);
247 levelComboFill(levelComboBox);
249 boolComboFill(purgedComboBox);
251 fileSetComboBox->addItem(tr("Any"));
252 fileSetComboBox->addItems(m_console->fileset_list);
253 comboSel(fileSetComboBox, m_filesetName);
255 poolComboBox->addItem(tr("Any"));
256 poolComboBox->addItems(m_console->pool_list);
258 jobStatusComboFill(statusComboBox);
262 void JobList::fillQueryString(QString &query)
265 int volumeIndex = volumeComboBox->currentIndex();
266 if (volumeIndex != -1)
267 m_mediaName = volumeComboBox->itemText(volumeIndex);
268 QString distinct = "";
269 if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
270 query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, "
271 " Client.Name AS Client,"
272 " Job.Starttime AS JobStart, Job.Type AS JobType,"
273 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
274 " Job.JobBytes AS Bytes, Job.JobStatus AS Status,"
275 " Job.PurgedFiles AS Purged, FileSet.FileSet,"
276 " Pool.Name AS Pool,"
277 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume,"
278 " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes"
280 " JOIN Client ON (Client.ClientId=Job.ClientId)"
281 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) "
282 " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId ";
283 QStringList conditions;
284 if (m_mediaName != tr("Any")) {
285 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
286 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
287 conditions.append("Media.VolumeName='" + m_mediaName + "'");
290 comboCond(conditions, clientComboBox, "Client.Name");
291 comboCond(conditions, jobComboBox, "Job.Name");
292 levelComboCond(conditions, levelComboBox, "Job.Level");
293 jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus");
294 boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles");
295 comboCond(conditions, fileSetComboBox, "FileSet.FileSet");
296 comboCond(conditions, poolComboBox, "Pool.Name");
298 /* If Limit check box For limit by days is checked */
299 if (daysCheckBox->checkState() == Qt::Checked) {
300 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
301 QString since = stamp.toString(Qt::ISODate);
302 conditions.append("Job.Starttime > '" + since + "'");
304 if (filterCopyCheckBox->checkState() == Qt::Checked) {
305 conditions.append("Job.Type != 'c'" );
307 if (filterMigrationCheckBox->checkState() == Qt::Checked) {
308 conditions.append("Job.Type != 'g'" );
311 foreach (QString condition, conditions) {
313 query += " WHERE " + condition;
316 query += " AND " + condition;
320 query += " ORDER BY Job.JobId DESC";
321 /* If Limit check box for limit records returned is checked */
322 if (limitCheckBox->checkState() == Qt::Checked) {
324 limit.setNum(limitSpinBox->value());
325 query += " LIMIT " + limit;
330 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
331 * The tree has been populated.
333 void JobList::PgSeltreeWidgetClicked()
337 /* Lets make sure the splitter is not all the way to size index 0 == 0 */
338 QList<int> sizes = m_splitter->sizes();
340 int frameMax = frame->maximumHeight();
342 foreach(int size, sizes) { sizeSum += size; }
343 int tabHeight = mainWin->tabWidget->geometry().height();
345 sizes[1] = tabHeight - frameMax;
346 m_splitter->setSizes(sizes);
349 if (!isOnceDocked()) {
355 * Virtual function override of pages function which is called when this page
356 * is visible on the stack
358 void JobList::currentStackItem()
360 /* if (!m_populated) populate every time user comes back to this object */
365 * Virtual Function to return the name for the medialist tree widget
367 void JobList::treeWidgetName(QString &desc)
369 if (m_mediaName != "" ) {
370 desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
371 } else if (m_clientName != "" ) {
372 desc = tr("Jobs Run from Client %1").arg(m_clientName);
373 } else if (m_jobName != "" ) {
374 desc = tr("Jobs Run of Job %1").arg(m_jobName);
375 } else if (m_filesetName != "" ) {
376 desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
378 desc = tr("Jobs Run");
383 * Function to create connections for context sensitive menu for this and
386 void JobList::createConnections()
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, SLOT(populateTable()));
391 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
393 connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
395 graphButton->setEnabled(false);
396 graphButton->setVisible(false);
398 /* for the selectionChanged to maintain m_currentJob and a delete selection */
399 connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
400 connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
402 /* Do what is required for the local context sensitive menu */
405 /* setContextMenuPolicy is required */
406 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
408 connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
409 connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
410 connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
411 connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob()));
412 connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
413 connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
414 connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
415 connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
416 connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
417 connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
418 connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
419 connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
421 m_contextActions.append(actionRefreshJobList);
422 m_contextActions.append(actionListJobTotals);
426 * Functions to respond to local context sensitive menu sending console commands
427 * If I could figure out how to make these one function passing a string, Yaaaaaa
429 void JobList::consoleListFilesOnJob()
431 QString cmd("list files jobid=");
433 if (mainWin->m_longList) { cmd.prepend("l"); }
436 void JobList::consoleListJobMedia()
438 QString cmd("list jobmedia jobid=");
440 if (mainWin->m_longList) { cmd.prepend("l"); }
444 void JobList::consoleListJobTotals()
446 QString cmd("list jobtotals");
447 if (mainWin->m_longList) { cmd.prepend("l"); }
451 void JobList::consoleDeleteJob()
453 if (QMessageBox::warning(this, "Bat",
454 tr("Are you sure you want to delete?? !!!.\n"
455 "This delete command is used to delete a Job record and all associated catalog"
456 " records that were created. This command operates only on the Catalog"
457 " database and has no effect on the actual data written to a Volume. This"
458 " command can be dangerous and we strongly recommend that you do not use"
459 " it unless you know what you are doing. The Job and all its associated"
460 " records (File and JobMedia) will be deleted from the catalog."
461 "Press OK to proceed with delete operation.?"),
462 QMessageBox::Ok | QMessageBox::Cancel)
463 == QMessageBox::Cancel) { return; }
465 QString cmd("delete job jobid=");
466 cmd += m_selectedJobs;
467 consoleCommand(cmd, false);
471 void JobList::consoleRestartJob()
475 cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName);
476 if (m_filesetName != "" && m_filesetName != "*None*") {
477 cmd += tr(" fileset=\"%1\"").arg(m_filesetName);
480 if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data());
481 consoleCommand(cmd, false);
487 void JobList::consolePurgeFiles()
489 if (QMessageBox::warning(this, "Bat",
490 tr("Are you sure you want to purge ?? !!!.\n"
491 "The Purge command will delete associated Catalog database records from Jobs and"
492 " Volumes without considering the retention period. Purge works only on the"
493 " Catalog database and does not affect data written to Volumes. This command can"
494 " be dangerous because you can delete catalog records associated with current"
495 " backups of files, and we recommend that you do not use it unless you know what"
497 "Press OK to proceed with the purge operation?"),
498 QMessageBox::Ok | QMessageBox::Cancel)
499 == QMessageBox::Cancel) { return; }
501 m_console->m_warningPrevent = true;
502 foreach(QString job, m_selectedJobsList) {
503 QString cmd("purge files jobid=");
505 consoleCommand(cmd, false);
507 m_console->m_warningPrevent = false;
512 * Subroutine to call preRestore to restore from a select job
514 void JobList::preRestoreFromJob()
516 new prerestorePage(m_currentJob, R_JOBIDLIST);
520 * Subroutine to call preRestore to restore from a select job
522 void JobList::preRestoreFromTime()
524 new prerestorePage(m_currentJob, R_JOBDATETIME);
528 * Subroutine to call class to show the log in the database from that job
530 void JobList::showLogForJob()
532 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
533 new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
537 * Subroutine to call class to show the log in the database from that job
539 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
541 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
542 new Job(m_currentJob, pageSelectorTreeWidgetItem);
546 * Cancel a running job
548 void JobList::consoleCancelJob()
550 QString cmd("cancel jobid=");
558 void JobList::graphTable()
562 pass.recordLimitCheck = limitCheckBox->checkState();
563 pass.daysLimitCheck = daysCheckBox->checkState();
564 pass.recordLimitSpin = limitSpinBox->value();
565 pass.daysLimitSpin = daysSpinBox->value();
566 pass.jobCombo = jobComboBox->currentText();
567 pass.clientCombo = clientComboBox->currentText();
568 pass.volumeCombo = volumeComboBox->currentText();
569 pass.fileSetCombo = fileSetComboBox->currentText();
570 pass.purgedCombo = purgedComboBox->currentText();
571 pass.levelCombo = levelComboBox->currentText();
572 pass.statusCombo = statusComboBox->currentText();
574 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
575 new JobPlot(pageSelectorTreeWidgetItem, pass);
580 * Save user settings associated with this page
582 void JobList::writeSettings()
584 QSettings settings(m_console->m_dir->name(), "bat");
585 settings.beginGroup(m_groupText);
586 settings.setValue(m_splitText, m_splitter->saveState());
587 settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
588 settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
593 * Read and restore user settings associated with this page
595 void JobList::readSettings()
597 m_groupText = "JobListPage";
598 m_splitText = "splitterSizes_2";
599 QSettings settings(m_console->m_dir->name(), "bat");
600 settings.beginGroup(m_groupText);
601 if (settings.contains(m_splitText)) {
602 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
604 filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
605 filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
610 * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
612 void JobList::selectionChanged()
615 QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
616 foreach (QTableWidgetItem *sitem, sitems) {
617 int row = sitem->row();
618 if (!rowList.contains(row)) {
624 m_selectedJobsList.clear();
626 foreach(int row, rowList) {
627 QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
628 if (!first) m_selectedJobs.append(",");
630 m_selectedJobs.append(sitem->text());
631 m_selectedJobsList.append(sitem->text());
633 m_selectedJobsCount = rowList.count();
634 if (m_selectedJobsCount > 1) {
635 QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
636 actionDeleteJob->setText(text);
637 text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
638 actionPurgeFiles->setText(text);
640 actionDeleteJob->setText(tr("Delete Single Job"));
641 actionPurgeFiles->setText(tr("Purge Files from single job"));
644 /* remove all actions */
645 foreach(QAction* mediaAction, mp_tableWidget->actions()) {
646 mp_tableWidget->removeAction(mediaAction);
650 mp_tableWidget->addAction(actionRefreshJobList);
651 if (m_selectedJobsCount == 1) {
652 mp_tableWidget->addAction(actionListFilesOnJob);
653 mp_tableWidget->addAction(actionListJobMedia);
654 mp_tableWidget->addAction(actionRestartJob);
655 mp_tableWidget->addAction(actionRestoreFromJob);
656 mp_tableWidget->addAction(actionRestoreFromTime);
657 mp_tableWidget->addAction(actionShowLogForJob);
658 mp_tableWidget->addAction(actionShowInfoForJob);
660 if (m_selectedJobsCount >= 1) {
661 mp_tableWidget->addAction(actionDeleteJob);
662 mp_tableWidget->addAction(actionPurgeFiles);
665 /* Make Connections */
666 if (m_checkCurrentWidget) {
667 int row = mp_tableWidget->currentRow();
668 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
669 m_currentJob = jobitem->text(); /* get JobId */
670 jobitem = mp_tableWidget->item(row, m_clientIndex);
671 m_clientName = jobitem->text(); /* get Client Name */
672 jobitem = mp_tableWidget->item(row, m_nameIndex);
673 m_jobName = jobitem->text(); /* get Job Name */
674 jobitem = mp_tableWidget->item(row, m_levelIndex);
675 m_levelName = jobitem->text(); /* get level */
676 jobitem = mp_tableWidget->item(row, m_filesetIndex);
678 m_filesetName = jobitem->text(); /* get FileSet Name */
683 /* include purged action or not */
684 jobitem = mp_tableWidget->item(row, m_purgedIndex);
685 QString purged = jobitem->text();
686 /* mp_tableWidget->removeAction(actionPurgeFiles);
687 if (purged == tr("No") ) {
688 mp_tableWidget->addAction(actionPurgeFiles);
691 /* include restore from time and job action or not */
692 jobitem = mp_tableWidget->item(row, m_typeIndex);
693 QString type = jobitem->text();
694 if (m_selectedJobsCount == 1) {
695 mp_tableWidget->removeAction(actionRestoreFromJob);
696 mp_tableWidget->removeAction(actionRestoreFromTime);
697 if (type == tr("Backup")) {
698 mp_tableWidget->addAction(actionRestoreFromJob);
699 mp_tableWidget->addAction(actionRestoreFromTime);
703 /* include cancel action or not */
704 jobitem = mp_tableWidget->item(row, m_statusIndex);
705 QString status = jobitem->text();
706 mp_tableWidget->removeAction(actionCancelJob);
707 if (status == tr("Running") || status == tr("Created, not yet running")) {
708 mp_tableWidget->addAction(actionCancelJob);
714 * Function to prevent the splitter from making index 0 of the size larger than it
717 void JobList::splitterMoved(int /*pos*/, int /*index*/)
719 int frameMax = frame->maximumHeight();
720 QList<int> sizes = m_splitter->sizes();
722 foreach(int size, sizes) { sizeSum += size; }
723 if (sizes[0] > frameMax) {
725 sizes[1] = sizeSum - frameMax;
726 m_splitter->setSizes(sizes);