2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
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 three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
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.
18 You should have received a copy of the GNU Affero 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
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.
31 * Dirk Bartley, March 2007
35 #include <QAbstractEventDispatcher>
36 #include <QTableWidgetItem>
40 #include "joblog/joblog.h"
42 #include "jobgraphs/jobplot.h"
44 #include "util/fmtwidgetitem.h"
45 #include "util/comboutil.h"
48 * Constructor for the class
50 JobList::JobList(const QString &mediaName, const QString &clientName,
51 const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
54 m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */
55 m_mediaName = mediaName;
56 m_clientName = clientName;
58 m_filesetName = filesetName;
59 pgInitialize("", parentTreeWidgetItem);
60 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
61 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
66 if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) {
69 m_checkCurrentWidget = true;
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);
77 QGridLayout *gridLayout = new QGridLayout(this);
78 gridLayout->setSpacing(6);
79 gridLayout->setMargin(9);
80 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
82 m_splitter = new QSplitter(Qt::Vertical, this);
83 QScrollArea *area = new QScrollArea();
84 area->setObjectName(QString::fromUtf8("area"));
85 area->setWidget(frame);
86 area->setWidgetResizable(true);
87 m_splitter->addWidget(area);
88 m_splitter->addWidget(mp_tableWidget);
90 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
93 if (m_closeable) { dockPage(); }
97 * Write the m_splitter settings in the destructor
105 * The Meat of the class.
106 * This function will populate the QTableWidget, mp_tablewidget, with
107 * QTableWidgetItems representing the results of a query for what jobs exist on
108 * the media name passed from the constructor stored in m_mediaName.
110 void JobList::populateTable()
112 /* Can't do this in constructor because not neccesarily conected in constructor */
113 prepareFilterWidgets();
116 Freeze frz(*mp_tableWidget); /* disable updating*/
120 fillQueryString(query);
122 /* Set up the Header for the table */
123 QStringList headerlist = (QStringList()
124 << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime")
125 << tr("Job Type") << tr("Job Level") << tr("Job Files")
126 << tr("Job Bytes") << tr("Job Status") << tr("Purged") << tr("File Set")
127 << tr("Pool Name") << tr("First Volume") << tr("VolCount"));
129 m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
130 m_purgedIndex = headerlist.indexOf(tr("Purged"));
131 m_typeIndex = headerlist.indexOf(tr("Job Type"));
132 m_statusIndex = headerlist.indexOf(tr("Job Status"));
133 m_startIndex = headerlist.indexOf(tr("Job Starttime"));
134 m_filesIndex = headerlist.indexOf(tr("Job Files"));
135 m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
136 m_levelIndex = headerlist.indexOf(tr("Job Level"));
137 m_nameIndex = headerlist.indexOf(tr("Job Name"));
138 m_filesetIndex = headerlist.indexOf(tr("File Set"));
139 m_clientIndex = headerlist.indexOf(tr("Client"));
141 /* Initialize the QTableWidget */
142 m_checkCurrentWidget = false;
143 mp_tableWidget->clear();
144 m_checkCurrentWidget = true;
145 mp_tableWidget->setColumnCount(headerlist.size());
146 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
147 mp_tableWidget->horizontalHeader()->setHighlightSections(false);
148 mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
149 mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
151 if (mainWin->m_sqlDebug) {
152 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
156 if (m_console->sql_cmd(query, results)) {
157 m_resultCount = results.count();
159 QStringList fieldlist;
160 mp_tableWidget->setRowCount(results.size());
163 /* Iterate through the record returned from the query */
165 foreach (resultline, results) {
166 fieldlist = resultline.split("\t");
167 if (fieldlist.size() < 13)
168 continue; /* some fields missing, ignore row */
170 TableItemFormatter jobitem(*mp_tableWidget, row);
172 /* Iterate through fields in the record */
173 QStringListIterator fld(fieldlist);
177 jobitem.setNumericFld(col++, fld.next());
180 jobitem.setTextFld(col++, fld.next());
183 jobitem.setTextFld(col++, fld.next());
186 jobitem.setTextFld(col++, fld.next(), true);
189 jobitem.setJobTypeFld(col++, fld.next());
192 jobitem.setJobLevelFld(col++, fld.next());
195 jobitem.setNumericFld(col++, fld.next());
198 jobitem.setBytesFld(col++, fld.next());
201 jobitem.setJobStatusFld(col++, fld.next());
204 jobitem.setBoolFld(col++, fld.next());
207 jobitem.setTextFld(col++, fld.next());
210 jobitem.setTextFld(col++, fld.next());
213 jobitem.setTextFld(col++, fld.next());
216 jobitem.setNumericFld(col++, fld.next());
220 /* set default sorting */
221 mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder);
222 mp_tableWidget->setSortingEnabled(true);
224 /* Resize the columns */
225 mp_tableWidget->resizeColumnsToContents();
226 mp_tableWidget->resizeRowsToContents();
227 mp_tableWidget->verticalHeader()->hide();
228 if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
229 /* for context sensitive searches, let the user know if there were no
231 QMessageBox::warning(this, "Bat",
232 tr("The Jobs query returned no results.\n"
233 "Press OK to continue?"), QMessageBox::Ok );
237 mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
240 void JobList::prepareFilterWidgets()
243 clientComboBox->addItem(tr("Any"));
244 clientComboBox->addItems(m_console->client_list);
245 comboSel(clientComboBox, m_clientName);
247 QStringList volumeList;
248 getVolumeList(volumeList);
249 volumeComboBox->addItem(tr("Any"));
250 volumeComboBox->addItems(volumeList);
251 comboSel(volumeComboBox, m_mediaName);
253 jobComboBox->addItem(tr("Any"));
254 jobComboBox->addItems(m_console->job_list);
255 comboSel(jobComboBox, m_jobName);
257 levelComboFill(levelComboBox);
259 boolComboFill(purgedComboBox);
261 fileSetComboBox->addItem(tr("Any"));
262 fileSetComboBox->addItems(m_console->fileset_list);
263 comboSel(fileSetComboBox, m_filesetName);
265 poolComboBox->addItem(tr("Any"));
266 poolComboBox->addItems(m_console->pool_list);
268 jobStatusComboFill(statusComboBox);
272 void JobList::fillQueryString(QString &query)
275 int volumeIndex = volumeComboBox->currentIndex();
276 if (volumeIndex != -1)
277 m_mediaName = volumeComboBox->itemText(volumeIndex);
278 QString distinct = "";
279 if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
280 query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, "
281 " Client.Name AS Client,"
282 " Job.Starttime AS JobStart, Job.Type AS JobType,"
283 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
284 " Job.JobBytes AS Bytes, Job.JobStatus AS Status,"
285 " Job.PurgedFiles AS Purged, FileSet.FileSet,"
286 " Pool.Name AS Pool,"
287 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume,"
288 " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes"
290 " JOIN Client ON (Client.ClientId=Job.ClientId)"
291 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) "
292 " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId ";
293 QStringList conditions;
294 if (m_mediaName != tr("Any")) {
295 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
296 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
297 conditions.append("Media.VolumeName='" + m_mediaName + "'");
300 comboCond(conditions, clientComboBox, "Client.Name");
301 comboCond(conditions, jobComboBox, "Job.Name");
302 levelComboCond(conditions, levelComboBox, "Job.Level");
303 jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus");
304 boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles");
305 comboCond(conditions, fileSetComboBox, "FileSet.FileSet");
306 comboCond(conditions, poolComboBox, "Pool.Name");
308 /* If Limit check box For limit by days is checked */
309 if (daysCheckBox->checkState() == Qt::Checked) {
310 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
311 QString since = stamp.toString(Qt::ISODate);
312 conditions.append("Job.Starttime > '" + since + "'");
314 if (filterCopyCheckBox->checkState() == Qt::Checked) {
315 conditions.append("Job.Type != 'c'" );
317 if (filterMigrationCheckBox->checkState() == Qt::Checked) {
318 conditions.append("Job.Type != 'g'" );
321 foreach (QString condition, conditions) {
323 query += " WHERE " + condition;
326 query += " AND " + condition;
330 query += " ORDER BY Job.JobId DESC";
331 /* If Limit check box for limit records returned is checked */
332 if (limitCheckBox->checkState() == Qt::Checked) {
334 limit.setNum(limitSpinBox->value());
335 query += " LIMIT " + limit;
340 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
341 * The tree has been populated.
343 void JobList::PgSeltreeWidgetClicked()
347 /* Lets make sure the splitter is not all the way to size index 0 == 0 */
348 QList<int> sizes = m_splitter->sizes();
350 int frameMax = frame->maximumHeight();
352 foreach(int size, sizes) { sizeSum += size; }
353 int tabHeight = mainWin->tabWidget->geometry().height();
355 sizes[1] = tabHeight - frameMax;
356 m_splitter->setSizes(sizes);
359 if (!isOnceDocked()) {
365 * Virtual function override of pages function which is called when this page
366 * is visible on the stack
368 void JobList::currentStackItem()
370 /* if (!m_populated) populate every time user comes back to this object */
375 * Virtual Function to return the name for the medialist tree widget
377 void JobList::treeWidgetName(QString &desc)
379 if (m_mediaName != "" ) {
380 desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
381 } else if (m_clientName != "" ) {
382 desc = tr("Jobs Run from Client %1").arg(m_clientName);
383 } else if (m_jobName != "" ) {
384 desc = tr("Jobs Run of Job %1").arg(m_jobName);
385 } else if (m_filesetName != "" ) {
386 desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
388 desc = tr("Jobs Run");
393 * Function to create connections for context sensitive menu for this and
396 void JobList::createConnections()
398 /* connect to the action specific to this pages class that shows up in the
399 * page selector tree */
400 connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable()));
401 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
403 connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
405 graphButton->setEnabled(false);
406 graphButton->setVisible(false);
408 /* for the selectionChanged to maintain m_currentJob and a delete selection */
409 connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
410 connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
412 /* Do what is required for the local context sensitive menu */
415 /* setContextMenuPolicy is required */
416 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
418 connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
419 connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
420 connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
421 connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob()));
422 connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
423 connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
424 connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
425 connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
426 connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
427 connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
428 connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
429 connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
431 m_contextActions.append(actionRefreshJobList);
432 m_contextActions.append(actionListJobTotals);
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
439 void JobList::consoleListFilesOnJob()
441 QString cmd("list files jobid=");
443 if (mainWin->m_longList) { cmd.prepend("l"); }
446 void JobList::consoleListJobMedia()
448 QString cmd("list jobmedia jobid=");
450 if (mainWin->m_longList) { cmd.prepend("l"); }
454 void JobList::consoleListJobTotals()
456 QString cmd("list jobtotals");
457 if (mainWin->m_longList) { cmd.prepend("l"); }
461 void JobList::consoleDeleteJob()
463 if (QMessageBox::warning(this, "Bat",
464 tr("Are you sure you want to delete?? !!!.\n"
465 "This delete command is used to delete a Job record and all associated catalog"
466 " records that were created. This command operates only on the Catalog"
467 " database and has no effect on the actual data written to a Volume. This"
468 " command can be dangerous and we strongly recommend that you do not use"
469 " it unless you know what you are doing. The Job and all its associated"
470 " records (File and JobMedia) will be deleted from the catalog."
471 "Press OK to proceed with delete operation.?"),
472 QMessageBox::Ok | QMessageBox::Cancel)
473 == QMessageBox::Cancel) { return; }
475 QString cmd("delete job jobid=");
476 cmd += m_selectedJobs;
477 consoleCommand(cmd, false);
481 void JobList::consoleRestartJob()
485 cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName);
486 if (m_filesetName != "" && m_filesetName != "*None*") {
487 cmd += tr(" fileset=\"%1\"").arg(m_filesetName);
490 if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data());
491 consoleCommand(cmd, false);
497 void JobList::consolePurgeFiles()
499 if (QMessageBox::warning(this, "Bat",
500 tr("Are you sure you want to purge ?? !!!.\n"
501 "The Purge command will delete associated Catalog database records from Jobs and"
502 " Volumes without considering the retention period. Purge works only on the"
503 " Catalog database and does not affect data written to Volumes. This command can"
504 " be dangerous because you can delete catalog records associated with current"
505 " backups of files, and we recommend that you do not use it unless you know what"
507 "Press OK to proceed with the purge operation?"),
508 QMessageBox::Ok | QMessageBox::Cancel)
509 == QMessageBox::Cancel) { return; }
511 m_console->m_warningPrevent = true;
512 foreach(QString job, m_selectedJobsList) {
513 QString cmd("purge files jobid=");
515 consoleCommand(cmd, false);
517 m_console->m_warningPrevent = false;
522 * Subroutine to call preRestore to restore from a select job
524 void JobList::preRestoreFromJob()
526 new prerestorePage(m_currentJob, R_JOBIDLIST);
530 * Subroutine to call preRestore to restore from a select job
532 void JobList::preRestoreFromTime()
534 new prerestorePage(m_currentJob, R_JOBDATETIME);
538 * Subroutine to call class to show the log in the database from that job
540 void JobList::showLogForJob()
542 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
543 new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
547 * Subroutine to call class to show the log in the database from that job
549 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
551 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
552 new Job(m_currentJob, pageSelectorTreeWidgetItem);
556 * Cancel a running job
558 void JobList::consoleCancelJob()
560 QString cmd("cancel jobid=");
568 void JobList::graphTable()
572 pass.recordLimitCheck = limitCheckBox->checkState();
573 pass.daysLimitCheck = daysCheckBox->checkState();
574 pass.recordLimitSpin = limitSpinBox->value();
575 pass.daysLimitSpin = daysSpinBox->value();
576 pass.jobCombo = jobComboBox->currentText();
577 pass.clientCombo = clientComboBox->currentText();
578 pass.volumeCombo = volumeComboBox->currentText();
579 pass.fileSetCombo = fileSetComboBox->currentText();
580 pass.purgedCombo = purgedComboBox->currentText();
581 pass.levelCombo = levelComboBox->currentText();
582 pass.statusCombo = statusComboBox->currentText();
584 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
585 new JobPlot(pageSelectorTreeWidgetItem, pass);
590 * Save user settings associated with this page
592 void JobList::writeSettings()
594 QSettings settings(m_console->m_dir->name(), "bat");
595 settings.beginGroup(m_groupText);
596 settings.setValue(m_splitText, m_splitter->saveState());
597 settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
598 settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
603 * Read and restore user settings associated with this page
605 void JobList::readSettings()
607 m_groupText = "JobListPage";
608 m_splitText = "splitterSizes_2";
609 QSettings settings(m_console->m_dir->name(), "bat");
610 settings.beginGroup(m_groupText);
611 if (settings.contains(m_splitText)) {
612 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
614 filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
615 filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
620 * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
622 void JobList::selectionChanged()
625 QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
626 foreach (QTableWidgetItem *sitem, sitems) {
627 int row = sitem->row();
628 if (!rowList.contains(row)) {
634 m_selectedJobsList.clear();
636 foreach(int row, rowList) {
637 QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
638 if (!first) m_selectedJobs.append(",");
640 m_selectedJobs.append(sitem->text());
641 m_selectedJobsList.append(sitem->text());
643 m_selectedJobsCount = rowList.count();
644 if (m_selectedJobsCount > 1) {
645 QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
646 actionDeleteJob->setText(text);
647 text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
648 actionPurgeFiles->setText(text);
650 actionDeleteJob->setText(tr("Delete Single Job"));
651 actionPurgeFiles->setText(tr("Purge Files from single job"));
654 /* remove all actions */
655 foreach(QAction* mediaAction, mp_tableWidget->actions()) {
656 mp_tableWidget->removeAction(mediaAction);
660 mp_tableWidget->addAction(actionRefreshJobList);
661 if (m_selectedJobsCount == 1) {
662 mp_tableWidget->addAction(actionListFilesOnJob);
663 mp_tableWidget->addAction(actionListJobMedia);
664 mp_tableWidget->addAction(actionRestartJob);
665 mp_tableWidget->addAction(actionRestoreFromJob);
666 mp_tableWidget->addAction(actionRestoreFromTime);
667 mp_tableWidget->addAction(actionShowLogForJob);
668 mp_tableWidget->addAction(actionShowInfoForJob);
670 if (m_selectedJobsCount >= 1) {
671 mp_tableWidget->addAction(actionDeleteJob);
672 mp_tableWidget->addAction(actionPurgeFiles);
675 /* Make Connections */
676 if (m_checkCurrentWidget) {
677 int row = mp_tableWidget->currentRow();
678 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
679 m_currentJob = jobitem->text(); /* get JobId */
680 jobitem = mp_tableWidget->item(row, m_clientIndex);
681 m_clientName = jobitem->text(); /* get Client Name */
682 jobitem = mp_tableWidget->item(row, m_nameIndex);
683 m_jobName = jobitem->text(); /* get Job Name */
684 jobitem = mp_tableWidget->item(row, m_levelIndex);
685 m_levelName = jobitem->text(); /* get level */
686 jobitem = mp_tableWidget->item(row, m_filesetIndex);
688 m_filesetName = jobitem->text(); /* get FileSet Name */
693 /* include purged action or not */
694 jobitem = mp_tableWidget->item(row, m_purgedIndex);
695 QString purged = jobitem->text();
696 /* mp_tableWidget->removeAction(actionPurgeFiles);
697 if (purged == tr("No") ) {
698 mp_tableWidget->addAction(actionPurgeFiles);
701 /* include restore from time and job action or not */
702 jobitem = mp_tableWidget->item(row, m_typeIndex);
703 QString type = jobitem->text();
704 if (m_selectedJobsCount == 1) {
705 mp_tableWidget->removeAction(actionRestoreFromJob);
706 mp_tableWidget->removeAction(actionRestoreFromTime);
707 if (type == tr("Backup")) {
708 mp_tableWidget->addAction(actionRestoreFromJob);
709 mp_tableWidget->addAction(actionRestoreFromTime);
713 /* include cancel action or not */
714 jobitem = mp_tableWidget->item(row, m_statusIndex);
715 QString status = jobitem->text();
716 mp_tableWidget->removeAction(actionCancelJob);
717 if (status == tr("Running") || status == tr("Created, not yet running")) {
718 mp_tableWidget->addAction(actionCancelJob);
724 * Function to prevent the splitter from making index 0 of the size larger than it
727 void JobList::splitterMoved(int /*pos*/, int /*index*/)
729 int frameMax = frame->maximumHeight();
730 QList<int> sizes = m_splitter->sizes();
732 foreach(int size, sizes) { sizeSum += size; }
733 if (sizes[0] > frameMax) {
735 sizes[1] = sizeSum - frameMax;
736 m_splitter->setSizes(sizes);