aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-11 02:17:32 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-11 02:17:32 +0200
commit2779c61e83491d1d798f3f494aa890e3f586245a (patch)
treec09e6e77efd85465a331a65f5f8d73dd450d6b4f /src
parentab3e5ad5f25862985c17ba557163a1902b54747f (diff)
downloadkristall-2779c61e83491d1d798f3f494aa890e3f586245a.tar.gz
Adds first draft of client certificate management.
Diffstat (limited to 'src')
-rw-r--r--src/certificateselectiondialog.cpp46
-rw-r--r--src/certificateselectiondialog.hpp6
-rw-r--r--src/certificateselectiondialog.ui2
-rw-r--r--src/documentoutlinemodel.cpp3
-rw-r--r--src/identitycollection.cpp263
-rw-r--r--src/identitycollection.hpp78
-rw-r--r--src/kristall.hpp3
-rw-r--r--src/kristall.pro5
-rw-r--r--src/main.cpp5
-rw-r--r--src/mainwindow.cpp7
-rw-r--r--src/newidentitiydialog.cpp74
-rw-r--r--src/newidentitiydialog.hpp40
-rw-r--r--src/newidentitiydialog.ui112
13 files changed, 641 insertions, 3 deletions
diff --git a/src/certificateselectiondialog.cpp b/src/certificateselectiondialog.cpp
index 70dac42..e3aef35 100644
--- a/src/certificateselectiondialog.cpp
+++ b/src/certificateselectiondialog.cpp
@@ -2,6 +2,12 @@
#include "ui_certificateselectiondialog.h"
#include "certificatehelper.hpp"
+#include "kristall.hpp"
+#include "newidentitiydialog.hpp"
+
+
+#include <QDebug>
+#include <QItemSelectionModel>
CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) :
QDialog(parent),
@@ -9,6 +15,11 @@ CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) :
{
ui->setupUi(this);
this->ui->server_request->setVisible(false);
+
+ this->ui->certificates->setModel(&global_identities);
+ this->ui->certificates->expandAll();
+
+ connect(this->ui->certificates->selectionModel(), &QItemSelectionModel::currentChanged, this, &CertificateSelectionDialog::on_currentChanged);
}
CertificateSelectionDialog::~CertificateSelectionDialog()
@@ -69,3 +80,38 @@ void CertificateSelectionDialog::acceptTemporaryWithTimeout(QDateTime timeout)
this->accept();
}
+
+void CertificateSelectionDialog::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ auto id = global_identities.getIdentity(current);
+
+ this->ui->use_selected_cert->setEnabled(id.isValid());
+}
+
+void CertificateSelectionDialog::on_create_new_cert_clicked()
+{
+ NewIdentitiyDialog dialog { this };
+
+ if(dialog.exec() != QDialog::Accepted)
+ return;
+
+ auto id = dialog.createIdentity();
+ if(not id.isValid())
+ return;
+ id.is_persistent = true;
+
+ global_identities.addCertificate(
+ dialog.groupName(),
+ id);
+}
+
+void CertificateSelectionDialog::on_use_selected_cert_clicked()
+{
+ auto sel = this->ui->certificates->selectionModel()->currentIndex();
+ this->cryto_identity = global_identities.getIdentity(sel);
+ if(this->cryto_identity.isValid()) {
+ this->accept();
+ } else {
+ qDebug() << "Tried to use an invalid identity when the button should not be enabled. This is a bug!";
+ }
+}
diff --git a/src/certificateselectiondialog.hpp b/src/certificateselectiondialog.hpp
index 55fe909..da43b0e 100644
--- a/src/certificateselectiondialog.hpp
+++ b/src/certificateselectiondialog.hpp
@@ -32,11 +32,17 @@ private slots:
void on_use_temp_cert_48h_clicked();
+ void on_create_new_cert_clicked();
+
+ void on_use_selected_cert_clicked();
+
private:
//! Creates an anonymous identity with a randomly chosen name that
//! will time out on `timeout`, then accepts the dialog.
void acceptTemporaryWithTimeout(QDateTime timeout);
+
+ void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);
private:
Ui::CertificateSelectionDialog *ui;
diff --git a/src/certificateselectiondialog.ui b/src/certificateselectiondialog.ui
index d7179ae..0199982 100644
--- a/src/certificateselectiondialog.ui
+++ b/src/certificateselectiondialog.ui
@@ -35,7 +35,7 @@
</widget>
</item>
<item>
- <widget class="QTreeView" name="treeView"/>
+ <widget class="QTreeView" name="certificates"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
diff --git a/src/documentoutlinemodel.cpp b/src/documentoutlinemodel.cpp
index 604ca6f..0f12233 100644
--- a/src/documentoutlinemodel.cpp
+++ b/src/documentoutlinemodel.cpp
@@ -115,7 +115,6 @@ QModelIndex DocumentOutlineModel::index(int row, int column, const QModelIndex &
if (childItem)
return createIndex(row, column, reinterpret_cast<quintptr>(childItem));
return QModelIndex();
-
}
QModelIndex DocumentOutlineModel::parent(const QModelIndex &child) const
@@ -137,7 +136,7 @@ QModelIndex DocumentOutlineModel::parent(const QModelIndex &child) const
int DocumentOutlineModel::rowCount(const QModelIndex &parent) const
{
- Node const *parentItem;
+ Node const * parentItem;
if (parent.column() > 0)
return 0;
diff --git a/src/identitycollection.cpp b/src/identitycollection.cpp
new file mode 100644
index 0000000..9955d3f
--- /dev/null
+++ b/src/identitycollection.cpp
@@ -0,0 +1,263 @@
+#include "identitycollection.hpp"
+
+#include <cassert>
+#include <QDebug>
+
+IdentityCollection::IdentityCollection(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+}
+
+void IdentityCollection::load(QSettings &settings)
+{
+ this->beginResetModel();
+
+ this->root.children.clear();
+
+ int group_cnt = settings.beginReadArray("groups");
+ for(int i = 0; i < group_cnt; i++)
+ {
+ settings.setArrayIndex(i);
+ auto group = std::make_unique<GroupNode>();
+
+ group->title = settings.value("name").toString();
+
+ int id_cnt = settings.beginReadArray("identities");
+
+ for(int j = 0; j < id_cnt; j++)
+ {
+ settings.setArrayIndex(j);
+ auto id = std::make_unique<IdentityNode>();
+
+ id->identity.is_persistent = true;
+ id->identity.display_name = settings.value("display_name").toString();
+
+ id->identity.certificate = QSslCertificate::fromData(
+ settings.value("certificate").toByteArray(),
+ QSsl::Der
+ ).first();
+
+ id->identity.private_key = QSslKey(
+ settings.value("private_key").toByteArray(),
+ QSsl::Rsa,
+ QSsl::Der
+ );
+
+ group->children.emplace_back(std::move(id));
+ }
+
+ settings.endArray();
+
+ this->root.children.emplace_back(std::move(group));
+ }
+ settings.endArray();
+
+ relayout();
+
+ this->endResetModel();
+}
+
+void IdentityCollection::save(QSettings &settings) const
+{
+ settings.beginWriteArray("groups", int(root.children.size()));
+
+ int grp_index = 0;
+ for(auto const & grp : root.children)
+ {
+ settings.setArrayIndex(grp_index);
+ grp_index += 1;
+
+ auto & group = grp->as<GroupNode>();
+ settings.setValue("name", group.title);
+
+ settings.beginWriteArray("identities", int(group.children.size()));
+
+ int id_index = 0;
+ for(auto const & _id : group.children)
+ {
+ settings.setArrayIndex(id_index);
+ id_index += 1;
+
+ auto & id = _id->as<IdentityNode>();
+
+ settings.setValue("display_name", id.identity.display_name);
+ settings.setValue("certificate", id.identity.certificate.toDer());
+ settings.setValue("private_key", id.identity.private_key.toDer());
+ }
+
+
+ settings.endArray();
+ }
+
+ settings.endArray();
+}
+
+bool IdentityCollection::addCertificate(const QString &group_name, const CryptoIdentity &crypto_id)
+{
+ // Don't allow saving transient certificates
+ if(not crypto_id.is_persistent)
+ return false;
+
+ this->beginResetModel();
+
+ GroupNode * group = nullptr;
+ for(auto const & grp : root.children)
+ {
+ auto * g = static_cast<GroupNode*>(grp.get());
+ if(g->title == group_name) {
+ group = g;
+ break;
+ }
+ }
+ if(group == nullptr) {
+ group = new GroupNode();
+ group->title = group_name;
+ this->root.children.emplace_back(group);
+ }
+
+ auto id = std::make_unique<IdentityNode>();
+ id->identity = crypto_id;
+ group->children.emplace_back(std::move(id));
+
+ this->relayout();
+
+ this->endResetModel();
+
+ return true;
+}
+
+CryptoIdentity IdentityCollection::getIdentity(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return CryptoIdentity();
+
+ if (index.column() != 0)
+ return CryptoIdentity();
+
+ Node const *item = static_cast<Node const*>(index.internalPointer());
+ switch(item->type) {
+ case Node::Identity: return static_cast<IdentityNode const *>(item)->identity;
+ default:
+ return CryptoIdentity();
+ }
+}
+
+QStringList IdentityCollection::groups() const
+{
+ QStringList result;
+ for(auto const & grp : root.children)
+ {
+ result.append(grp->as<GroupNode>().title);
+ }
+ return result;
+}
+
+//QVariant IdentityCollection::headerData(int section, Qt::Orientation orientation, int role) const
+//{
+// return QVariant { };
+//}
+
+QModelIndex IdentityCollection::index(int row, int column, const QModelIndex &parent) const
+{
+ qDebug() << "index" << row << column << parent;
+ if (not hasIndex(row, column, parent))
+ return QModelIndex();
+
+ Node const * parentItem;
+
+ if(!parent.isValid())
+ parentItem = &this->root;
+ else
+ parentItem = static_cast<Node*>(parent.internalPointer());
+
+ auto & children = parentItem->children;
+ if(row < 0 or size_t(row) >= children.size())
+ return QModelIndex { };
+ return createIndex(
+ row,
+ column,
+ reinterpret_cast<quintptr>(children[row].get())
+ );
+}
+
+QModelIndex IdentityCollection::parent(const QModelIndex &index) const
+{
+ qDebug() << "parent" << index;
+ if (!index.isValid())
+ return QModelIndex();
+
+ Node const *childItem = static_cast<Node const *>(index.internalPointer());
+ Node const * parent = childItem->parent;
+
+ if (parent == &root)
+ return QModelIndex();
+
+ return createIndex(
+ parent->index,
+ 0,
+ reinterpret_cast<quintptr>(parent));
+}
+
+int IdentityCollection::rowCount(const QModelIndex &parent) const
+{
+ Node const * parentItem;
+
+ if (!parent.isValid())
+ parentItem = &root;
+ else
+ parentItem = static_cast<Node const *>(parent.internalPointer());
+
+ int rc = parentItem->children.size();
+ qDebug() << "row count for " << parent << rc;
+ return rc;
+}
+
+int IdentityCollection::columnCount(const QModelIndex &parent) const
+{
+ qDebug() << "column count" << parent;
+ return 1;
+}
+
+QVariant IdentityCollection::data(const QModelIndex &index, int role) const
+{
+ qDebug() << "data" << index << role;
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.column() != 0)
+ return QVariant();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ Node const *item = static_cast<Node const*>(index.internalPointer());
+ switch(item->type) {
+ case Node::Root: return "root";
+ case Node::Group: return static_cast<GroupNode const *>(item)->title;
+ case Node::Identity: return static_cast<IdentityNode const *>(item)->identity.display_name;
+ default:
+ return "Unknown";
+ }
+}
+
+void IdentityCollection::relayout()
+{
+ for(size_t i = 0; i < root.children.size(); i++)
+ {
+ auto & group = *root.children[i];
+ group.parent = &root;
+ group.index = i;
+
+ qDebug() << "group[" << group.index << "]" << group.as<GroupNode>().title;
+
+ for(size_t j = 0; j < group.children.size(); j++)
+ {
+ auto & id = *group.children[j];
+ id.parent = &group;
+ id.index = j;
+ assert(id.children.size() == 0);
+
+ qDebug() << "id[" << id.index << "]" << id.as<IdentityNode>().identity.display_name;
+ }
+ }
+}
diff --git a/src/identitycollection.hpp b/src/identitycollection.hpp
new file mode 100644
index 0000000..38463ab
--- /dev/null
+++ b/src/identitycollection.hpp
@@ -0,0 +1,78 @@
+#ifndef IDENTITYCOLLECTION_HPP
+#define IDENTITYCOLLECTION_HPP
+
+#include "cryptoidentity.hpp"
+
+#include <QAbstractItemModel>
+#include <memory>
+#include <QSettings>
+
+class IdentityCollection : public QAbstractItemModel
+{
+ Q_OBJECT
+ struct Node {
+ enum Type { Root, Group, Identity };
+ Node * parent = nullptr;
+ int index = 0;
+ std::vector<std::unique_ptr<Node>> children;
+ Type type;
+ explicit Node(Type t) : type(t) { }
+ virtual ~Node() = default;
+
+ template<typename T>
+ T & as() { return *static_cast<T*>(this); }
+ };
+
+ struct IdentityNode : Node {
+ CryptoIdentity identity;
+ IdentityNode() : Node(Identity) { }
+ ~IdentityNode() override = default;
+ };
+
+ struct GroupNode : Node {
+ QString title;
+ GroupNode() : Node(Group) { }
+ ~GroupNode() override = default;
+ };
+
+ struct RootNode : Node {
+ RootNode() : Node(Root) { }
+ ~RootNode() override = default;
+ };
+
+public:
+ explicit IdentityCollection(QObject *parent = nullptr);
+
+public:
+ void load(QSettings & settings);
+
+ void save(QSettings & settings) const;
+
+ bool addCertificate(QString const & group, CryptoIdentity const & id);
+
+ CryptoIdentity getIdentity(QModelIndex const & index) const;
+
+ QStringList groups() const;
+
+public:
+ // Header:
+ // QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+ // Basic functionality:
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+private:
+ void relayout();
+
+private:
+ RootNode root;
+};
+
+#endif // IDENTITYCOLLECTION_HPP
diff --git a/src/kristall.hpp b/src/kristall.hpp
index 73c0bc5..a0a4b49 100644
--- a/src/kristall.hpp
+++ b/src/kristall.hpp
@@ -4,7 +4,10 @@
#include <QSettings>
#include <QClipboard>
+#include "identitycollection.hpp"
+
extern QSettings global_settings;
+extern IdentityCollection global_identities;
extern QClipboard * global_clipboard;
#endif // KRISTALL_HPP
diff --git a/src/kristall.pro b/src/kristall.pro
index 91aabf2..73f2892 100644
--- a/src/kristall.pro
+++ b/src/kristall.pro
@@ -37,10 +37,12 @@ SOURCES += \
geminirenderer.cpp \
gopherclient.cpp \
gophermaprenderer.cpp \
+ identitycollection.cpp \
ioutil.cpp \
main.cpp \
mainwindow.cpp \
mediaplayer.cpp \
+ newidentitiydialog.cpp \
plaintextrenderer.cpp \
protocolsetup.cpp \
settingsdialog.cpp \
@@ -61,10 +63,12 @@ HEADERS += \
geminirenderer.hpp \
gopherclient.hpp \
gophermaprenderer.hpp \
+ identitycollection.hpp \
ioutil.hpp \
kristall.hpp \
mainwindow.hpp \
mediaplayer.hpp \
+ newidentitiydialog.hpp \
plaintextrenderer.hpp \
protocolsetup.hpp \
settingsdialog.hpp \
@@ -76,6 +80,7 @@ FORMS += \
certificateselectiondialog.ui \
mainwindow.ui \
mediaplayer.ui \
+ newidentitiydialog.ui \
settingsdialog.ui
TRANSLATIONS += \
diff --git a/src/main.cpp b/src/main.cpp
index b7974de..c280425 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,6 +7,7 @@
#include <QCommandLineParser>
#include <QDebug>
+IdentityCollection global_identities;
QSettings global_settings { "xqTechnologies", "Kristall" };
QClipboard * global_clipboard;
@@ -23,6 +24,10 @@ int main(int argc, char *argv[])
global_settings.setValue("start_page", "about:favourites");
}
+ global_settings.beginGroup("Client Identities");
+ global_identities.load(global_settings);
+ global_settings.endGroup();
+
MainWindow w(&app);
auto urls = cli_parser.positionalArguments();
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 4cd1919..9a56133 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -39,6 +39,9 @@ MainWindow::MainWindow(QApplication * app, QWidget *parent) :
ui->favourites_view->setModel(&favourites);
+ ui->clientcert_view->setModel(&global_identities);
+ ui->clientcert_view->expandAll();
+
this->ui->outline_window->setVisible(false);
this->ui->history_window->setVisible(false);
this->ui->clientcert_window->setVisible(false);
@@ -143,6 +146,10 @@ void MainWindow::saveSettings()
this->favourites.save(global_settings);
this->protocols.save(global_settings);
+ global_settings.beginGroup("Client Identities");
+ global_identities.save(global_settings);
+ global_settings.endGroup();
+
global_settings.beginGroup("Theme");
this->current_style.save(global_settings);
global_settings.endGroup();
diff --git a/src/newidentitiydialog.cpp b/src/newidentitiydialog.cpp
new file mode 100644
index 0000000..5419d74
--- /dev/null
+++ b/src/newidentitiydialog.cpp
@@ -0,0 +1,74 @@
+#include "newidentitiydialog.hpp"
+#include "ui_newidentitiydialog.h"
+
+#include "certificatehelper.hpp"
+#include "kristall.hpp"
+
+#include <QPushButton>
+#include <QDebug>
+
+NewIdentitiyDialog::NewIdentitiyDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::NewIdentitiyDialog)
+{
+ ui->setupUi(this);
+
+ ui->display_name->setText("Unnamed");
+ ui->common_name->setText("Unnamed");
+ ui->expiration_date->setDate(QDate::currentDate().addYears(1));
+ ui->expiration_date->setTime(QTime(12, 00));
+
+ ui->group->clear();
+ for(auto group_name : global_identities.groups())
+ {
+ ui->group->addItem(group_name);
+ }
+}
+
+NewIdentitiyDialog::~NewIdentitiyDialog()
+{
+ delete ui;
+}
+
+CryptoIdentity NewIdentitiyDialog::createIdentity() const
+{
+ auto id = CertificateHelper::createNewIdentity(
+ this->ui->common_name->text(),
+ this->ui->expiration_date->dateTime()
+ );
+ id.display_name = this->ui->display_name->text();
+ return id;
+}
+
+QString NewIdentitiyDialog::groupName() const
+{
+ return this->ui->group->currentText();
+}
+
+void NewIdentitiyDialog::updateUI()
+{
+ bool is_ok = true;
+
+ is_ok &= (not this->ui->group->currentText().isEmpty());
+ is_ok &= (not this->ui->common_name->text().isEmpty());
+ is_ok &= (not this->ui->display_name->text().isEmpty());
+ is_ok &= (this->ui->expiration_date->dateTime() > QDateTime::currentDateTime());
+
+ this->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(is_ok);
+}
+
+void NewIdentitiyDialog::on_group_editTextChanged(const QString &arg1)
+{
+ qDebug() << arg1;
+ this->updateUI();
+}
+
+void NewIdentitiyDialog::on_display_name_textChanged(const QString &arg1)
+{
+ this->updateUI();
+}
+
+void NewIdentitiyDialog::on_common_name_textChanged(const QString &arg1)
+{
+ this->updateUI();
+}
diff --git a/src/newidentitiydialog.hpp b/src/newidentitiydialog.hpp
new file mode 100644
index 0000000..bc8f90e
--- /dev/null
+++ b/src/newidentitiydialog.hpp
@@ -0,0 +1,40 @@
+#ifndef NEWIDENTITIYDIALOG_HPP
+#define NEWIDENTITIYDIALOG_HPP
+
+#include <QDialog>
+
+#include "cryptoidentity.hpp"
+
+namespace Ui {
+class NewIdentitiyDialog;
+}
+
+class NewIdentitiyDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit NewIdentitiyDialog(QWidget *parent = nullptr);
+ ~NewIdentitiyDialog();
+
+ //! Creates a new identity from the currently set
+ //! user settings.
+ CryptoIdentity createIdentity() const;
+
+ QString groupName() const;
+
+private slots:
+ void on_group_editTextChanged(const QString &arg1);
+
+ void on_display_name_textChanged(const QString &arg1);
+
+ void on_common_name_textChanged(const QString &arg1);
+
+private:
+ void updateUI();
+
+private:
+ Ui::NewIdentitiyDialog *ui;
+};
+
+#endif // NEWIDENTITIYDIALOG_HPP
diff --git a/src/newidentitiydialog.ui b/src/newidentitiydialog.ui
new file mode 100644
index 0000000..05c8155
--- /dev/null
+++ b/src/newidentitiydialog.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewIdentitiyDialog</class>
+ <widget class="QDialog" name="NewIdentitiyDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>328</width>
+ <height>191</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Display Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Expiration Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="display_name"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QDateTimeEdit" name="expiration_date"/>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="common_name"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Common Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Group</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="group">
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>NewIdentitiyDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>NewIdentitiyDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>