File indexing completed on 2023-09-24 06:01:14
0001 /*************************************************************************** 0002 * Copyright (C) 2009-2011 by Daniel Nicoletti * 0003 * dantti12@gmail.com * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; see the file COPYING. If not, write to * 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0018 * Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "SessionTask.h" 0022 #include "ui_SessionTask.h" 0023 0024 #include "IntroDialog.h" 0025 #include "InfoWidget.h" 0026 #include "ReviewChanges.h" 0027 #include "ApplicationLauncher.h" 0028 0029 #include <PkStrings.h> 0030 #include <PackageModel.h> 0031 #include <PkTransactionWidget.h> 0032 0033 #include <limits.h> 0034 #include <QtDBus/QDBusConnection> 0035 #include <QTimer> 0036 #include <QStringList> 0037 #include <QFile> 0038 #include <QSignalMapper> 0039 #include <QStringBuilder> 0040 #include <QDialogButtonBox> 0041 0042 //#include <KWindowSystem> 0043 #include <KLocalizedString> 0044 //#include <KGlobalSettings> 0045 #include <QPushButton> 0046 //#include <KGlobal> 0047 0048 #include <QLoggingCategory> 0049 0050 #include <Daemon> 0051 0052 Q_DECLARE_LOGGING_CATEGORY(APPER_SESSION) 0053 0054 using namespace PackageKit; 0055 0056 SessionTask::SessionTask(uint xid, const QString &interaction, const QDBusMessage &message, QWidget *parent) : 0057 QDialog(parent), 0058 m_xid(xid), 0059 m_message(message), 0060 ui(new Ui::SessionTask) 0061 { 0062 ui->setupUi(this); 0063 setAttribute(Qt::WA_DeleteOnClose); 0064 0065 m_model = new PackageModel(this); 0066 0067 // connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), 0068 // this, SLOT(updatePallete())); 0069 updatePallete(); 0070 0071 setWindowIcon(QIcon::fromTheme(QLatin1String("system-software-install"))); 0072 QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok); 0073 okButton->setText(i18n("Continue")); 0074 okButton->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); 0075 enableButtonOk(false); 0076 connect(okButton, &QPushButton::clicked, this, &SessionTask::slotContinueClicked); 0077 0078 QPushButton *cancelButton = ui->buttonBox->button(QDialogButtonBox::Cancel); 0079 connect(cancelButton, &QPushButton::clicked, this, &SessionTask::slotCancelClicked); 0080 0081 0082 0083 Daemon::global()->setHints(QLatin1String("locale=") + QLocale::system().name() + QLatin1String(".UTF-8")); 0084 0085 // Defaults to always 0086 m_interactions = ConfirmSearch 0087 | ConfirmDeps 0088 | ConfirmInstall 0089 | Progress 0090 | Finished 0091 | Warning; 0092 m_timeout = 0; 0093 parseInteraction(interaction); 0094 0095 QString cmdline; 0096 uint pid; 0097 // TODO as we are running on the session it might 0098 // be useless to check the PID on the system 0099 if ((pid = getPidSession()) != UINT_MAX) { 0100 cmdline = getCmdLine(pid); 0101 } else if ((pid = getPidSystem()) != UINT_MAX) { 0102 cmdline = getCmdLine(pid); 0103 } 0104 0105 if (!cmdline.isNull()) { 0106 setExec(cmdline); 0107 } 0108 0109 setMinimumSize(QSize(430,280)); 0110 // KConfig config("apper"); 0111 // KConfigGroup configGroup(&config, "SessionInstaller"); 0112 // restoreDialogSize(configGroup); 0113 } 0114 0115 SessionTask::~SessionTask() 0116 { 0117 // KConfig config("apper"); 0118 // KConfigGroup configGroup(&config, "SessionInstaller"); 0119 // saveDialogSize(configGroup); 0120 0121 delete ui; 0122 } 0123 0124 void SessionTask::addPackage(Transaction::Info info, const QString &packageID, const QString &summary) 0125 { 0126 m_model->addSelectedPackage(info, packageID, summary); 0127 } 0128 0129 void SessionTask::searchFinished(PkTransaction::ExitStatus status) 0130 { 0131 if (m_pkTransaction) { 0132 // Disconnect so it can be connected to commitFinished latter 0133 disconnect(m_pkTransaction->transaction(), &PkTransaction::finished, this, &SessionTask::searchFinished); 0134 } 0135 0136 if (status == PkTransaction::Success) { 0137 m_model->finished(); 0138 if (m_model->rowCount() == 0) { 0139 notFound(); 0140 showCloseButton(); 0141 } else { 0142 searchSuccess(); 0143 } 0144 } else if (status == PkTransaction::Cancelled) { 0145 cancelClicked(); 0146 } else { 0147 searchFailed(); 0148 showCloseButton(); 0149 } 0150 } 0151 0152 void SessionTask::commitFinished(PkTransaction::ExitStatus status) 0153 { 0154 if (m_pkTransaction) { 0155 // Disconnect so it can be connected to something else latter 0156 disconnect(m_pkTransaction->transaction(), &PkTransaction::finished, this, &SessionTask::searchFinished); 0157 } 0158 0159 if (status == PkTransaction::Success) { 0160 if (!m_removePackages.isEmpty()) { 0161 removePackages(); 0162 } else { 0163 commitSuccess(); 0164 showCloseButton(); 0165 } 0166 } else if (status == PkTransaction::Cancelled) { 0167 cancelClicked(); 0168 } else { 0169 commitFailed(); 0170 showCloseButton(); 0171 } 0172 } 0173 0174 void SessionTask::updatePallete() 0175 { 0176 QPalette pal; 0177 // pal.setColor(QPalette::Window, KGlobalSettings::activeTitleColor()); 0178 // pal.setColor(QPalette::WindowText, KGlobalSettings::activeTextColor()); 0179 ui->backgroundFrame->setPalette(pal); 0180 } 0181 0182 void SessionTask::setDialog(QDialog *dialog) 0183 { 0184 // Store the current values 0185 QWidget *widget = ui->stackedWidget->currentWidget(); 0186 0187 if (qobject_cast<ApplicationLauncher*>(dialog)) { 0188 // TODO if there is a removal after instalation 0189 // this will break it, but we don't have 0190 // this case yet... 0191 commitSuccess(dialog); 0192 } else { 0193 // Set the new ones 0194 setMainWidget(dialog); 0195 // setTitle(dialog->windowTitle()); // must come after 0196 connect(this, &SessionTask::continueClicked, dialog, &QDialog::accept); 0197 // connect(this, &SessionTask::continueClicked, dia, &QDialog::accept); 0198 // connect(this, SIGNAL(okClicked()), 0199 // dialog->mainWidget(), SLOT(deleteLater())); 0200 // connect(this, SIGNAL(okClicked()), 0201 // dialog, SLOT(deleteLater())); 0202 0203 // Make sure we see the last widget and title 0204 auto mapper = new QSignalMapper(this); 0205 mapper->setMapping(this, widget); 0206 connect(this, &SessionTask::continueClicked, mapper, QOverload<>::of(&QSignalMapper::map)); 0207 connect(mapper, QOverload<QWidget*>::of(&QSignalMapper::mapped), this, &SessionTask::setMainWidget); 0208 enableButtonOk(true); 0209 } 0210 } 0211 0212 void SessionTask::setMainWidget(QWidget *widget) 0213 { 0214 if (widget != mainWidget()) { 0215 ui->stackedWidget->addWidget(widget); 0216 ui->stackedWidget->setCurrentWidget(widget); 0217 setTitle(widget->windowTitle()); 0218 } 0219 } 0220 0221 QWidget* SessionTask::mainWidget() 0222 { 0223 return ui->stackedWidget->currentWidget(); 0224 } 0225 0226 void SessionTask::setInfo(const QString &title, const QString &text, const QString &details) 0227 { 0228 auto info = new InfoWidget(this); 0229 info->setWindowTitle(title); 0230 info->setDescription(text); 0231 info->setDetails(details); 0232 setMainWidget(info); 0233 showCloseButton(); 0234 0235 if (qobject_cast<PkTransaction*>(sender())) { 0236 // if we have a sender this method was caller by PkTransaction 0237 // be carefull because QSignalMapper from KDialog also calls this method 0238 sender()->disconnect(); 0239 sendErrorFinished(Failed, text); 0240 } 0241 } 0242 0243 void SessionTask::setError(const QString &title, const QString &text, const QString &details) 0244 { 0245 auto info = new InfoWidget(this); 0246 info->setWindowTitle(title); 0247 info->setDescription(text); 0248 info->setIcon(QIcon::fromTheme(QLatin1String("dialog-error"))); 0249 info->setDetails(details); 0250 setMainWidget(info); 0251 showCloseButton(); 0252 0253 if (qobject_cast<PkTransaction*>(sender())) { 0254 // if we have a sender this method was caller by PkTransaction 0255 // be carefull because QSignalMapper from KDialog also calls this method 0256 sender()->disconnect(); 0257 sendErrorFinished(Failed, text); 0258 } 0259 } 0260 0261 void SessionTask::setFinish(const QString &title, const QString &text, QWidget *widget) 0262 { 0263 auto info = new InfoWidget(this); 0264 info->setWindowTitle(title); 0265 info->setDescription(text); 0266 info->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-apply"))); 0267 info->addWidget(widget); 0268 setMainWidget(info); 0269 showCloseButton(); 0270 } 0271 0272 void SessionTask::setTitle(const QString &title) 0273 { 0274 ui->titleL->setText(title); 0275 } 0276 0277 void SessionTask::setExec(const QString &exec) 0278 { 0279 if (pathIsTrusted(exec)) { 0280 // Get from X11 the window title 0281 // KWindowInfo info = KWindowSystem::windowInfo(m_xid, NET::WMVisibleName); 0282 // parentTitle = info.visibleName(); 0283 } else { 0284 parentTitle = exec; 0285 } 0286 } 0287 0288 bool SessionTask::pathIsTrusted(const QString &exec) 0289 { 0290 // special case the plugin helper -- it's trusted 0291 return exec == QLatin1String("/usr/libexec/gst-install-plugins-helper") || 0292 exec == QLatin1String("/usr/libexec/pk-gstreamer-install") || 0293 exec == QLatin1String("/usr/bin/gstreamer-codec-install") || 0294 exec == QLatin1String("/usr/lib/packagekit/pk-gstreamer-install") || 0295 exec == QLatin1String("/usr/bin/plasma-desktop") || 0296 exec == QLatin1String("/usr/bin/apper"); 0297 } 0298 0299 QString SessionTask::getCmdLine(uint pid) 0300 { 0301 QFile file(QString(QLatin1String("/proc/%1/cmdline")).arg(pid)); 0302 QString line; 0303 if (file.open(QFile::ReadOnly)) { 0304 char buf[1024]; 0305 qint64 lineLength = file.readLine(buf, sizeof(buf)); 0306 if (lineLength != -1) { 0307 // the line is available in buf 0308 line = QString::fromLocal8Bit(buf); 0309 if (!line.contains(QLatin1String("(deleted)"))) { 0310 return line; 0311 } 0312 } 0313 } 0314 return QString(); 0315 } 0316 0317 uint SessionTask::getPidSystem() 0318 { 0319 QDBusMessage msg; 0320 msg = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.DBus"), 0321 QLatin1String("/org/freedesktop/DBus/Bus"), 0322 QLatin1String("org.freedesktop.DBus"), 0323 QLatin1String("GetConnectionUnixProcessID")); 0324 msg << m_message.service(); 0325 QDBusMessage reply = QDBusConnection::systemBus().call(msg); 0326 if (reply.type() != QDBusMessage::ReplyMessage) { 0327 qCWarning(APPER_SESSION) << "Message did not receive a reply"; 0328 } 0329 0330 if (reply.arguments().size() == 1) { 0331 return reply.arguments().at(0).toUInt(); 0332 } 0333 0334 return UINT_MAX; 0335 } 0336 0337 uint SessionTask::getPidSession() 0338 { 0339 QDBusMessage msg; 0340 msg = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.DBus"), 0341 QLatin1String("/org/freedesktop/DBus/Bus"), 0342 QLatin1String("org.freedesktop.DBus"), 0343 QLatin1String("GetConnectionUnixProcessID")); 0344 msg << m_message.service(); 0345 QDBusMessage reply = QDBusConnection::sessionBus().call(msg); 0346 if (reply.type() != QDBusMessage::ReplyMessage) { 0347 qCWarning(APPER_SESSION) << "Message did not receive a reply"; 0348 } 0349 0350 if (reply.arguments().size() == 1) { 0351 return reply.arguments().at(0).toUInt(); 0352 } 0353 0354 return UINT_MAX; 0355 } 0356 0357 void SessionTask::search() 0358 { 0359 qCDebug(APPER_SESSION) << "virtual method called, falling back to commit()"; 0360 commit(); 0361 } 0362 0363 void SessionTask::commit() 0364 { 0365 qCDebug(APPER_SESSION) << "virtual method called"; 0366 if (m_reviewChanges) { 0367 QStringList installPackages = m_reviewChanges->model()->selectedPackagesToInstall(); 0368 m_removePackages = m_reviewChanges->model()->selectedPackagesToRemove(); 0369 0370 if (installPackages.isEmpty() && m_removePackages.isEmpty()) { 0371 setInfo(i18n("There are no packages to Install or Remove"), 0372 i18n("This action should not happen")); 0373 sendErrorFinished(Failed, QLatin1String("to install or remove due to empty lists")); 0374 } else if (!installPackages.isEmpty()) { 0375 // Install Packages 0376 auto transaction = new PkTransaction(this); 0377 setTransaction(Transaction::RoleInstallPackages, transaction); 0378 connect(transaction, &PkTransaction::finished, this, &SessionTask::commitFinished, Qt::UniqueConnection); 0379 transaction->installPackages(installPackages); 0380 } else { 0381 // Remove them 0382 removePackages(); 0383 } 0384 } 0385 } 0386 0387 void SessionTask::removePackages() 0388 { 0389 // Remove Packages 0390 auto transaction = new PkTransaction(this); 0391 setTransaction(Transaction::RoleRemovePackages, transaction); 0392 connect(transaction, &PkTransaction::finished, this, &SessionTask::commitFinished, Qt::UniqueConnection); 0393 transaction->removePackages(m_removePackages); 0394 m_removePackages.clear(); 0395 } 0396 0397 void SessionTask::notFound() 0398 { 0399 qCDebug(APPER_SESSION) << "virtual method called"; 0400 if (showWarning()) { 0401 setInfo(i18n("Could not find"), 0402 i18n("No packages were found that meet the request")); 0403 } 0404 sendErrorFinished(NoPackagesFound, QLatin1String("no package found")); 0405 } 0406 0407 void SessionTask::searchFailed() 0408 { 0409 qCDebug(APPER_SESSION) << "virtual method called"; 0410 setInfo(i18n("Failed to find"), 0411 i18n("No packages were found that meet the request")); 0412 sendErrorFinished(Failed, QLatin1String("failed to search")); 0413 } 0414 0415 void SessionTask::searchSuccess() 0416 { 0417 qCDebug(APPER_SESSION) << "virtual method called"; 0418 enableButtonOk(true); 0419 m_reviewChanges = new ReviewChanges(m_model, this); 0420 connect(m_reviewChanges, &ReviewChanges::hasSelectedPackages, this, &SessionTask::enableButtonOk); 0421 setMainWidget(m_reviewChanges); 0422 } 0423 0424 void SessionTask::commitFailed() 0425 { 0426 qCDebug(APPER_SESSION) << "virtual method called"; 0427 // This should not be used to display stuff as the transaction should 0428 // emit error() or info() 0429 // setInfo(i18n("Failed to commit transaction"), 0430 // PkStrings::errsearchFailedorMessage(m_pkTransaction->error())); 0431 sendErrorFinished(Failed, i18n("Transaction did not finish with success")); 0432 } 0433 0434 void SessionTask::commitSuccess(QWidget *widget) 0435 { 0436 qCDebug(APPER_SESSION) << "virtual method called"; 0437 setFinish(i18n("Task completed"), i18n("All operations were committed successfully"), widget); 0438 finishTaskOk(); 0439 } 0440 0441 void SessionTask::showCloseButton() 0442 { 0443 ui->buttonBox->setStandardButtons(QDialogButtonBox::Close); 0444 QPushButton *closeBt = ui->buttonBox->button(QDialogButtonBox::Close); 0445 closeBt->setDefault(true); 0446 connect(closeBt, &QPushButton::clicked, this, &SessionTask::accept); 0447 } 0448 0449 void SessionTask::sendErrorFinished(DBusError error, const QString &msg) 0450 { 0451 QString dbusError; 0452 switch (error) { 0453 case Failed: 0454 dbusError = QLatin1String("org.freedesktop.PackageKit.Failed"); 0455 break; 0456 case InternalError: 0457 dbusError = QLatin1String("org.freedesktop.PackageKit.InternalError"); 0458 break; 0459 case NoPackagesFound: 0460 dbusError = QLatin1String("org.freedesktop.PackageKit.NoPackagesFound"); 0461 break; 0462 case Forbidden: 0463 dbusError = QLatin1String("org.freedesktop.PackageKit.Forbidden"); 0464 break; 0465 case Cancelled: 0466 dbusError = QLatin1String("org.freedesktop.PackageKit.Cancelled"); 0467 break; 0468 } 0469 QDBusMessage reply = m_message.createErrorReply(dbusError, msg); 0470 QDBusConnection::sessionBus().send(reply); 0471 } 0472 0473 bool SessionTask::sendMessageFinished(const QDBusMessage &message) 0474 { 0475 // emit finished(); 0476 return QDBusConnection::sessionBus().send(message); 0477 } 0478 0479 uint SessionTask::parentWId() const 0480 { 0481 return m_xid; 0482 } 0483 0484 void SessionTask::slotContinueClicked() 0485 { 0486 if (qobject_cast<IntroDialog*>(mainWidget())) { 0487 enableButtonOk(false); 0488 search(); 0489 } else if (qobject_cast<ReviewChanges*>(mainWidget())) { 0490 enableButtonOk(false); 0491 commit(); 0492 } else { 0493 // emit okClicked(); 0494 } 0495 } 0496 0497 void SessionTask::slotCancelClicked() 0498 { 0499 emit cancelClicked(); 0500 sendErrorFinished(Cancelled, QLatin1String("Aborted by the user")); 0501 reject(); 0502 0503 } 0504 0505 void SessionTask::enableButtonOk(bool enable) 0506 { 0507 QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok); 0508 okButton->setEnabled(enable); 0509 if (enable) { 0510 // When enabling the Continue button put focus on it 0511 okButton->setFocus(); 0512 } 0513 } 0514 0515 void SessionTask::parseInteraction(const QString &interaction) 0516 { 0517 QStringList interactions = interaction.split(QLatin1Char(',')); 0518 0519 // Enable or disable all options 0520 if (interactions.contains(QLatin1String("always"))) { 0521 m_interactions = ConfirmSearch 0522 | ConfirmDeps 0523 | ConfirmInstall 0524 | Progress 0525 | Finished 0526 | Warning; 0527 } else if (interactions.contains(QLatin1String("never"))) { 0528 m_interactions = {}; 0529 } 0530 0531 // show custom options 0532 if (interactions.contains(QLatin1String("show-confirm-search"))) { 0533 m_interactions |= ConfirmSearch; 0534 } 0535 if (interactions.contains(QLatin1String("show-confirm-deps"))) { 0536 m_interactions |= ConfirmDeps; 0537 } 0538 if (interactions.contains(QLatin1String("show-confirm-install"))) { 0539 m_interactions |= ConfirmInstall; 0540 } 0541 if (interactions.contains(QLatin1String("show-progress"))) { 0542 m_interactions |= Progress; 0543 } 0544 if (interactions.contains(QLatin1String("show-finished"))) { 0545 m_interactions |= Finished; 0546 } 0547 if (interactions.contains(QLatin1String("show-warning"))) { 0548 m_interactions |= Warning; 0549 } 0550 0551 // hide custom options 0552 if (interactions.contains(QLatin1String("hide-confirm-search"))) { 0553 m_interactions &= ~ConfirmSearch; 0554 } 0555 if (interactions.contains(QLatin1String("hide-confirm-deps"))) { 0556 m_interactions &= ~ConfirmDeps; 0557 } 0558 if (interactions.contains(QLatin1String("hide-confirm-install"))) { 0559 m_interactions &= ~ConfirmInstall; 0560 } 0561 if (interactions.contains(QLatin1String("hide-progress"))) { 0562 m_interactions &= ~Progress; 0563 } 0564 if (interactions.contains(QLatin1String("hide-finished"))) { 0565 m_interactions &= ~Finished; 0566 } 0567 if (interactions.contains(QLatin1String("hide-warning"))) { 0568 m_interactions &= ~Warning; 0569 } 0570 0571 int index; 0572 QRegExp rx(QLatin1String("^timeout=(\\d+)$")); 0573 index = interactions.indexOf(rx); 0574 if (index != -1) { 0575 if (rx.indexIn(interactions.at(index)) != -1) { 0576 m_timeout = rx.cap(1).toUInt(); 0577 } 0578 } 0579 } 0580 0581 bool SessionTask::foundPackages() const 0582 { 0583 return m_model->rowCount(); 0584 } 0585 0586 int SessionTask::foundPackagesSize() const 0587 { 0588 return m_model->rowCount(); 0589 } 0590 0591 PackageModel *SessionTask::model() const 0592 { 0593 return m_model; 0594 } 0595 0596 void SessionTask::setTransaction(Transaction::Role role, PkTransaction *t) 0597 { 0598 if (m_pkTransaction == nullptr) { 0599 m_pkTransaction = new PkTransactionWidget(this); 0600 m_pkTransaction->hideCancelButton(); 0601 0602 ui->stackedWidget->addWidget(m_pkTransaction); 0603 connect(m_pkTransaction, &PkTransactionWidget::titleChanged, this, &SessionTask::setTitle); 0604 connect(this, &SessionTask::cancelClicked, m_pkTransaction, &PkTransactionWidget::cancel); 0605 connect(m_pkTransaction, &PkTransactionWidget::dialog, this, &SessionTask::setDialog); 0606 connect(m_pkTransaction, &PkTransactionWidget::sorry, this, &SessionTask::setInfo); 0607 connect(m_pkTransaction, &PkTransactionWidget::error, this, &SessionTask::setError); 0608 } 0609 if (t) { 0610 m_pkTransaction->setTransaction(t, role); 0611 // setTitle(m_pkTransaction->title()); 0612 } 0613 0614 // avoid changing the current widget 0615 if (mainWidget() != m_pkTransaction) { 0616 ui->stackedWidget->setCurrentWidget(m_pkTransaction); 0617 } 0618 } 0619 0620 void SessionTask::finishTaskOk() 0621 { 0622 sendMessageFinished(m_message.createReply()); 0623 } 0624 0625 SessionTask::Interactions SessionTask::interactions() const 0626 { 0627 return m_interactions; 0628 } 0629 0630 uint SessionTask::timeout() const 0631 { 0632 return m_timeout; 0633 } 0634 0635 bool SessionTask::showConfirmSearch() const 0636 { 0637 return m_interactions & ConfirmSearch; 0638 } 0639 0640 bool SessionTask::showConfirmDeps() const 0641 { 0642 return m_interactions & ConfirmDeps; 0643 } 0644 0645 bool SessionTask::showConfirmInstall() const 0646 { 0647 return m_interactions & ConfirmInstall; 0648 } 0649 0650 bool SessionTask::showProgress() const 0651 { 0652 return m_interactions & Progress; 0653 } 0654 0655 bool SessionTask::showFinished() const 0656 { 0657 return m_interactions & Finished; 0658 } 0659 0660 bool SessionTask::showWarning() const 0661 { 0662 return m_interactions & Warning; 0663 } 0664 0665 #include "moc_SessionTask.cpp"