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)
59 : QAbstractListModel{parent}
63 void setKeyservers(
const std::vector<KeyserverConfig> &servers)
66 if (!servers.empty()) {
67 beginInsertRows(QModelIndex(), 0, servers.size() - 1);
70 if (!servers.empty()) {
75 void addKeyserver(
const KeyserverConfig &keyserver)
77 const auto row = m_items.size();
78 beginInsertRows(QModelIndex(), row, row);
79 m_items.push_back(keyserver);
83 KeyserverConfig getKeyserver(
unsigned int id)
85 if (
id >= m_items.size()) {
86 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
93 void updateKeyserver(
unsigned int id,
const KeyserverConfig &keyserver)
95 if (
id >= m_items.size()) {
96 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
100 m_items[id] = keyserver;
101 Q_EMIT dataChanged(index(
id), index(
id));
104 void deleteKeyserver(
unsigned int id)
106 if (
id >= m_items.size()) {
107 qCDebug(KLEO_UI_LOG) << __func__ <<
"invalid keyserver id:" << id;
111 beginRemoveRows(QModelIndex(),
id,
id);
112 m_items.erase(m_items.begin() +
id);
118 if (m_items.empty()) {
121 beginRemoveRows(QModelIndex(), 0, m_items.size() - 1);
126 int rowCount(
const QModelIndex & = QModelIndex())
const override
128 return m_items.size();
131 QVariant data(
const QModelIndex &index,
int role)
const override
139 const auto keyserver = m_items[index.
row()];
140 return isStandardActiveDirectory(keyserver) ?
i18n(
"Active Directory") : keyserver.host();
146 bool hasActiveDirectory()
149 return std::any_of(std::cbegin(m_items), std::cend(m_items), isStandardActiveDirectory);
156 std::vector<KeyserverConfig> m_items;
160class DirectoryServicesWidget::Private
162 DirectoryServicesWidget *
const q;
165 QListView *keyserverList =
nullptr;
166 QToolButton *newButton =
nullptr;
167 QAction *addActiveDirectoryAction =
nullptr;
168 QAction *addLdapServerAction =
nullptr;
169 QPushButton *editButton =
nullptr;
170 QPushButton *deleteButton =
nullptr;
172 KeyserverModel *keyserverModel =
nullptr;
173 bool readOnly =
false;
176 Private(DirectoryServicesWidget *qq)
179 auto mainLayout =
new QVBoxLayout{q};
181 auto gridLayout =
new QGridLayout{};
182 gridLayout->setColumnStretch(0, 1);
183 gridLayout->setRowStretch(1, 1);
185 keyserverModel =
new KeyserverModel{q};
186 ui.keyserverList =
new QListView();
187 ui.keyserverList->setModel(keyserverModel);
188 ui.keyserverList->setModelColumn(0);
191 ui.keyserverList->setWhatsThis(
i18nc(
"@info:whatsthis",
"This is a list of all directory services that are configured for use with X.509."));
192 gridLayout->addWidget(ui.keyserverList, 1, 0);
194 auto groupsButtonLayout =
new QVBoxLayout();
196 auto menu =
new QMenu{q};
197 ui.addActiveDirectoryAction = menu->addAction(
i18n(
"Active Directory"), [
this]() {
198 addActiveDirectory();
200 ui.addActiveDirectoryAction->setToolTip(
i18nc(
"@info:tooltip",
201 "Click to use a directory service running on your Active Directory. "
202 "This works only on Windows and requires GnuPG 2.2.28 or later."));
203 ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported());
204 ui.addLdapServerAction = menu->addAction(
i18n(
"LDAP Server"), [
this]() {
207 ui.addLdapServerAction->setToolTip(
i18nc(
"@info:tooltip",
"Click to add a directory service provided by an LDAP server."));
208 ui.newButton =
new QToolButton{q};
209 ui.newButton->setText(
i18n(
"Add"));
210 ui.newButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to add a directory service."));
211 ui.newButton->setWhatsThis(
i18nc(
"@info:whatsthis",
212 "Click this button to add a directory service to the list of services. "
213 "The change will only take effect once you acknowledge the configuration dialog."));
217 ui.newButton->setMenu(menu);
218 groupsButtonLayout->addWidget(ui.newButton);
220 ui.editButton =
new QPushButton(
i18nc(
"@action:button",
"Edit"));
221 ui.editButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to edit the selected service."));
222 ui.editButton->setWhatsThis(
i18nc(
"@info:whatsthis",
223 "Click this button to edit the settings of the currently selected directory service. "
224 "The changes will only take effect once you acknowledge the configuration dialog."));
225 ui.editButton->setEnabled(
false);
226 groupsButtonLayout->addWidget(ui.editButton);
228 ui.deleteButton =
new QPushButton(
i18nc(
"@action:button",
"Delete"));
229 ui.deleteButton->setToolTip(
i18nc(
"@info:tooltip",
"Click to remove the selected service."));
230 ui.deleteButton->setWhatsThis(
i18nc(
"@info:whatsthis",
231 "Click this button to remove the currently selected directory service. "
232 "The change will only take effect once you acknowledge the configuration dialog."));
233 ui.deleteButton->setEnabled(
false);
234 groupsButtonLayout->addWidget(ui.deleteButton);
236 groupsButtonLayout->addStretch(1);
238 gridLayout->addLayout(groupsButtonLayout, 1, 1);
240 mainLayout->addLayout(gridLayout, 1);
256 editKeyserver(index);
267 void setReadOnly(
bool ro)
273 void setKeyservers(
const std::vector<KeyserverConfig> &servers)
275 keyserverModel->setKeyservers(servers);
278 std::vector<KeyserverConfig> keyservers()
const
280 std::vector<KeyserverConfig> result;
281 result.reserve(keyserverModel->rowCount());
282 for (
int row = 0; row < keyserverModel->rowCount(); ++row) {
283 result.push_back(keyserverModel->getKeyserver(row));
290 if (keyserverModel->rowCount() == 0) {
293 keyserverModel->clear();
299 const auto indexes = ui.keyserverList->selectionModel()->selectedRows();
300 return indexes.empty() ?
QModelIndex() : indexes[0];
309 void selectionChanged()
316 const auto index = selectedIndex();
317 ui.newButton->setEnabled(!readOnly);
318 ui.addActiveDirectoryAction->setEnabled(activeDirectoryIsSupported() && !keyserverModel->hasActiveDirectory());
319 ui.editButton->setEnabled(!readOnly && index.
isValid() && keyserverIsEditable(keyserverModel->getKeyserver(index.
row())));
320 ui.deleteButton->setEnabled(!readOnly && index.
isValid());
323 void handleEditKeyserverDialogResult(
const int id,
const EditDirectoryServiceDialog *dialog)
326 keyserverModel->updateKeyserver(
id, dialog->keyserver());
328 keyserverModel->addKeyserver(dialog->keyserver());
332 void showEditKeyserverDialog(
const int id,
const KeyserverConfig &keyserver,
const QString &windowTitle)
338 dialog->setKeyserver(keyserver);
341 handleEditKeyserverDialogResult(
id, dialog);
347 void addActiveDirectory()
349 KeyserverConfig keyserver;
350 keyserver.setAuthentication(KeyserverAuthentication::ActiveDirectory);
351 keyserverModel->addKeyserver(keyserver);
356 showEditKeyserverDialog(-1, {},
i18nc(
"@title:window",
"LDAP Directory Service"));
361 const auto serverIndex = index.
isValid() ? index : selectedIndex();
362 if (!serverIndex.isValid()) {
363 qCDebug(KLEO_UI_LOG) << __func__ <<
"selection is empty";
366 const auto id = serverIndex.row();
367 const KeyserverConfig keyserver = keyserverModel->getKeyserver(
id);
368 if (!keyserverIsEditable(keyserver)) {
369 qCDebug(KLEO_UI_LOG) << __func__ <<
"selected keyserver (id:" <<
id <<
") cannot be modified";
373 showEditKeyserverDialog(
id, keyserver,
i18nc(
"@title:window",
"LDAP Directory Service"));
376 void deleteKeyserver()
380 qCDebug(KLEO_UI_LOG) << __func__ <<
"selection is empty";
383 keyserverModel->deleteKeyserver(serverIndex.
row());
387DirectoryServicesWidget::DirectoryServicesWidget(
QWidget *parent)
389 , d{std::make_unique<Private>(this)}
393DirectoryServicesWidget::~DirectoryServicesWidget() =
default;
395void DirectoryServicesWidget::setKeyservers(
const std::vector<KeyserverConfig> &servers)
397 d->setKeyservers(servers);
400std::vector<KeyserverConfig> DirectoryServicesWidget::keyservers()
const
402 return d->keyservers();
405void DirectoryServicesWidget::setReadOnly(
bool readOnly)
407 d->setReadOnly(readOnly);
410void DirectoryServicesWidget::clear()
415#include "directoryserviceswidget.moc"
417#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 selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)