File indexing completed on 2025-01-05 04:47:06

0001 /*
0002     SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "agentconfigurationwidget.h"
0008 #include "agentconfigurationdialog.h"
0009 #include "agentconfigurationwidget_p.h"
0010 #include "akonadiwidgets_debug.h"
0011 #include "core/agentconfigurationbase.h"
0012 #include "core/agentconfigurationfactorybase.h"
0013 #include "core/agentconfigurationmanager_p.h"
0014 #include "core/agentmanager.h"
0015 #include "core/servermanager.h"
0016 
0017 #include <QChildEvent>
0018 #include <QLabel>
0019 #include <QTimer>
0020 #include <QVBoxLayout>
0021 
0022 #include <KLocalizedString>
0023 #include <KSharedConfig>
0024 
0025 using namespace Akonadi;
0026 using namespace std::chrono_literals;
0027 AgentConfigurationWidgetPrivate::AgentConfigurationWidgetPrivate(const AgentInstance &instance)
0028     : agentInstance(instance)
0029 {
0030 }
0031 
0032 AgentConfigurationWidgetPrivate::~AgentConfigurationWidgetPrivate()
0033 {
0034 }
0035 
0036 void AgentConfigurationWidgetPrivate::setupErrorWidget(QWidget *parent, const QString &text)
0037 {
0038     auto layout = new QVBoxLayout(parent);
0039     layout->addStretch(2);
0040     auto label = new QLabel(text, parent);
0041     label->setAlignment(Qt::AlignCenter);
0042     layout->addWidget(label);
0043     layout->addStretch(2);
0044 }
0045 
0046 bool AgentConfigurationWidgetPrivate::loadPlugin(const QString &pluginPath)
0047 {
0048     if (pluginPath.isEmpty()) {
0049         qCDebug(AKONADIWIDGETS_LOG) << "Haven't found config plugin for" << agentInstance.type().identifier();
0050         return false;
0051     }
0052     loader = decltype(loader)(new QPluginLoader(pluginPath));
0053     if (!loader->load()) {
0054         qCWarning(AKONADIWIDGETS_LOG) << "Failed to load config plugin" << pluginPath << ":" << loader->errorString();
0055         loader.reset();
0056         return false;
0057     }
0058     factory = qobject_cast<AgentConfigurationFactoryBase *>(loader->instance());
0059     if (!factory) {
0060         // will unload the QPluginLoader and thus delete the factory as well
0061         qCWarning(AKONADIWIDGETS_LOG) << "Config plugin" << pluginPath << "does not contain AgentConfigurationFactory!";
0062         loader.reset();
0063         return false;
0064     }
0065 
0066     qCDebug(AKONADIWIDGETS_LOG) << "Loaded agent configuration plugin" << pluginPath;
0067     return true;
0068 }
0069 
0070 AgentConfigurationWidget::AgentConfigurationWidget(const AgentInstance &instance, QWidget *parent)
0071     : QWidget(parent)
0072     , d(new AgentConfigurationWidgetPrivate(instance))
0073 {
0074     if (AgentConfigurationManager::self()->registerInstanceConfiguration(instance.identifier())) {
0075         const auto pluginPath = AgentConfigurationManager::self()->findConfigPlugin(instance.type().identifier());
0076         if (d->loadPlugin(pluginPath)) {
0077             QString configName = instance.identifier() + QStringLiteral("rc");
0078             configName = Akonadi::ServerManager::addNamespace(configName);
0079             KSharedConfigPtr config = KSharedConfig::openConfig(configName);
0080             auto layout = new QVBoxLayout(this);
0081             layout->setContentsMargins({});
0082             d->plugin = d->factory->create(config, this, {instance.identifier()});
0083             connect(d->plugin.data(), &AgentConfigurationBase::enableOkButton, this, &AgentConfigurationWidget::enableOkButton);
0084         } else {
0085             // Hide this dialog and fallback to calling the out-of-process configuration
0086             if (auto dlg = qobject_cast<AgentConfigurationDialog *>(parent)) {
0087                 const_cast<AgentInstance &>(instance).configure(topLevelWidget()->parentWidget());
0088                 // If we are inside the AgentConfigurationDialog, hide the dialog
0089                 QTimer::singleShot(0s, this, [dlg]() {
0090                     dlg->reject();
0091                 });
0092             } else {
0093                 const_cast<AgentInstance &>(instance).configure();
0094                 // Otherwise show a message that this is opened externally
0095                 d->setupErrorWidget(this, i18n("The configuration dialog has been opened in another window"));
0096             }
0097 
0098             // TODO: Re-enable once we can kill the fallback code above ^^
0099             // d->setupErrorWidget(this, i18n("Failed to load configuration plugin"));
0100         }
0101     } else if (AgentConfigurationManager::self()->isInstanceRegistered(instance.identifier())) {
0102         d->setupErrorWidget(this, i18n("Configuration for %1 is already opened elsewhere.", instance.name()));
0103     } else {
0104         d->setupErrorWidget(this, i18n("Failed to register %1 configuration dialog.", instance.name()));
0105     }
0106 
0107     QTimer::singleShot(0, this, &AgentConfigurationWidget::load);
0108 }
0109 
0110 AgentConfigurationWidget::~AgentConfigurationWidget()
0111 {
0112     AgentConfigurationManager::self()->unregisterInstanceConfiguration(d->agentInstance.identifier());
0113 }
0114 
0115 void AgentConfigurationWidget::load()
0116 {
0117     if (d->plugin) {
0118         d->plugin->load();
0119     }
0120 }
0121 
0122 void AgentConfigurationWidget::save()
0123 {
0124     qCDebug(AKONADIWIDGETS_LOG) << "Saving configuration for" << d->agentInstance.identifier();
0125     if (d->plugin) {
0126         if (d->plugin->save()) {
0127             d->agentInstance.reconfigure();
0128         }
0129     }
0130 }
0131 
0132 QSize AgentConfigurationWidget::restoreDialogSize() const
0133 {
0134     if (d->plugin) {
0135         return d->plugin->restoreDialogSize();
0136     }
0137     return {};
0138 }
0139 
0140 void AgentConfigurationWidget::saveDialogSize(QSize size)
0141 {
0142     if (d->plugin) {
0143         d->plugin->saveDialogSize(size);
0144     }
0145 }
0146 
0147 QDialogButtonBox::StandardButtons AgentConfigurationWidget::standardButtons() const
0148 {
0149     if (d->plugin) {
0150         return d->plugin->standardButtons();
0151     }
0152     return QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel;
0153 }
0154 
0155 void AgentConfigurationWidget::childEvent(QChildEvent *event)
0156 {
0157     if (event->added()) {
0158         if (event->child()->isWidgetType()) {
0159             layout()->addWidget(static_cast<QWidget *>(event->child()));
0160         }
0161     }
0162 
0163     QWidget::childEvent(event);
0164 }
0165 
0166 #include "moc_agentconfigurationwidget.cpp"