Prepare Async objects for Linphone tools to be used from GUI.

Fix AccountManager for missing sdk listening.
Fix login : custom parameters were missing.
This commit is contained in:
Julien Wadel 2023-11-08 09:58:52 +00:00
parent 053d0bcacc
commit 46e91b46a8
14 changed files with 280 additions and 14 deletions

View file

@ -21,7 +21,7 @@ set(APP_TARGETS ${LinphoneCxx_TARGET})
set(QT_DEFAULT_MAJOR_VERSION 6)
set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia)# Search Core at first for initialize Qt scripts for next find_packages.
set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia Test)# Search Core at first for initialize Qt scripts for next find_packages.
if (UNIX AND NOT APPLE)
list(APPEND QT_PACKAGES DBus)
endif()

View file

@ -33,7 +33,9 @@
#include "core/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/singleapplication/singleapplication.h"
#include "model/object/VariantObject.hpp"
#include "tool/Constants.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/Thread.hpp"
#include "tool/providers/ImageProvider.hpp"
@ -99,8 +101,12 @@ void App::initCppInterfaces() {
qmlRegisterSingletonType<Constants>(
"ConstantsCpp", 1, 0, "ConstantsCpp",
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Constants(engine); });
qmlRegisterSingletonType<Utils>("UtilsCpp", 1, 0, "UtilsCpp",
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Utils(engine); });
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable"));
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterUncreatableType<Account>(Constants::MainQmlUri, 1, 0, "Account", QLatin1String("Uncreatable"));

View file

@ -42,12 +42,19 @@ public:
static auto postModelAsync(Func &&callable) {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable);
}
template <typename Func>
static auto postModelSync(Func &&callable) {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable,
QThread::currentThread() != CoreModel::getInstance()->thread()
? Qt::BlockingQueuedConnection
: Qt::DirectConnection);
template <typename Func, typename... Args>
static auto postModelSync(Func &&callable, Args &&...args) {
if (QThread::currentThread() != CoreModel::getInstance()->thread()) {
bool end = false;
postModelAsync([&end, callable, args...]() mutable {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, args..., Qt::DirectConnection);
end = true;
});
while (!end)
qApp->processEvents();
} else {
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, Qt::DirectConnection);
}
}
void clean();

View file

@ -10,7 +10,11 @@ list(APPEND _LINPHONEAPP_SOURCES
model/logger/LoggerModel.cpp
model/logger/LoggerListener.cpp
model/object/VariantObject.cpp
model/setting/SettingsModel.cpp
model/tool/ToolModel.cpp
)
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)

View file

@ -65,6 +65,8 @@ bool AccountManager::login(QString username, QString password) {
.arg(Utils::coreStringToAppString(identity->asStringUriOnly()));
return false;
}
account->setParams(params);
core->addAuthInfo(factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
"", // User ID.
Utils::appStringToCoreString(password), // Password.
@ -73,6 +75,7 @@ bool AccountManager::login(QString username, QString password) {
identity->getDomain() // Domain.
));
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account);
mAccountModel->setSelf(mAccountModel);
connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this,
&AccountManager::onRegistrationStateChanged);
core->addAccount(account);

View file

@ -35,16 +35,15 @@
class CoreModel : public QObject {
Q_OBJECT
public:
CoreModel(const QString &configPath, QThread * parent);
CoreModel(const QString &configPath, QThread *parent);
~CoreModel();
static QSharedPointer<CoreModel> create(const QString &configPath, QThread * parent);
static QSharedPointer<CoreModel> create(const QString &configPath, QThread *parent);
static QSharedPointer<CoreModel> getInstance();
std::shared_ptr<linphone::Core> getCore();
void start();
void setConfigPath(QString path);
bool mEnd = false;
@ -53,14 +52,15 @@ public:
signals:
void loggerInitialized();
private:
QString mConfigPath;
QTimer *mIterateTimer = nullptr;
void setPathBeforeCreation();
void setPathsAfterCreation();
void setPathAfterStart();
static QSharedPointer<CoreModel> gCoreModel;
};

View file

@ -58,7 +58,7 @@ public:
protected:
std::shared_ptr<LinphoneClass> mMonitor;
std::shared_ptr<ListenerClass> mSelf;
std::shared_ptr<ListenerClass> mSelf = nullptr;
};
#endif

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "VariantObject.hpp"
#include <QDebug>
#include <QTest>
DEFINE_ABSTRACT_OBJECT(VariantObject)
VariantObject::VariantObject(QObject *parent) {
mustBeInMainThread(getClassName());
}
VariantObject::VariantObject(QVariant value, QObject *parent) : mValue(value) {
mustBeInMainThread(getClassName());
connect(this, &VariantObject::updateValue, this, &VariantObject::setValue);
mCoreObject = new VariantObject();
connect(mCoreObject, &VariantObject::valueChanged, this, &VariantObject::setValue);
connect(mCoreObject, &VariantObject::valueChanged, mCoreObject, &QObject::deleteLater);
}
VariantObject::~VariantObject() {
mustBeInMainThread("~" + getClassName());
}
QVariant VariantObject::getValue() const {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
return mValue;
}
void VariantObject::setValue(QVariant value) {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
if (value != mValue) {
mValue = value;
emit valueChanged(mValue);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VARIANT_OBJECT_H_
#define VARIANT_OBJECT_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <QVariant>
// Store the VariantObject on a propery and use value.
// Do not use direcly teh value like VariantObject.value : in this case if value change, VariantObject will be
// reevaluated.
class VariantObject : public QObject, public AbstractObject {
Q_OBJECT
public:
Q_PROPERTY(QVariant value READ getValue WRITE setValue NOTIFY valueChanged)
VariantObject(QObject *parent = nullptr);
VariantObject(QVariant value, QObject *parent = nullptr);
~VariantObject();
QVariant getValue() const;
void setValue(QVariant value);
VariantObject *mCoreObject; // Ensure to use DeleteLater() after updating value
signals:
void valueChanged(QVariant value);
void updateValue(QVariant value);
private:
QVariant mValue;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ToolModel.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include <QDebug>
#include <QTest>
DEFINE_ABSTRACT_OBJECT(ToolModel)
ToolModel::ToolModel(QObject *parent) {
}
ToolModel::~ToolModel() {
}
std::shared_ptr<linphone::Address> ToolModel::interpretUrl(const QString &address) {
bool usePrefix = false; // TODO
// CoreManager::getInstance()->getAccountSettingsModel()->getUseInternationalPrefixForCallsAndChats();
auto interpretedAddress =
CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(address), usePrefix);
if (!interpretedAddress) { // Try by removing scheme.
QStringList splitted = address.split(":");
if (splitted.size() > 0 && splitted[0] == "sip") {
splitted.removeFirst();
interpretedAddress = CoreModel::getInstance()->getCore()->interpretUrl(
Utils::appStringToCoreString(splitted.join(":")), usePrefix);
}
}
return interpretedAddress;
}
QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address> &address) {
QString displayName;
if (address) {
displayName = Utils::coreStringToAppString(address->getDisplayName());
// TODO
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
// cleanAddress->clean();
// QString qtAddress = Utils::coreStringToAppString(cleanAddress->asStringUriOnly());
// auto sipAddressEntry = getSipAddressEntry(qtAddress, cleanAddress);
// displayName = sipAddressEntry->displayNames.get();
}
return displayName;
}
QString ToolModel::getDisplayName(QString address) {
mustBeInLinphoneThread(QString(gClassName) + " : " + Q_FUNC_INFO);
QString displayName = getDisplayName(interpretUrl(address));
return displayName.isEmpty() ? address : displayName;
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOOL_MODEL_H_
#define TOOL_MODEL_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class ToolModel : public QObject, public AbstractObject {
Q_OBJECT
public:
ToolModel(QObject *parent = nullptr);
~ToolModel();
static std::shared_ptr<linphone::Address> interpretUrl(const QString &address);
static QString getDisplayName(const std::shared_ptr<const linphone::Address> &address);
static QString getDisplayName(QString address);
private:
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -20,6 +20,10 @@
#include "Utils.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
// =============================================================================
char *Utils::rstrstr(const char *a, const char *b) {
@ -34,3 +38,12 @@ char *Utils::rstrstr(const char *a, const char *b) {
return nullptr;
}
VariantObject *Utils::getDisplayName(const QString &address) {
VariantObject *data = new VariantObject(address); // Scope : GUI
App::postModelAsync([coreObject = data->mCoreObject, address]() mutable {
QString displayName = ToolModel::getDisplayName(address);
emit coreObject->valueChanged(displayName);
});
return data;
}

View file

@ -40,12 +40,16 @@
#endif // if defined(__GNUC__) && __GNUC__ >= 7
#endif // ifndef UTILS_NO_BREAK
class VariantObject;
class Utils : public QObject {
Q_OBJECT
public:
Utils(QObject *parent = nullptr) : QObject(parent) {
}
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
static inline QString coreStringToAppString(const std::string &str) {
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
else

View file

@ -2,6 +2,8 @@ import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
// Snippet
ListView{
@ -34,7 +36,10 @@ ListView{
}
}
Text{
text: $modelData.identityAddress
// Store the VariantObject and use value on this object. Do not use value in one line because of looping signals.
property var displayName: UtilsCpp.getDisplayName($modelData.identityAddress)
text: displayName.value
onTextChanged: console.log('[ProtoAccounts] Async account displayName: ' +$modelData.identityAddress + " => " +text)
}
Text{
text: $modelData.registrationState == LinphoneEnums.RegistrationState.Ok