Akonadi

agentconfigurationwidget.cpp
1 /*
2  Copyright (c) 2018 Daniel Vrátil <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "agentconfigurationwidget.h"
21 #include "agentconfigurationwidget_p.h"
22 #include "agentconfigurationdialog.h"
23 #include "akonadiwidgets_debug.h"
24 #include "core/agentconfigurationmanager_p.h"
25 #include "core/agentconfigurationbase.h"
26 #include "core/agentconfigurationfactorybase.h"
27 #include "core/agentmanager.h"
28 #include "core/servermanager.h"
29 
30 #include <QTimer>
31 #include <QLabel>
32 #include <QVBoxLayout>
33 #include <QChildEvent>
34 
35 #include <KSharedConfig>
36 #include <KLocalizedString>
37 #include <QDialogButtonBox>
38 
39 #include <memory>
40 
41 using namespace Akonadi;
42 
43 AgentConfigurationWidget::Private::Private(const AgentInstance &instance)
44  : agentInstance(instance)
45 {
46 }
47 
48 AgentConfigurationWidget::Private::~Private()
49 {
50 }
51 
52 void AgentConfigurationWidget::Private::setupErrorWidget(QWidget *parent, const QString &text)
53 {
54  QVBoxLayout *layout = new QVBoxLayout(parent);
55  layout->addStretch(2);
56  auto label = new QLabel(text, parent);
57  label->setAlignment(Qt::AlignCenter);
58  layout->addWidget(label);
59  layout->addStretch(2);
60 }
61 
62 bool AgentConfigurationWidget::Private::loadPlugin(const QString &pluginPath)
63 {
64  if (pluginPath.isEmpty()) {
65  qCDebug(AKONADIWIDGETS_LOG) << "Haven't found config plugin for" << agentInstance.type().identifier();
66  return false;
67  }
68  loader = decltype(loader)(new QPluginLoader(pluginPath));
69  if (!loader->load()) {
70  qCWarning(AKONADIWIDGETS_LOG) << "Failed to load config plugin" << pluginPath << ":" << loader->errorString();
71  loader.reset();
72  return false;
73  }
74  factory = qobject_cast<AgentConfigurationFactoryBase*>(loader->instance());
75  if (!factory) {
76  // will unload the QPluginLoader and thus delete the factory as well
77  qCWarning(AKONADIWIDGETS_LOG) << "Config plugin" << pluginPath << "does not contain AgentConfigurationFactory!";
78  loader.reset();
79  return false;
80  }
81 
82  qCDebug(AKONADIWIDGETS_LOG) << "Loaded agent configuration plugin" << pluginPath;
83  return true;
84 }
85 
86 
87 AgentConfigurationWidget::AgentConfigurationWidget(const AgentInstance &instance, QWidget *parent)
88  : QWidget(parent)
89  , d(new Private(instance))
90 {
91  if (AgentConfigurationManager::self()->registerInstanceConfiguration(instance.identifier())) {
92  const auto pluginPath = AgentConfigurationManager::self()->findConfigPlugin(instance.type().identifier());
93  if (d->loadPlugin(pluginPath)) {
94  QString configName = instance.identifier() + QStringLiteral("rc");
95  configName = Akonadi::ServerManager::addNamespace(configName);
96  KSharedConfigPtr config = KSharedConfig::openConfig(configName);
97  QVBoxLayout *layout = new QVBoxLayout(this);
98  layout->setContentsMargins(0, 0, 0, 0);
99  d->plugin = d->factory->create(config, this, { instance.identifier() });
100  connect(d->plugin.data(), &AgentConfigurationBase::enableOkButton, this, &AgentConfigurationWidget::enableOkButton);
101  } else {
102  // Hide this dialog and fallback to calling the out-of-process configuration
103  if (auto dlg = qobject_cast<AgentConfigurationDialog*>(parent)) {
104  const_cast<AgentInstance&>(instance).configure(topLevelWidget()->parentWidget());
105  // If we are inside the AgentConfigurationDialog, hide the dialog
106  QTimer::singleShot(0, this, [dlg]() { dlg->reject(); });
107  } else {
108  const_cast<AgentInstance&>(instance).configure();
109  // Otherwise show a message that this is opened externally
110  d->setupErrorWidget(this, i18n("The configuration dialog has been opened in another window"));
111  }
112 
113  // TODO: Re-enable once we can kill the fallback code above ^^
114  //d->setupErrorWidget(this, i18n("Failed to load configuration plugin"));
115  }
116  } else if (AgentConfigurationManager::self()->isInstanceRegistered(instance.identifier())) {
117  d->setupErrorWidget(this, i18n("Configuration for %1 is already opened elsewhere.", instance.name()));
118  } else {
119  d->setupErrorWidget(this, i18n("Failed to register %1 configuration dialog.", instance.name()));
120  }
121 
122  QTimer::singleShot(0, this, &AgentConfigurationWidget::load);
123 }
124 
125 AgentConfigurationWidget::~AgentConfigurationWidget()
126 {
127  AgentConfigurationManager::self()->unregisterInstanceConfiguration(d->agentInstance.identifier());
128 }
129 
130 void AgentConfigurationWidget::load()
131 {
132  if (d->plugin) {
133  d->plugin->load();
134  }
135 }
136 
137 void AgentConfigurationWidget::save()
138 {
139  qCDebug(AKONADIWIDGETS_LOG) << "Saving configuration for" << d->agentInstance.identifier();
140  if (d->plugin) {
141  if (d->plugin->save()) {
142  d->agentInstance.reconfigure();
143  }
144  }
145 }
146 
147 QSize AgentConfigurationWidget::restoreDialogSize() const
148 {
149  if (d->plugin) {
150  return d->plugin->restoreDialogSize();
151  }
152  return {};
153 }
154 
155 void AgentConfigurationWidget::saveDialogSize(QSize size)
156 {
157  if (d->plugin) {
158  d->plugin->saveDialogSize(size);
159  }
160 }
161 
162 QDialogButtonBox::StandardButtons AgentConfigurationWidget::standardButtons() const
163 {
164  if (d->plugin) {
165  return d->plugin->standardButtons();
166  }
167  return QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel;
168 }
169 
170 void AgentConfigurationWidget::childEvent(QChildEvent *event)
171 {
172  if (event->added()) {
173  if (event->child()->isWidgetType()) {
174  layout()->addWidget(static_cast<QWidget*>(event->child()));
175  }
176  }
177 
178  QWidget::childEvent(event);
179 }
void setContentsMargins(int left, int top, int right, int bottom)
virtual void childEvent(QChildEvent *event)
AgentType type() const
Returns the agent type of this instance.
QString identifier() const
Returns the unique identifier of the agent instance.
QString identifier() const
Returns the unique identifier of the agent type.
QObject * child() const const
virtual bool event(QEvent *e)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
KGuiItem configure()
bool added() const const
QString label(StandardShortcut id)
bool isEmpty() const const
T * data() const const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18n(const char *text, const TYPE &arg...)
typedef StandardButtons
void addStretch(int stretch)
QString name() const
Returns the user visible name of the agent instance.
Helper integration between Akonadi and Qt.
A representation of an agent instance.
bool isWidgetType() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with &#39;_&#39; as separator).
T qobject_cast(QObject *object)
QObject * parent() const const
KSharedConfigPtr config() const
Returns KConfig object belonging to the current Akonadi agent instance.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:53 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.