File indexing completed on 2024-04-14 14:18:23
0001 /* 0002 SPDX-FileCopyrightText: 2000 Matthias Elter <elter@kde.org> 0003 SPDX-FileCopyrightText: 2003 Daniel Molkentin <molkentin@kde.org> 0004 SPDX-FileCopyrightText: 2003, 2006 Matthias Kretz <kretz@kde.org> 0005 SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com> 0006 SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org> 0007 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de> 0008 0009 SPDX-License-Identifier: LGPL-2.0-or-later 0010 */ 0011 0012 #include "kcmultidialog.h" 0013 #include "kcmultidialog_p.h" 0014 0015 #include "kcmoduleproxy.h" 0016 #include "kcmoduleqml_p.h" 0017 #include <kcmutils_debug.h> 0018 0019 #include <QApplication> 0020 #include <QDesktopServices> 0021 #include <QJsonArray> 0022 #include <QLayout> 0023 #include <QProcess> 0024 #include <QPushButton> 0025 #include <QScreen> 0026 #include <QStandardPaths> 0027 #include <QStringList> 0028 #include <QStyle> 0029 #include <QUrl> 0030 0031 #if KCONFIGWIDGETS_WITH_KAUTH 0032 #include <KAuth/Action> 0033 #include <KAuth/ObjectDecorator> 0034 #endif 0035 #include <KGuiItem> 0036 #include <KIconUtils> 0037 #include <KLocalizedString> 0038 #include <KMessageBox> 0039 #include <KPageWidgetModel> 0040 0041 bool KCMultiDialogPrivate::resolveChanges(KCModuleProxy *currentProxy) 0042 { 0043 Q_Q(KCMultiDialog); 0044 if (!currentProxy || !currentProxy->isChanged()) { 0045 return true; 0046 } 0047 0048 // Let the user decide 0049 const int queryUser = KMessageBox::warningTwoActionsCancel(q, 0050 i18n("The settings of the current module have changed.\n" 0051 "Do you want to apply the changes or discard them?"), 0052 i18n("Apply Settings"), 0053 KStandardGuiItem::apply(), 0054 KStandardGuiItem::discard(), 0055 KStandardGuiItem::cancel()); 0056 0057 switch (queryUser) { 0058 case KMessageBox::PrimaryAction: 0059 return moduleSave(currentProxy); 0060 0061 case KMessageBox::SecondaryAction: 0062 currentProxy->load(); 0063 return true; 0064 0065 case KMessageBox::Cancel: 0066 return false; 0067 0068 default: 0069 Q_ASSERT(false); 0070 return false; 0071 } 0072 } 0073 0074 void KCMultiDialogPrivate::_k_slotCurrentPageChanged(KPageWidgetItem *current, KPageWidgetItem *previous) 0075 { 0076 Q_Q(KCMultiDialog); 0077 0078 KCModuleProxy *previousModule = nullptr; 0079 for (int i = 0; i < modules.count(); ++i) { 0080 if (modules[i].item == previous) { 0081 previousModule = modules[i].kcm; 0082 } 0083 } 0084 0085 // Delete global margins and spacing, since we want the contents to 0086 // be able to touch the edges of the window 0087 q->layout()->setContentsMargins(0, 0, 0, 0); 0088 0089 const KPageWidget *pageWidget = q->pageWidget(); 0090 pageWidget->layout()->setSpacing(0); 0091 0092 // Then, we set the margins for the title header and the buttonBox footer 0093 const QStyle *style = q->style(); 0094 const QMargins layoutMargins = QMargins(style->pixelMetric(QStyle::PM_LayoutLeftMargin), 0095 style->pixelMetric(QStyle::PM_LayoutTopMargin), 0096 style->pixelMetric(QStyle::PM_LayoutRightMargin), 0097 style->pixelMetric(QStyle::PM_LayoutBottomMargin)); 0098 0099 if (pageWidget->pageHeader()) { 0100 pageWidget->pageHeader()->setContentsMargins(layoutMargins); 0101 } 0102 0103 // Do not set buttonBox's top margin as that space will be covered by the content's bottom margin 0104 q->buttonBox()->setContentsMargins(layoutMargins.left(), 0, layoutMargins.right(), layoutMargins.bottom()); 0105 0106 q->blockSignals(true); 0107 q->setCurrentPage(previous); 0108 0109 if (resolveChanges(previousModule)) { 0110 q->setCurrentPage(current); 0111 } 0112 q->blockSignals(false); 0113 0114 // We need to get the state of the now active module 0115 _k_clientChanged(); 0116 } 0117 0118 void KCMultiDialogPrivate::_k_clientChanged() 0119 { 0120 Q_Q(KCMultiDialog); 0121 // qDebug(); 0122 // Get the current module 0123 KCModuleProxy *activeModule = nullptr; 0124 for (int i = 0; i < modules.count(); ++i) { 0125 if (modules[i].item == q->currentPage()) { 0126 activeModule = modules[i].kcm; 0127 break; 0128 } 0129 } 0130 0131 bool change = false; 0132 bool defaulted = false; 0133 if (activeModule) { 0134 change = activeModule->isChanged(); 0135 defaulted = activeModule->defaulted(); 0136 0137 QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply); 0138 if (applyButton) { 0139 q->disconnect(applyButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); 0140 #if KCONFIGWIDGETS_WITH_KAUTH 0141 delete applyButton->findChild<KAuth::ObjectDecorator *>(); 0142 #endif 0143 } 0144 0145 QPushButton *okButton = q->buttonBox()->button(QDialogButtonBox::Ok); 0146 if (okButton) { 0147 q->disconnect(okButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); 0148 #if KCONFIGWIDGETS_WITH_KAUTH 0149 delete okButton->findChild<KAuth::ObjectDecorator *>(); 0150 #endif 0151 } 0152 0153 #if KCONFIGWIDGETS_WITH_KAUTH 0154 if (activeModule->realModule()->needsAuthorization()) { 0155 if (applyButton) { 0156 KAuth::ObjectDecorator *decorator = new KAuth::ObjectDecorator(applyButton); 0157 decorator->setAuthAction(activeModule->realModule()->authAction()); 0158 activeModule->realModule()->authAction().setParentWidget(activeModule->realModule()); 0159 q->connect(decorator, &KAuth::ObjectDecorator::authorized, q, &KCMultiDialog::slotApplyClicked); 0160 } 0161 0162 if (okButton) { 0163 KAuth::ObjectDecorator *decorator = new KAuth::ObjectDecorator(okButton); 0164 decorator->setAuthAction(activeModule->realModule()->authAction()); 0165 activeModule->realModule()->authAction().setParentWidget(activeModule->realModule()); 0166 q->connect(decorator, &KAuth::ObjectDecorator::authorized, q, &KCMultiDialog::slotOkClicked); 0167 } 0168 } else { 0169 if (applyButton) { 0170 q->connect(applyButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); 0171 delete applyButton->findChild<KAuth::ObjectDecorator *>(); 0172 } 0173 0174 if (okButton) { 0175 q->connect(okButton, &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); 0176 delete okButton->findChild<KAuth::ObjectDecorator *>(); 0177 } 0178 } 0179 #endif 0180 } 0181 0182 auto buttons = activeModule ? activeModule->buttons() : KCModule::NoAdditionalButton; 0183 0184 QPushButton *resetButton = q->buttonBox()->button(QDialogButtonBox::Reset); 0185 if (resetButton) { 0186 resetButton->setVisible(buttons & KCModule::Apply); 0187 resetButton->setEnabled(change); 0188 } 0189 0190 QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply); 0191 if (applyButton) { 0192 applyButton->setVisible(buttons & KCModule::Apply); 0193 applyButton->setEnabled(change); 0194 } 0195 0196 QPushButton *cancelButton = q->buttonBox()->button(QDialogButtonBox::Cancel); 0197 if (cancelButton) { 0198 cancelButton->setVisible(buttons & KCModule::Apply); 0199 } 0200 0201 QPushButton *okButton = q->buttonBox()->button(QDialogButtonBox::Ok); 0202 if (okButton) { 0203 okButton->setVisible(buttons & KCModule::Apply); 0204 } 0205 0206 QPushButton *closeButton = q->buttonBox()->button(QDialogButtonBox::Close); 0207 if (closeButton) { 0208 closeButton->setHidden(buttons & KCModule::Apply); 0209 } 0210 0211 QPushButton *helpButton = q->buttonBox()->button(QDialogButtonBox::Help); 0212 if (helpButton) { 0213 helpButton->setVisible(buttons & KCModule::Help); 0214 } 0215 0216 QPushButton *defaultButton = q->buttonBox()->button(QDialogButtonBox::RestoreDefaults); 0217 if (defaultButton) { 0218 defaultButton->setVisible(buttons & KCModule::Default); 0219 defaultButton->setEnabled(!defaulted); 0220 } 0221 } 0222 0223 void KCMultiDialogPrivate::_k_updateHeader(bool use, const QString &message) 0224 { 0225 Q_Q(KCMultiDialog); 0226 KPageWidgetItem *item = q->currentPage(); 0227 KCModuleProxy *kcm = qobject_cast<KCModuleProxy *>(item->widget()); 0228 0229 QString moduleName; 0230 QString icon; 0231 0232 if (kcm->metaData().isValid()) { 0233 moduleName = kcm->metaData().name(); 0234 icon = kcm->metaData().iconName(); 0235 } 0236 0237 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 88) 0238 if (kcm->moduleInfo().isValid()) { 0239 moduleName = kcm->moduleInfo().moduleName(); 0240 icon = kcm->moduleInfo().icon(); 0241 } 0242 #endif 0243 0244 if (use) { 0245 item->setHeader(QStringLiteral("<b>") + moduleName + QStringLiteral("</b><br><i>") + message + QStringLiteral("</i>")); 0246 item->setIcon(KIconUtils::addOverlay(QIcon::fromTheme(icon), QIcon::fromTheme(QStringLiteral("dialog-warning")), Qt::BottomRightCorner)); 0247 } else { 0248 item->setHeader(moduleName); 0249 item->setIcon(QIcon::fromTheme(icon)); 0250 } 0251 } 0252 0253 void KCMultiDialogPrivate::init() 0254 { 0255 Q_Q(KCMultiDialog); 0256 q->setFaceType(KPageDialog::Auto); 0257 q->setWindowTitle(i18n("Configure")); 0258 q->setModal(false); 0259 0260 QDialogButtonBox *buttonBox = new QDialogButtonBox(q); 0261 buttonBox->setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel | QDialogButtonBox::Apply 0262 | QDialogButtonBox::Close | QDialogButtonBox::Ok | QDialogButtonBox::Reset); 0263 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); 0264 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); 0265 KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); 0266 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::apply()); 0267 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Close), KStandardGuiItem::close()); 0268 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Reset), KStandardGuiItem::reset()); 0269 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Help), KStandardGuiItem::help()); 0270 buttonBox->button(QDialogButtonBox::Close)->setVisible(false); 0271 buttonBox->button(QDialogButtonBox::Reset)->setEnabled(false); 0272 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); 0273 0274 q->connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, &KCMultiDialog::slotApplyClicked); 0275 q->connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, q, &KCMultiDialog::slotOkClicked); 0276 q->connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, &KCMultiDialog::slotDefaultClicked); 0277 q->connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &KCMultiDialog::slotHelpClicked); 0278 q->connect(buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, q, &KCMultiDialog::slotUser1Clicked); 0279 0280 q->setButtonBox(buttonBox); 0281 q->connect(q, &KPageDialog::currentPageChanged, q, [this](KPageWidgetItem *current, KPageWidgetItem *before) { 0282 _k_slotCurrentPageChanged(current, before); 0283 }); 0284 } 0285 0286 KCMultiDialog::KCMultiDialog(QWidget *parent) 0287 : KPageDialog(parent) 0288 , d_ptr(new KCMultiDialogPrivate(this)) 0289 { 0290 d_func()->init(); 0291 } 0292 0293 KCMultiDialog::KCMultiDialog(KPageWidget *pageWidget, QWidget *parent, Qt::WindowFlags flags) 0294 : KPageDialog(pageWidget, parent, flags) 0295 , d_ptr(new KCMultiDialogPrivate(this)) 0296 { 0297 d_func()->init(); 0298 } 0299 0300 KCMultiDialog::KCMultiDialog(KCMultiDialogPrivate &dd, KPageWidget *pageWidget, QWidget *parent, Qt::WindowFlags flags) 0301 : KPageDialog(pageWidget, parent, flags) 0302 , d_ptr(&dd) 0303 { 0304 d_func()->init(); 0305 } 0306 0307 KCMultiDialog::~KCMultiDialog() 0308 { 0309 delete d_ptr; 0310 } 0311 0312 void KCMultiDialog::showEvent(QShowEvent *ev) 0313 { 0314 KPageDialog::showEvent(ev); 0315 adjustSize(); 0316 /** 0317 * adjustSize() relies on sizeHint but is limited to 2/3 of the desktop size 0318 * Workaround for https://bugreports.qt.io/browse/QTBUG-3459 0319 * 0320 * We adjust the size after passing the show event 0321 * because otherwise window pos is set to (0,0) 0322 */ 0323 0324 const QSize maxSize = screen()->availableGeometry().size(); 0325 resize(qMin(sizeHint().width(), maxSize.width()), qMin(sizeHint().height(), maxSize.height())); 0326 } 0327 0328 void KCMultiDialog::slotDefaultClicked() 0329 { 0330 Q_D(KCMultiDialog); 0331 const KPageWidgetItem *item = currentPage(); 0332 if (!item) { 0333 return; 0334 } 0335 0336 for (int i = 0; i < d->modules.count(); ++i) { 0337 if (d->modules[i].item == item) { 0338 d->modules[i].kcm->defaults(); 0339 d->_k_clientChanged(); 0340 return; 0341 } 0342 } 0343 } 0344 0345 void KCMultiDialog::slotUser1Clicked() 0346 { 0347 const KPageWidgetItem *item = currentPage(); 0348 if (!item) { 0349 return; 0350 } 0351 0352 Q_D(KCMultiDialog); 0353 for (int i = 0; i < d->modules.count(); ++i) { 0354 if (d->modules[i].item == item) { 0355 d->modules[i].kcm->load(); 0356 d->_k_clientChanged(); 0357 return; 0358 } 0359 } 0360 } 0361 0362 bool KCMultiDialogPrivate::moduleSave(KCModuleProxy *module) 0363 { 0364 if (!module) { 0365 return false; 0366 } 0367 0368 module->save(); 0369 return true; 0370 } 0371 0372 void KCMultiDialogPrivate::apply() 0373 { 0374 Q_Q(KCMultiDialog); 0375 QStringList updatedComponents; 0376 0377 for (const CreatedModule &module : std::as_const(modules)) { 0378 KCModuleProxy *proxy = module.kcm; 0379 0380 if (proxy->isChanged()) { 0381 proxy->save(); 0382 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 85) 0383 /** 0384 * Add name of the components the kcm belongs to the list 0385 * of updated components. 0386 */ 0387 const QStringList componentNames = module.componentNames; 0388 for (const QString &componentName : componentNames) { 0389 if (!updatedComponents.contains(componentName)) { 0390 updatedComponents.append(componentName); 0391 } 0392 } 0393 #endif 0394 } 0395 } 0396 0397 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 85) 0398 // Send the configCommitted signal for every updated component. 0399 for (const QString &name : std::as_const(updatedComponents)) { 0400 Q_EMIT q->configCommitted(name.toLatin1()); 0401 } 0402 #endif 0403 0404 Q_EMIT q->configCommitted(); 0405 } 0406 0407 void KCMultiDialog::slotApplyClicked() 0408 { 0409 QPushButton *applyButton = buttonBox()->button(QDialogButtonBox::Apply); 0410 applyButton->setFocus(); 0411 0412 d_func()->apply(); 0413 } 0414 0415 void KCMultiDialog::slotOkClicked() 0416 { 0417 QPushButton *okButton = buttonBox()->button(QDialogButtonBox::Ok); 0418 okButton->setFocus(); 0419 0420 d_func()->apply(); 0421 accept(); 0422 } 0423 0424 void KCMultiDialog::slotHelpClicked() 0425 { 0426 const KPageWidgetItem *item = currentPage(); 0427 if (!item) { 0428 return; 0429 } 0430 0431 Q_D(KCMultiDialog); 0432 QString docPath; 0433 for (int i = 0; i < d->modules.count(); ++i) { 0434 if (d->modules[i].item == item) { 0435 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 88) 0436 docPath = d->modules[i].kcm->moduleInfo().docPath(); 0437 #endif 0438 if (docPath.isEmpty()) { 0439 docPath = d->modules[i].kcm->metaData().value(QStringLiteral("X-DocPath")); 0440 } 0441 break; 0442 } 0443 } 0444 0445 const QUrl docUrl = QUrl(QStringLiteral("help:/")).resolved(QUrl(docPath)); // same code as in KHelpClient::invokeHelp 0446 const QString docUrlScheme = docUrl.scheme(); 0447 const QString helpExec = QStandardPaths::findExecutable(QStringLiteral("khelpcenter")); 0448 const bool foundExec = !helpExec.isEmpty(); 0449 if (!foundExec) { 0450 qCDebug(KCMUTILS_LOG) << "Couldn't find khelpcenter executable in PATH."; 0451 } 0452 if (foundExec && (docUrlScheme == QLatin1String("man") || docUrlScheme == QLatin1String("info"))) { 0453 QProcess::startDetached(helpExec, QStringList() << docUrl.toString()); 0454 } else { 0455 QDesktopServices::openUrl(docUrl); 0456 } 0457 } 0458 0459 void KCMultiDialog::closeEvent(QCloseEvent *event) 0460 { 0461 Q_D(KCMultiDialog); 0462 KPageDialog::closeEvent(event); 0463 0464 /** 0465 * If we don't delete them, the DBUS registration stays, and trying to load the KCMs 0466 * in other situations will lead to "module already loaded in Foo," while to the user 0467 * doesn't appear so(the dialog is hidden) 0468 */ 0469 for (auto &proxy : std::as_const(d->modules)) { 0470 proxy.kcm->deleteClient(); 0471 } 0472 } 0473 0474 KPageWidgetItem *KCMultiDialog::addModule(const KPluginMetaData &metaData) 0475 { 0476 return addModule(metaData, QStringList()); 0477 } 0478 0479 KPageWidgetItem *KCMultiDialog::addModule(const KPluginMetaData &metaData, const QStringList &args) 0480 { 0481 Q_D(KCMultiDialog); 0482 // Create the scroller 0483 auto *moduleScroll = new UnboundScrollArea(this); 0484 // Prepare the scroll area 0485 moduleScroll->setWidgetResizable(true); 0486 moduleScroll->setFrameStyle(QFrame::NoFrame); 0487 moduleScroll->viewport()->setAutoFillBackground(false); 0488 0489 KCModuleProxy *kcm = new KCModuleProxy(metaData, moduleScroll, args); 0490 moduleScroll->setWidget(kcm); 0491 0492 KPageWidgetItem *item = new KPageWidgetItem(moduleScroll, metaData.name()); 0493 0494 KCMultiDialogPrivate::CreatedModule createdModule; 0495 createdModule.kcm = kcm; 0496 createdModule.item = item; 0497 d->modules.append(createdModule); 0498 0499 if (qobject_cast<KCModuleQml *>(kcm->realModule())) { 0500 item->setHeaderVisible(false); 0501 } 0502 0503 if (kcm->realModule() && kcm->realModule()->useRootOnlyMessage()) { 0504 item->setHeader(QStringLiteral("<b>%1</b><br><i>%2</i>").arg(metaData.name(), kcm->realModule()->rootOnlyMessage())); 0505 item->setIcon(KIconUtils::addOverlay(QIcon::fromTheme(metaData.iconName()), QIcon::fromTheme(QStringLiteral("dialog-warning")), Qt::BottomRightCorner)); 0506 } else { 0507 item->setHeader(metaData.name()); 0508 item->setIcon(QIcon::fromTheme(metaData.iconName())); 0509 } 0510 const int weight = metaData.rawData().value(QStringLiteral("X-KDE-Weight")).toInt(); 0511 item->setProperty("_k_weight", weight); 0512 0513 bool updateCurrentPage = false; 0514 const KPageWidgetModel *model = qobject_cast<const KPageWidgetModel *>(pageWidget()->model()); 0515 Q_ASSERT(model); 0516 const int siblingCount = model->rowCount(); 0517 int row = 0; 0518 for (; row < siblingCount; ++row) { 0519 KPageWidgetItem *siblingItem = model->item(model->index(row, 0)); 0520 if (siblingItem->property("_k_weight").toInt() > weight) { 0521 // the item we found is heavier than the new module 0522 // qDebug() << "adding KCM " << item->name() << " before " << siblingItem->name(); 0523 insertPage(siblingItem, item); 0524 if (siblingItem == currentPage()) { 0525 updateCurrentPage = true; 0526 } 0527 0528 break; 0529 } 0530 } 0531 if (row == siblingCount) { 0532 // the new module is either the first or the heaviest item 0533 // qDebug() << "adding KCM " << item->name() << " at the top level"; 0534 addPage(item); 0535 } 0536 0537 QObject::connect(kcm, qOverload<bool>(&KCModuleProxy::changed), this, [d]() { 0538 d->_k_clientChanged(); 0539 }); 0540 0541 QObject::connect(kcm->realModule(), &KCModule::rootOnlyMessageChanged, this, [d](bool use, const QString &message) { 0542 d->_k_updateHeader(use, message); 0543 }); 0544 0545 if (d->modules.count() == 1 || updateCurrentPage) { 0546 setCurrentPage(item); 0547 d->_k_clientChanged(); 0548 } 0549 return item; 0550 } 0551 0552 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 85) 0553 KPageWidgetItem *KCMultiDialog::addModule(const QString &path, const QStringList &args) 0554 { 0555 QString complete = path; 0556 0557 if (!path.endsWith(QLatin1String(".desktop"))) { 0558 complete += QStringLiteral(".desktop"); 0559 } 0560 0561 KService::Ptr service = KService::serviceByStorageId(complete); 0562 0563 return addModule(KCModuleInfo(service), nullptr, args); 0564 } 0565 #endif 0566 0567 #if KCMUTILS_BUILD_DEPRECATED_SINCE(5, 85) 0568 KPageWidgetItem *KCMultiDialog::addModule(const KCModuleInfo &moduleInfo, KPageWidgetItem *parentItem, const QStringList &args) 0569 { 0570 Q_D(KCMultiDialog); 0571 if (!moduleInfo.isValid()) { 0572 return nullptr; 0573 } 0574 0575 // KAuthorized::authorizeControlModule( moduleInfo.service()->menuId() ) is 0576 // checked in noDisplay already 0577 if (moduleInfo.service() && moduleInfo.service()->noDisplay()) { 0578 return nullptr; 0579 } 0580 0581 // Create the scroller 0582 auto *moduleScroll = new UnboundScrollArea(this); 0583 // Prepare the scroll area 0584 moduleScroll->setWidgetResizable(true); 0585 moduleScroll->setFrameStyle(QFrame::NoFrame); 0586 moduleScroll->viewport()->setAutoFillBackground(false); 0587 0588 KCModuleProxy *kcm = new KCModuleProxy(moduleInfo, moduleScroll, args); 0589 moduleScroll->setWidget(kcm); 0590 0591 // qDebug() << moduleInfo.moduleName(); 0592 KPageWidgetItem *item = new KPageWidgetItem(moduleScroll, moduleInfo.moduleName()); 0593 0594 KCMultiDialogPrivate::CreatedModule cm; 0595 cm.kcm = kcm; 0596 cm.item = item; 0597 cm.componentNames = moduleInfo.property(QStringLiteral("X-KDE-ParentComponents")).toStringList(); 0598 d->modules.append(cm); 0599 0600 if (qobject_cast<KCModuleQml *>(kcm->realModule())) { 0601 item->setHeaderVisible(false); 0602 } 0603 0604 if (kcm->realModule() && kcm->realModule()->useRootOnlyMessage()) { 0605 item->setHeader(QStringLiteral("<b>") + moduleInfo.moduleName() + QStringLiteral("</b><br><i>") + kcm->realModule()->rootOnlyMessage() 0606 + QStringLiteral("</i>")); 0607 item->setIcon(KIconUtils::addOverlay(QIcon::fromTheme(moduleInfo.icon()), QIcon::fromTheme(QStringLiteral("dialog-warning")), Qt::BottomRightCorner)); 0608 } else { 0609 item->setHeader(moduleInfo.moduleName()); 0610 item->setIcon(QIcon::fromTheme(moduleInfo.icon())); 0611 } 0612 item->setProperty("_k_weight", moduleInfo.weight()); 0613 0614 bool updateCurrentPage = false; 0615 const KPageWidgetModel *model = qobject_cast<const KPageWidgetModel *>(pageWidget()->model()); 0616 Q_ASSERT(model); 0617 if (parentItem) { 0618 const QModelIndex parentIndex = model->index(parentItem); 0619 const int siblingCount = model->rowCount(parentIndex); 0620 int row = 0; 0621 for (; row < siblingCount; ++row) { 0622 KPageWidgetItem *siblingItem = model->item(model->index(row, 0, parentIndex)); 0623 if (siblingItem->property("_k_weight").toInt() > moduleInfo.weight()) { 0624 // the item we found is heavier than the new module 0625 // qDebug() << "adding KCM " << item->name() << " before " << siblingItem->name(); 0626 insertPage(siblingItem, item); 0627 break; 0628 } 0629 } 0630 if (row >= siblingCount) { 0631 // the new module is either the first or the heaviest item 0632 // qDebug() << "adding KCM " << item->name() << " with parent " << parentItem->name(); 0633 addSubPage(parentItem, item); 0634 } 0635 } else { 0636 const int siblingCount = model->rowCount(); 0637 int row = 0; 0638 for (; row < siblingCount; ++row) { 0639 KPageWidgetItem *siblingItem = model->item(model->index(row, 0)); 0640 if (siblingItem->property("_k_weight").toInt() > moduleInfo.weight()) { 0641 // the item we found is heavier than the new module 0642 // qDebug() << "adding KCM " << item->name() << " before " << siblingItem->name(); 0643 insertPage(siblingItem, item); 0644 if (siblingItem == currentPage()) { 0645 updateCurrentPage = true; 0646 } 0647 0648 break; 0649 } 0650 } 0651 if (row == siblingCount) { 0652 // the new module is either the first or the heaviest item 0653 // qDebug() << "adding KCM " << item->name() << " at the top level"; 0654 addPage(item); 0655 } 0656 } 0657 0658 QObject::connect(kcm, qOverload<bool>(&KCModuleProxy::changed), this, [d]() { 0659 d->_k_clientChanged(); 0660 }); 0661 0662 QObject::connect(kcm->realModule(), &KCModule::rootOnlyMessageChanged, this, [d](bool use, QString message) { 0663 d->_k_updateHeader(use, message); 0664 }); 0665 0666 if (d->modules.count() == 1 || updateCurrentPage) { 0667 setCurrentPage(item); 0668 d->_k_clientChanged(); 0669 } 0670 return item; 0671 } 0672 #endif 0673 0674 void KCMultiDialog::clear() 0675 { 0676 Q_D(KCMultiDialog); 0677 // qDebug() ; 0678 0679 for (int i = 0; i < d->modules.count(); ++i) { 0680 removePage(d->modules[i].item); 0681 } 0682 0683 d->modules.clear(); 0684 0685 d->_k_clientChanged(); 0686 } 0687 0688 #include "moc_kcmultidialog.cpp"