aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlink2xt <link2xt@testrun.org>2020-11-05 22:03:37 +0300
committerlink2xt <link2xt@testrun.org>2020-11-05 23:08:08 +0300
commitfe89c7a4ff760564f3cdbcd8e27c04eadd9f79d8 (patch)
tree39d56b00509277afca8743adcf6051bd42121e99
parentdaa31b783ad1dead6cbed79b428792702612aa31 (diff)
downloadkdeltachat-fe89c7a4ff760564f3cdbcd8e27c04eadd9f79d8.tar.gz
kdeltachat-fe89c7a4ff760564f3cdbcd8e27c04eadd9f79d8.zip
Move accounts model from C++ to QML
C++ models are not well documented and it is easier to manage the model in QML. Now all QObjects are thin wrappers around Delta Chat core structures.
-rw-r--r--CMakeLists.txt2
-rw-r--r--accounts.cpp97
-rw-r--r--accounts.h31
-rw-r--r--accounts_model.cpp142
-rw-r--r--accounts_model.h51
-rw-r--r--main.cpp4
-rw-r--r--qml/AccountsPage.qml33
-rw-r--r--qml/main.qml14
8 files changed, 166 insertions, 208 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48ae24e..e380217 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,7 +31,7 @@ add_executable(kdeltachat
main.cpp
message.cpp
context.cpp
- accounts_model.cpp
+ accounts.cpp
chatlist.cpp
contact.cpp
chat.cpp
diff --git a/accounts.cpp b/accounts.cpp
new file mode 100644
index 0000000..f1486b5
--- /dev/null
+++ b/accounts.cpp
@@ -0,0 +1,97 @@
+#include <QFile>
+
+#include "accounts.h"
+
+DcAccounts::DcAccounts(QObject *parent)
+ : QObject(parent)
+{
+ m_accounts = dc_accounts_new("Qt", "./deltachat-data");
+}
+
+DcAccounts::~DcAccounts()
+{
+ dc_accounts_unref(m_accounts);
+}
+
+uint32_t
+DcAccounts::addAccount()
+{
+ return dc_accounts_add_account(m_accounts);
+}
+
+uint32_t
+DcAccounts::importAccount(QString tarfile)
+{
+ QByteArray utf8Text = tarfile.toUtf8();
+ return dc_accounts_import_account(m_accounts, utf8Text.constData());
+}
+
+uint32_t
+DcAccounts::migrateAccount(QString dbfile)
+{
+ QByteArray utf8Text = dbfile.toUtf8();
+ return dc_accounts_migrate_account(m_accounts, utf8Text.constData());
+}
+
+bool
+DcAccounts::removeAccount(uint32_t accountId)
+{
+ return dc_accounts_remove_account(m_accounts, accountId);
+}
+
+QVariantList
+DcAccounts::getAll()
+{
+ QVariantList result;
+ dc_array_t *accountIdArray = dc_accounts_get_all(m_accounts);
+ for (size_t i = 0; i < dc_array_get_cnt(accountIdArray); i++) {
+ result << dc_array_get_id(accountIdArray, i);
+ }
+ dc_array_unref(accountIdArray);
+ return result;
+}
+
+Context *
+DcAccounts::getAccount(uint32_t accountId)
+{
+ dc_context_t *context = dc_accounts_get_account(m_accounts, accountId);
+
+ return new Context(this, context);
+}
+
+Context *
+DcAccounts::getSelectedAccount()
+{
+ dc_context_t *context = dc_accounts_get_selected_account(m_accounts);
+
+ return new Context(this, context);
+}
+
+bool
+DcAccounts::selectAccount(uint32_t accountId) {
+ return dc_accounts_select_account(m_accounts, accountId);
+}
+
+void
+DcAccounts::startIo()
+{
+ dc_accounts_start_io(m_accounts);
+}
+
+void
+DcAccounts::stopIo()
+{
+ dc_accounts_stop_io(m_accounts);
+}
+
+void
+DcAccounts::maybeNetwork()
+{
+ dc_accounts_maybe_network(m_accounts);
+}
+
+DcAccountsEventEmitter *
+DcAccounts::getEventEmitter()
+{
+ return new DcAccountsEventEmitter{dc_accounts_get_event_emitter(m_accounts)};
+}
diff --git a/accounts.h b/accounts.h
new file mode 100644
index 0000000..20ede38
--- /dev/null
+++ b/accounts.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <QAbstractListModel>
+#include <deltachat.h>
+
+#include "eventemitter.h"
+#include "context.h"
+
+class DcAccounts : public QObject {
+ Q_OBJECT
+
+public:
+ explicit DcAccounts(QObject *parent = nullptr);
+ ~DcAccounts();
+
+ Q_INVOKABLE uint32_t addAccount();
+ Q_INVOKABLE uint32_t importAccount(QString tarfile);
+ Q_INVOKABLE uint32_t migrateAccount(QString dbfile);
+ Q_INVOKABLE bool removeAccount(uint32_t accountId);
+ Q_INVOKABLE QVariantList getAll();
+ Q_INVOKABLE Context *getAccount(uint32_t accountId);
+ Q_INVOKABLE Context *getSelectedAccount();
+ Q_INVOKABLE bool selectAccount(uint32_t accountId);
+ Q_INVOKABLE void startIo();
+ Q_INVOKABLE void stopIo();
+ Q_INVOKABLE void maybeNetwork();
+ Q_INVOKABLE DcAccountsEventEmitter *getEventEmitter();
+
+private:
+ dc_accounts_t *m_accounts{nullptr};
+};
diff --git a/accounts_model.cpp b/accounts_model.cpp
deleted file mode 100644
index f701245..0000000
--- a/accounts_model.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include <QFile>
-
-#include "accounts_model.h"
-
-AccountsModel::AccountsModel(QObject *parent)
- : QAbstractListModel(parent)
-{
- m_accounts = dc_accounts_new("Qt", "./deltachat-data");
-}
-
-AccountsModel::~AccountsModel()
-{
- dc_accounts_unref(m_accounts);
-}
-
-int
-AccountsModel::rowCount(const QModelIndex & parent) const
-{
- Q_UNUSED(parent);
- return accountCount();
-}
-
-QVariant AccountsModel::data(const QModelIndex & index, int role) const {
- QVariant result{};
-
- dc_array_t *accounts_arr = dc_accounts_get_all(m_accounts);
- if (index.row() >= 0 && index.row() < dc_array_get_cnt(accounts_arr)) {
- result = dc_array_get_id(accounts_arr, index.row());
- }
- dc_array_unref(accounts_arr);
-
- return result;
-}
-
-QHash<int, QByteArray>
-AccountsModel::roleNames() const {
- QHash<int, QByteArray> roles;
- roles[NumberRole] = "number";
- return roles;
-}
-
-size_t
-AccountsModel::accountCount() const {
- dc_array_t *accounts_arr = dc_accounts_get_all(m_accounts);
- size_t result = dc_array_get_cnt(accounts_arr);
- dc_array_unref(accounts_arr);
- return result;
-}
-
-uint32_t
-AccountsModel::selectedAccount() {
- return m_selectedAccount;
-}
-
-void
-AccountsModel::setSelectedAccount(uint32_t selectedAccount) {
- if (m_selectedAccount != selectedAccount) {
- if (dc_accounts_select_account (m_accounts, selectedAccount)) {
- m_selectedAccount = selectedAccount;
- emit selectedAccountChanged();
- }
- }
-}
-
-uint32_t
-AccountsModel::addAccount()
-{
- int row = accountCount();
- emit beginInsertRows(QModelIndex(), row, row);
- uint32_t res = dc_accounts_add_account(m_accounts);
- if (res != 0) {
- emit accountCountChanged();
- }
- emit endInsertRows();
- return res;
-}
-
-void
-AccountsModel::removeAccount(uint32_t accountId)
-{
- size_t index = -1;
-
- dc_array_t *accounts_arr = dc_accounts_get_all(m_accounts);
- int res = dc_array_search_id(accounts_arr, accountId, &index);
- dc_array_unref(accounts_arr);
-
- if (res) {
- emit beginRemoveRows(QModelIndex(), index, index);
- dc_accounts_remove_account(m_accounts, accountId);
- emit endRemoveRows();
- emit accountCountChanged();
- }
-}
-
-uint32_t
-AccountsModel::importAccount(const QString &filename) {
- int row = accountCount();
- QByteArray ba = QFile::encodeName(filename);
- uint32_t res = dc_accounts_import_account(m_accounts, ba.data());
- if (res) {
- // XXX: Looks like there is no way
- // to abort inserting rows,
- // so we begin and end at the same time to notify the UI about the added
- // row. https://forum.qt.io/topic/19194/how-to-abort-begininsertrows
- emit beginInsertRows(QModelIndex(), row, row);
- emit endInsertRows();
- }
- return res;
-}
-
-Context *
-AccountsModel::getSelectedAccount()
-{
- dc_context_t *context = dc_accounts_get_selected_account(m_accounts);
-
- return new Context(this, context);
-}
-
-void
-AccountsModel::startIo()
-{
- dc_accounts_start_io(m_accounts);
-}
-
-void
-AccountsModel::stopIo()
-{
- dc_accounts_stop_io(m_accounts);
-}
-
-void
-AccountsModel::maybeNetwork()
-{
- dc_accounts_maybe_network(m_accounts);
-}
-
-DcAccountsEventEmitter *
-AccountsModel::getEventEmitter()
-{
- std::cerr << "GETTING EVENT EMITTER" << std::endl;
- return new DcAccountsEventEmitter{dc_accounts_get_event_emitter(m_accounts)};
-}
diff --git a/accounts_model.h b/accounts_model.h
deleted file mode 100644
index 5541f7e..0000000
--- a/accounts_model.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include <QAbstractListModel>
-#include <deltachat.h>
-
-#include "eventemitter.h"
-#include "context.h"
-
-class AccountsModel : public QAbstractListModel {
- Q_OBJECT
- Q_PROPERTY(size_t accountCount READ accountCount NOTIFY accountCountChanged)
- Q_PROPERTY(uint32_t selectedAccount READ selectedAccount WRITE setSelectedAccount NOTIFY selectedAccountChanged)
-
-public:
- enum AccountRoles {
- NumberRole = Qt::UserRole + 1
- };
- explicit AccountsModel(QObject *parent = nullptr);
- ~AccountsModel();
-
- int rowCount(const QModelIndex & parent = QModelIndex()) const;
-
- QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
-
- size_t accountCount() const;
-
- uint32_t selectedAccount();
- void setSelectedAccount(uint32_t selectedAccount);
-
- Q_INVOKABLE uint32_t addAccount();
- Q_INVOKABLE void removeAccount(uint32_t accountId);
- Q_INVOKABLE uint32_t importAccount(const QString &filename);
- Q_INVOKABLE Context *getSelectedAccount();
-
- Q_INVOKABLE void startIo();
- Q_INVOKABLE void stopIo();
- Q_INVOKABLE void maybeNetwork();
-
- Q_INVOKABLE DcAccountsEventEmitter *getEventEmitter();
-
-signals:
- void accountCountChanged();
- void selectedAccountChanged();
-
-protected:
- QHash<int, QByteArray> roleNames() const;
-
-private:
- dc_accounts_t *m_accounts{nullptr};
- uint32_t m_selectedAccount{0};
-};
diff --git a/main.cpp b/main.cpp
index 6c9af57..f2687e0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,7 +2,7 @@
#include <QQmlApplicationEngine>
#include <QMetaType>
-#include "accounts_model.h"
+#include "accounts.h"
#include "message.h"
#include "chat.h"
#include "chatlist.h"
@@ -21,7 +21,7 @@ int main(int argc, char *argv[])
app.setOrganizationDomain("delta.chat");
// TODO: switch to using Qt 5.15 QML_ELEMENT macro
- if (qmlRegisterType<AccountsModel>("DeltaChat", 1, 0, "AccountsModel") == -1)
+ if (qmlRegisterType<DcAccounts>("DeltaChat", 1, 0, "DcAccounts") == -1)
{
QCoreApplication::exit(-1);
}
diff --git a/qml/AccountsPage.qml b/qml/AccountsPage.qml
index c9368d2..3278031 100644
--- a/qml/AccountsPage.qml
+++ b/qml/AccountsPage.qml
@@ -12,7 +12,10 @@ Kirigami.Page {
mainAction: Kirigami.Action {
iconName: "list-add-user"
text: "Add account"
- onTriggered: accountsModel.addAccount()
+ onTriggered: {
+ let accountId = dcAccounts.addAccount()
+ accountsModel.insert(accountsModel.count, { number: accountId })
+ }
}
contextualActions: [
@@ -31,7 +34,7 @@ Kirigami.Page {
if (url.startsWith("file://")) {
var filename = url.substring(7)
console.log("Importing " + filename)
- var accountId = accountsModel.importAccount (filename)
+ var accountId = dcAccounts.importAccount(filename)
if (accountId == 0) {
console.log("Import failed")
} else {
@@ -41,6 +44,23 @@ Kirigami.Page {
}
}
+ ListModel {
+ id: accountsModel
+ }
+
+ function updateAccounts() {
+ let accountsList = dcAccounts.getAll()
+
+ accountsModel.clear()
+ for (let i = 0; i < accountsList.length; i++) {
+ accountsModel.insert(i, { number: accountsList[i] })
+ }
+ }
+
+ Component.onCompleted: {
+ updateAccounts()
+ }
+
ListView {
id: accountsListView
anchors.fill: parent
@@ -63,8 +83,8 @@ Kirigami.Page {
while (pageStack.depth > 1) {
pageStack.pop()
}
- accountsModel.selectedAccount = model.number
- let context = accountsModel.getSelectedAccount()
+ dcAccounts.selectAccount(model.number)
+ let context = dcAccounts.getSelectedAccount()
if (context.isConfigured()) {
pageStack.push("qrc:/qml/ChatlistPage.qml", {context: context})
} else {
@@ -76,7 +96,10 @@ Kirigami.Page {
Button {
width: 100
text: "Delete"
- onClicked: accountsModel.removeAccount(model.number)
+ onClicked: {
+ dcAccounts.removeAccount(model.number)
+ accountsModel.remove(model.index)
+ }
}
}
}
diff --git a/qml/main.qml b/qml/main.qml
index cb116b3..546d553 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -19,9 +19,9 @@ Kirigami.ApplicationWindow {
text: "Start IO"
onCheckedChanged: {
if (checked) {
- accountsModel.startIo()
+ dcAccounts.startIo()
} else {
- accountsModel.stopIo()
+ dcAccouts.stopIo()
}
}
}
@@ -30,7 +30,7 @@ Kirigami.ApplicationWindow {
Kirigami.Action {
text: "Maybe network"
iconName: "view-refresh"
- onTriggered: accountsModel.maybeNetwork()
+ onTriggered: dcAccounts.maybeNetwork()
}
]
}
@@ -39,18 +39,18 @@ Kirigami.ApplicationWindow {
id: contextDrawer
}
- AccountsModel {
- id: accountsModel
+ DcAccounts {
+ id: dcAccounts
}
Component.onCompleted: {
console.log('starting')
- eventEmitter = accountsModel.getEventEmitter()
+ eventEmitter = dcAccounts.getEventEmitter()
eventEmitter.start();
}
onClosing: {
// Cancel all tasks that may block the termination of event loop.
- accountsModel.stopIo()
+ dcAccounts.stopIo()
}
}