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)
55 m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */
56 m_mediaName = mediaName;
57 m_clientName = clientName;
59 m_filesetName = filesetName;
60 pgInitialize("", parentTreeWidgetItem);
61 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
62 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
67 if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) {
70 m_checkCurrentWidget = true;
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);
78 QGridLayout *gridLayout = new QGridLayout(this);
79 gridLayout->setSpacing(6);
80 gridLayout->setMargin(9);
81 gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
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);
91 gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
94 if (m_closeable) { dockPage(); }
98 * Write the m_splitter settings in the destructor
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.
111 void JobList::populateTable()
113 /* Can't do this in constructor because not neccesarily conected in constructor */
114 prepareFilterWidgets();
117 Freeze frz(*mp_tableWidget); /* disable updating*/
121 fillQueryString(query);
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"));
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 m_levelIndex = headerlist.indexOf(tr("Job Level"));
138 m_nameIndex = headerlist.indexOf(tr("Job Name"));
139 m_filesetIndex = headerlist.indexOf(tr("File Set"));
140 m_clientIndex = headerlist.indexOf(tr("Client"));
142 /* Initialize the QTableWidget */
143 m_checkCurrentWidget = false;
144 mp_tableWidget->clear();
145 m_checkCurrentWidget = true;
146 mp_tableWidget->setColumnCount(headerlist.size());
147 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
148 mp_tableWidget->horizontalHeader()->setHighlightSections(false);
149 mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
150 mp_tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
152 if (mainWin->m_sqlDebug) {
153 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
157 if (m_console->sql_cmd(query, results)) {
158 m_resultCount = results.count();
160 QStringList fieldlist;
161 mp_tableWidget->setRowCount(results.size());
164 /* Iterate through the record returned from the query */
166 foreach (resultline, results) {
167 fieldlist = resultline.split("\t");
168 if (fieldlist.size() < 13)
169 continue; /* some fields missing, ignore row */
171 TableItemFormatter jobitem(*mp_tableWidget, row);
173 /* Iterate through fields in the record */
174 QStringListIterator fld(fieldlist);
178 jobitem.setNumericFld(col++, fld.next());
181 jobitem.setTextFld(col++, fld.next());
184 jobitem.setTextFld(col++, fld.next());
187 jobitem.setTextFld(col++, fld.next(), true);
190 jobitem.setJobTypeFld(col++, fld.next());
193 jobitem.setJobLevelFld(col++, fld.next());
196 jobitem.setNumericFld(col++, fld.next());
199 jobitem.setBytesFld(col++, fld.next());
202 jobitem.setJobStatusFld(col++, fld.next());
205 jobitem.setBoolFld(col++, fld.next());
208 jobitem.setTextFld(col++, fld.next());
211 jobitem.setTextFld(col++, fld.next());
214 jobitem.setTextFld(col++, fld.next());
217 jobitem.setNumericFld(col++, fld.next());
221 /* set default sorting */
222 mp_tableWidget->sortByColumn(m_jobIdIndex, Qt::DescendingOrder);
223 mp_tableWidget->setSortingEnabled(true);
225 /* Resize the columns */
226 mp_tableWidget->resizeColumnsToContents();
227 mp_tableWidget->resizeRowsToContents();
228 mp_tableWidget->verticalHeader()->hide();
229 if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
230 /* for context sensitive searches, let the user know if there were no
232 QMessageBox::warning(this, "Bat",
233 tr("The Jobs query returned no results.\n"
234 "Press OK to continue?"), QMessageBox::Ok );
238 mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
241 void JobList::prepareFilterWidgets()
244 clientComboBox->addItem(tr("Any"));
245 clientComboBox->addItems(m_console->client_list);
246 comboSel(clientComboBox, m_clientName);
248 QStringList volumeList;
249 getVolumeList(volumeList);
250 volumeComboBox->addItem(tr("Any"));
251 volumeComboBox->addItems(volumeList);
252 comboSel(volumeComboBox, m_mediaName);
254 jobComboBox->addItem(tr("Any"));
255 jobComboBox->addItems(m_console->job_list);
256 comboSel(jobComboBox, m_jobName);
258 levelComboFill(levelComboBox);
260 boolComboFill(purgedComboBox);
262 fileSetComboBox->addItem(tr("Any"));
263 fileSetComboBox->addItems(m_console->fileset_list);
264 comboSel(fileSetComboBox, m_filesetName);
266 poolComboBox->addItem(tr("Any"));
267 poolComboBox->addItems(m_console->pool_list);
269 jobStatusComboFill(statusComboBox);
273 void JobList::fillQueryString(QString &query)
276 int volumeIndex = volumeComboBox->currentIndex();
277 if (volumeIndex != -1)
278 m_mediaName = volumeComboBox->itemText(volumeIndex);
279 QString distinct = "";
280 if (m_mediaName != tr("Any")) { distinct = "DISTINCT "; }
281 query += "SELECT " + distinct + "Job.JobId AS JobId, Job.Name AS JobName, "
282 " Client.Name AS Client,"
283 " Job.Starttime AS JobStart, Job.Type AS JobType,"
284 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
285 " Job.JobBytes AS Bytes, Job.JobStatus AS Status,"
286 " Job.PurgedFiles AS Purged, FileSet.FileSet,"
287 " Pool.Name AS Pool,"
288 " (SELECT Media.VolumeName FROM JobMedia JOIN Media ON JobMedia.MediaId=Media.MediaId WHERE JobMedia.JobId=Job.JobId ORDER BY JobMediaId LIMIT 1) AS FirstVolume,"
289 " (SELECT count(DISTINCT MediaId) FROM JobMedia WHERE JobMedia.JobId=Job.JobId) AS Volumes"
291 " JOIN Client ON (Client.ClientId=Job.ClientId)"
292 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId) "
293 " LEFT OUTER JOIN Pool ON Job.PoolId = Pool.PoolId ";
294 QStringList conditions;
295 if (m_mediaName != tr("Any")) {
296 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId) "
297 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId) ";
298 conditions.append("Media.VolumeName='" + m_mediaName + "'");
301 comboCond(conditions, clientComboBox, "Client.Name");
302 comboCond(conditions, jobComboBox, "Job.Name");
303 levelComboCond(conditions, levelComboBox, "Job.Level");
304 jobStatusComboCond(conditions, statusComboBox, "Job.JobStatus");
305 boolComboCond(conditions, purgedComboBox, "Job.PurgedFiles");
306 comboCond(conditions, fileSetComboBox, "FileSet.FileSet");
307 comboCond(conditions, poolComboBox, "Pool.Name");
309 /* If Limit check box For limit by days is checked */
310 if (daysCheckBox->checkState() == Qt::Checked) {
311 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
312 QString since = stamp.toString(Qt::ISODate);
313 conditions.append("Job.Starttime > '" + since + "'");
315 if (filterCopyCheckBox->checkState() == Qt::Checked) {
316 conditions.append("Job.Type != 'c'" );
318 if (filterMigrationCheckBox->checkState() == Qt::Checked) {
319 conditions.append("Job.Type != 'g'" );
322 foreach (QString condition, conditions) {
324 query += " WHERE " + condition;
327 query += " AND " + condition;
331 query += " ORDER BY Job.JobId DESC";
332 /* If Limit check box for limit records returned is checked */
333 if (limitCheckBox->checkState() == Qt::Checked) {
335 limit.setNum(limitSpinBox->value());
336 query += " LIMIT " + limit;
341 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
342 * The tree has been populated.
344 void JobList::PgSeltreeWidgetClicked()
348 /* Lets make sure the splitter is not all the way to size index 0 == 0 */
349 QList<int> sizes = m_splitter->sizes();
351 int frameMax = frame->maximumHeight();
353 foreach(int size, sizes) { sizeSum += size; }
354 int tabHeight = mainWin->tabWidget->geometry().height();
356 sizes[1] = tabHeight - frameMax;
357 m_splitter->setSizes(sizes);
360 if (!isOnceDocked()) {
366 * Virtual function override of pages function which is called when this page
367 * is visible on the stack
369 void JobList::currentStackItem()
371 /* if (!m_populated) populate every time user comes back to this object */
376 * Virtual Function to return the name for the medialist tree widget
378 void JobList::treeWidgetName(QString &desc)
380 if (m_mediaName != "" ) {
381 desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
382 } else if (m_clientName != "" ) {
383 desc = tr("Jobs Run from Client %1").arg(m_clientName);
384 } else if (m_jobName != "" ) {
385 desc = tr("Jobs Run of Job %1").arg(m_jobName);
386 } else if (m_filesetName != "" ) {
387 desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
389 desc = tr("Jobs Run");
394 * Function to create connections for context sensitive menu for this and
397 void JobList::createConnections()
399 /* connect to the action specific to this pages class that shows up in the
400 * page selector tree */
401 connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable()));
402 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
404 connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
406 graphButton->setEnabled(false);
407 graphButton->setVisible(false);
409 /* for the selectionChanged to maintain m_currentJob and a delete selection */
410 connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
411 connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
413 /* Do what is required for the local context sensitive menu */
416 /* setContextMenuPolicy is required */
417 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
419 connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
420 connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
421 connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
422 connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob()));
423 connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
424 connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
425 connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
426 connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
427 connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
428 connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
429 connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
430 connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
432 m_contextActions.append(actionRefreshJobList);
433 m_contextActions.append(actionListJobTotals);
437 * Functions to respond to local context sensitive menu sending console commands
438 * If I could figure out how to make these one function passing a string, Yaaaaaa
440 void JobList::consoleListFilesOnJob()
442 QString cmd("list files jobid=");
444 if (mainWin->m_longList) { cmd.prepend("l"); }
447 void JobList::consoleListJobMedia()
449 QString cmd("list jobmedia jobid=");
451 if (mainWin->m_longList) { cmd.prepend("l"); }
455 void JobList::consoleListJobTotals()
457 QString cmd("list jobtotals");
458 if (mainWin->m_longList) { cmd.prepend("l"); }
462 void JobList::consoleDeleteJob()
464 if (QMessageBox::warning(this, "Bat",
465 tr("Are you sure you want to delete?? !!!.\n"
466 "This delete command is used to delete a Job record and all associated catalog"
467 " records that were created. This command operates only on the Catalog"
468 " database and has no effect on the actual data written to a Volume. This"
469 " command can be dangerous and we strongly recommend that you do not use"
470 " it unless you know what you are doing. The Job and all its associated"
471 " records (File and JobMedia) will be deleted from the catalog."
472 "Press OK to proceed with delete operation.?"),
473 QMessageBox::Ok | QMessageBox::Cancel)
474 == QMessageBox::Cancel) { return; }
476 QString cmd("delete job jobid=");
477 cmd += m_selectedJobs;
478 consoleCommand(cmd, false);
482 void JobList::consoleRestartJob()
486 cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName);
487 if (m_filesetName != "" && m_filesetName != "*None*") {
488 cmd += tr(" fileset=\"%1\"").arg(m_filesetName);
491 if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data());
492 consoleCommand(cmd, false);
498 void JobList::consolePurgeFiles()
500 if (QMessageBox::warning(this, "Bat",
501 tr("Are you sure you want to purge ?? !!!.\n"
502 "The Purge command will delete associated Catalog database records from Jobs and"
503 " Volumes without considering the retention period. Purge works only on the"
504 " Catalog database and does not affect data written to Volumes. This command can"
505 " be dangerous because you can delete catalog records associated with current"
506 " backups of files, and we recommend that you do not use it unless you know what"
508 "Press OK to proceed with the purge operation?"),
509 QMessageBox::Ok | QMessageBox::Cancel)
510 == QMessageBox::Cancel) { return; }
512 m_console->m_warningPrevent = true;
513 foreach(QString job, m_selectedJobsList) {
514 QString cmd("purge files jobid=");
516 consoleCommand(cmd, false);
518 m_console->m_warningPrevent = false;
523 * Subroutine to call preRestore to restore from a select job
525 void JobList::preRestoreFromJob()
527 new prerestorePage(m_currentJob, R_JOBIDLIST);
531 * Subroutine to call preRestore to restore from a select job
533 void JobList::preRestoreFromTime()
535 new prerestorePage(m_currentJob, R_JOBDATETIME);
539 * Subroutine to call class to show the log in the database from that job
541 void JobList::showLogForJob()
543 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
544 new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
548 * Subroutine to call class to show the log in the database from that job
550 void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
552 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
553 new Job(m_currentJob, pageSelectorTreeWidgetItem);
557 * Cancel a running job
559 void JobList::consoleCancelJob()
561 QString cmd("cancel jobid=");
569 void JobList::graphTable()
573 pass.recordLimitCheck = limitCheckBox->checkState();
574 pass.daysLimitCheck = daysCheckBox->checkState();
575 pass.recordLimitSpin = limitSpinBox->value();
576 pass.daysLimitSpin = daysSpinBox->value();
577 pass.jobCombo = jobComboBox->currentText();
578 pass.clientCombo = clientComboBox->currentText();
579 pass.volumeCombo = volumeComboBox->currentText();
580 pass.fileSetCombo = fileSetComboBox->currentText();
581 pass.purgedCombo = purgedComboBox->currentText();
582 pass.levelCombo = levelComboBox->currentText();
583 pass.statusCombo = statusComboBox->currentText();
585 QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
586 new JobPlot(pageSelectorTreeWidgetItem, pass);
591 * Save user settings associated with this page
593 void JobList::writeSettings()
595 QSettings settings(m_console->m_dir->name(), "bat");
596 settings.beginGroup(m_groupText);
597 settings.setValue(m_splitText, m_splitter->saveState());
598 settings.setValue("FilterCopyCheckState", filterCopyCheckBox->checkState());
599 settings.setValue("FilterMigrationCheckState", filterMigrationCheckBox->checkState());
604 * Read and restore user settings associated with this page
606 void JobList::readSettings()
608 m_groupText = "JobListPage";
609 m_splitText = "splitterSizes_2";
610 QSettings settings(m_console->m_dir->name(), "bat");
611 settings.beginGroup(m_groupText);
612 if (settings.contains(m_splitText)) {
613 m_splitter->restoreState(settings.value(m_splitText).toByteArray());
615 filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
616 filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
621 * Function to fill m_selectedJobsCount and m_selectedJobs with selected values
623 void JobList::selectionChanged()
626 QList<QTableWidgetItem *> sitems = mp_tableWidget->selectedItems();
627 foreach (QTableWidgetItem *sitem, sitems) {
628 int row = sitem->row();
629 if (!rowList.contains(row)) {
635 m_selectedJobsList.clear();
637 foreach(int row, rowList) {
638 QTableWidgetItem * sitem = mp_tableWidget->item(row, m_jobIdIndex);
639 if (!first) m_selectedJobs.append(",");
641 m_selectedJobs.append(sitem->text());
642 m_selectedJobsList.append(sitem->text());
644 m_selectedJobsCount = rowList.count();
645 if (m_selectedJobsCount > 1) {
646 QString text = QString( tr("Delete list of %1 Jobs")).arg(m_selectedJobsCount);
647 actionDeleteJob->setText(text);
648 text = QString( tr("Purge Files from list of %1 Jobs")).arg(m_selectedJobsCount);
649 actionPurgeFiles->setText(text);
651 actionDeleteJob->setText(tr("Delete Single Job"));
652 actionPurgeFiles->setText(tr("Purge Files from single job"));
655 /* remove all actions */
656 foreach(QAction* mediaAction, mp_tableWidget->actions()) {
657 mp_tableWidget->removeAction(mediaAction);
661 mp_tableWidget->addAction(actionRefreshJobList);
662 if (m_selectedJobsCount == 1) {
663 mp_tableWidget->addAction(actionListFilesOnJob);
664 mp_tableWidget->addAction(actionListJobMedia);
665 mp_tableWidget->addAction(actionRestartJob);
666 mp_tableWidget->addAction(actionRestoreFromJob);
667 mp_tableWidget->addAction(actionRestoreFromTime);
668 mp_tableWidget->addAction(actionShowLogForJob);
669 mp_tableWidget->addAction(actionShowInfoForJob);
671 if (m_selectedJobsCount >= 1) {
672 mp_tableWidget->addAction(actionDeleteJob);
673 mp_tableWidget->addAction(actionPurgeFiles);
676 /* Make Connections */
677 if (m_checkCurrentWidget) {
678 int row = mp_tableWidget->currentRow();
679 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
680 m_currentJob = jobitem->text(); /* get JobId */
681 jobitem = mp_tableWidget->item(row, m_clientIndex);
682 m_clientName = jobitem->text(); /* get Client Name */
683 jobitem = mp_tableWidget->item(row, m_nameIndex);
684 m_jobName = jobitem->text(); /* get Job Name */
685 jobitem = mp_tableWidget->item(row, m_levelIndex);
686 m_levelName = jobitem->text(); /* get level */
687 jobitem = mp_tableWidget->item(row, m_filesetIndex);
689 m_filesetName = jobitem->text(); /* get FileSet Name */
694 /* include purged action or not */
695 jobitem = mp_tableWidget->item(row, m_purgedIndex);
696 QString purged = jobitem->text();
697 /* mp_tableWidget->removeAction(actionPurgeFiles);
698 if (purged == tr("No") ) {
699 mp_tableWidget->addAction(actionPurgeFiles);
702 /* include restore from time and job action or not */
703 jobitem = mp_tableWidget->item(row, m_typeIndex);
704 QString type = jobitem->text();
705 if (m_selectedJobsCount == 1) {
706 mp_tableWidget->removeAction(actionRestoreFromJob);
707 mp_tableWidget->removeAction(actionRestoreFromTime);
708 if (type == tr("Backup")) {
709 mp_tableWidget->addAction(actionRestoreFromJob);
710 mp_tableWidget->addAction(actionRestoreFromTime);
714 /* include cancel action or not */
715 jobitem = mp_tableWidget->item(row, m_statusIndex);
716 QString status = jobitem->text();
717 mp_tableWidget->removeAction(actionCancelJob);
718 if (status == tr("Running") || status == tr("Created, not yet running")) {
719 mp_tableWidget->addAction(actionCancelJob);
725 * Function to prevent the splitter from making index 0 of the size larger than it
728 void JobList::splitterMoved(int /*pos*/, int /*index*/)
730 int frameMax = frame->maximumHeight();
731 QList<int> sizes = m_splitter->sizes();
733 foreach(int size, sizes) { sizeSum += size; }
734 if (sizes[0] > frameMax) {
736 sizes[1] = sizeSum - frameMax;
737 m_splitter->setSizes(sizes);