13#include <config-libkleo.h>
15#include "directoryserviceswidget.h"
17#include "editdirectoryservicedialog.h"
19#include <libkleo/gnupg.h>
20#include <libkleo/keyserverconfig.h>
22#include <kleo_ui_debug.h>
24#include <KLocalizedString>
38bool activeDirectoryIsSupported()
40 return engineIsVersion(2, 2, 28, GpgME::GpgSMEngine);
43bool isStandardActiveDirectory(
const KeyserverConfig &keyserver)
45 return (keyserver.authentication() == KeyserverAuthentication::ActiveDirectory) && keyserver.host().
isEmpty();
48bool keyserverIsEditable(
const KeyserverConfig &keyserver)
51 return !isStandardActiveDirectory(keyserver);
58 explicit KeyserverModel(
QObject *parent =
nullptr)
63 void setKeyservers(
const std::vector<KeyserverConfig> &servers)
66 beginInsertRows(
QModelIndex(), 0, servers.size() - 1);
71 void addKeyserver(
const KeyserverConfig &keyserver)
73 const auto row = m_items.size();
75 m_items.push_back(keyserver);
79 KeyserverConfig getKeyserver(
unsigned int id)
81 if (
id >= m_items.size()) {
82 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
89 void updateKeyserver(
unsigned int id,
const KeyserverConfig &keyserver)
91 if (
id >= m_items.size()) {
92 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
96 m_items[id] = keyserver;
97 Q_EMIT dataChanged(index(
id), index(
id));
100 void deleteKeyserver(
unsigned int id)
102 if (
id >= m_items.size()) {
103 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
108 m_items.erase(m_items.begin() +
id);
114 if (m_items.empty()) {
117 beginRemoveRows(
QModelIndex(), 0, m_items.size() - 1);
124 return m_items.size();
135 const auto keyserver = m_items[index.
row()];
136 return isStandardActiveDirectory(keyserver) ?
i18n(
"Active Directory") : keyserver.host();
142 bool hasActiveDirectory()
145 return std::any_of(std::cbegin(m_items), std::cend(m_items), isStandardActiveDirectory);
152 std::vector<KeyserverConfig> m_items;
156class DirectoryServicesWidget::Private
158 DirectoryServicesWidget *
const q;
163 QAction *addActiveDirectoryAction =
nullptr;
164 QAction *addLdapServerAction =
nullptr;
168 KeyserverModel *keyserverModel =
nullptr;
169 bool readOnly =
false;
172 Private(DirectoryServicesWidget *qq)
179 gridLayout->setRowStretch(1, 1);
181 keyserverModel =
new KeyserverModel{q};
183 ui.keyserverList->setModel(keyserverModel);
184 ui.keyserverList->setModelColumn(0);
187 ui.keyserverList->setWhatsThis(
i18nc(
"@info:whatsthis",
"This is a list of all directory services that are configured for use with X.509."));
188 gridLayout->addWidget(ui.keyserverList, 1, 0);
192 auto menu =
new QMenu{q};
193 ui.addActiveDirectoryAction = menu->addAction(
i18n(
"Active Directory"), [
this]() {
194 addActiveDirectory();
196 ui.addActiveDirectoryAction->setToolTip(
i18nc(
"@info:tooltip",
197 "Click to use a directory service running on your Active Directory. "
198 "This works only on Windows and requires GnuPG 2.2.28 or later."));
199 ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported());
200 ui.addLdapServerAction = menu->addAction(
i18n(
"LDAP Server"), [
this]() {
203 ui.addLdapServerAction->setToolTip(
i18nc(
"@info:tooltip",
"Click to add a directory service provided by an LDAP server."));
205 ui.newButton->setText(
i18n(
"Add"));
206 ui.newButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to add a directory service."));
207 ui.newButton->setWhatsThis(
i18nc(
"@info:whatsthis",
208 "Click this button to add a directory service to the list of services. "
209 "The change will only take effect once you acknowledge the configuration dialog."));
213 ui.newButton->setMenu(menu);
214 groupsButtonLayout->addWidget(ui.newButton);
217 ui.editButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to edit the selected service."));
218 ui.editButton->setWhatsThis(
i18nc(
"@info:whatsthis",
219 "Click this button to edit the settings of the currently selected directory service. "
220 "The changes will only take effect once you acknowledge the configuration dialog."));
221 ui.editButton->setEnabled(
false);
222 groupsButtonLayout->addWidget(ui.editButton);
225 ui.deleteButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to remove the selected service."));
226 ui.deleteButton->setWhatsThis(
i18nc(
"@info:whatsthis",
227 "Click this button to remove the currently selected directory service. "
228 "The change will only take effect once you acknowledge the configuration dialog."));
229 ui.deleteButton->setEnabled(
false);
230 groupsButtonLayout->addWidget(ui.deleteButton);
232 groupsButtonLayout->addStretch(1);
234 gridLayout->addLayout(groupsButtonLayout, 1, 1);
236 mainLayout->addLayout(gridLayout, 1);
252 editKeyserver(index);
263 void setReadOnly(
bool ro)
269 void setKeyservers(
const std::vector<KeyserverConfig> &servers)
271 keyserverModel->setKeyservers(servers);
274 std::vector<KeyserverConfig> keyservers()
const
276 std::vector<KeyserverConfig> result;
277 result.reserve(keyserverModel->rowCount());
278 for (
int row = 0; row < keyserverModel->rowCount(); ++row) {
279 result.push_back(keyserverModel->getKeyserver(row));
286 if (keyserverModel->rowCount() == 0) {
289 keyserverModel->clear();
295 const auto indexes = ui.keyserverList->selectionModel()->selectedRows();
296 return indexes.empty() ?
QModelIndex() : indexes[0];
305 void selectionChanged()
312 const auto index = selectedIndex();
313 ui.newButton->setEnabled(!readOnly);
314 ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported() && !keyserverModel->hasActiveDirectory());
315 ui.editButton->setEnabled(!readOnly && index.
isValid() && keyserverIsEditable(keyserverModel->getKeyserver(index.
row())));
316 ui.deleteButton->setEnabled(!readOnly && index.
isValid());
319 void handleEditKeyserverDialogResult(
const int id,
const EditDirectoryServiceDialog *dialog)
322 keyserverModel->updateKeyserver(
id, dialog->keyserver());
324 keyserverModel->addKeyserver(dialog->keyserver());
328 void showEditKeyserverDialog(
const int id,
const KeyserverConfig &keyserver,
const QString &windowTitle)
334 dialog->setKeyserver(keyserver);
337 handleEditKeyserverDialogResult(
id, dialog);
343 void addActiveDirectory()
345 KeyserverConfig keyserver;
346 keyserver.setAuthentication(KeyserverAuthentication::ActiveDirectory);
347 keyserverModel->addKeyserver(keyserver);
352 showEditKeyserverDialog(-1, {},
i18nc(
"@title:window",
"LDAP Directory Service"));
357 const auto serverIndex = index.
isValid() ? index : selectedIndex();
358 if (!serverIndex.isValid()) {
359 qCDebug(KLEO_UI_LOG) << __func__ <<
"selection is empty";
362 const auto id = serverIndex.row();
363 const KeyserverConfig keyserver = keyserverModel->getKeyserver(
id);
364 if (!keyserverIsEditable(keyserver)) {
365 qCDebug(KLEO_UI_LOG) << __func__ <<
"selected keyserver (id:" <<
id <<
") cannot be modified";
369 showEditKeyserverDialog(
id, keyserver,
i18nc(
"@title:window",
"LDAP Directory Service"));
372 void deleteKeyserver()
376 qCDebug(KLEO_UI_LOG) << __func__ <<
"selection is empty";
379 keyserverModel->deleteKeyserver(serverIndex.
row());
383DirectoryServicesWidget::DirectoryServicesWidget(
QWidget *parent)
385 , d{std::make_unique<Private>(this)}
389DirectoryServicesWidget::~DirectoryServicesWidget() =
default;
391void DirectoryServicesWidget::setKeyservers(
const std::vector<KeyserverConfig> &servers)
393 d->setKeyservers(servers);
396std::vector<KeyserverConfig> DirectoryServicesWidget::keyservers()
const
398 return d->keyservers();
401void DirectoryServicesWidget::setReadOnly(
bool readOnly)
403 d->setReadOnly(readOnly);
406void DirectoryServicesWidget::clear()
411#include "directoryserviceswidget.moc"
413#include "moc_directoryserviceswidget.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
void doubleClicked(const QModelIndex &index)
void setColumnStretch(int column, int stretch)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)