diff --git a/Linphone/CMakeLists.txt b/Linphone/CMakeLists.txt index cbbe54884..18cbda4b6 100644 --- a/Linphone/CMakeLists.txt +++ b/Linphone/CMakeLists.txt @@ -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() diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index e37f0b8a4..3e5a1a029 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -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( "ConstantsCpp", 1, 0, "ConstantsCpp", [](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Constants(engine); }); + qmlRegisterSingletonType("UtilsCpp", 1, 0, "UtilsCpp", + [](QQmlEngine *engine, QJSEngine *) -> QObject * { return new Utils(engine); }); qmlRegisterType(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "VariantObject"); + qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "AccountProxy"); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "Account", QLatin1String("Uncreatable")); diff --git a/Linphone/core/App.hpp b/Linphone/core/App.hpp index 20c764150..da2256d63 100644 --- a/Linphone/core/App.hpp +++ b/Linphone/core/App.hpp @@ -42,12 +42,19 @@ public: static auto postModelAsync(Func &&callable) { QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable); } - template - static auto postModelSync(Func &&callable) { - QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable, - QThread::currentThread() != CoreModel::getInstance()->thread() - ? Qt::BlockingQueuedConnection - : Qt::DirectConnection); + template + 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(); diff --git a/Linphone/model/CMakeLists.txt b/Linphone/model/CMakeLists.txt index c404b7b8d..6cb66ac22 100644 --- a/Linphone/model/CMakeLists.txt +++ b/Linphone/model/CMakeLists.txt @@ -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) diff --git a/Linphone/model/account/AccountManager.cpp b/Linphone/model/account/AccountManager.cpp index 67900326b..0dc1c4080 100644 --- a/Linphone/model/account/AccountManager.cpp +++ b/Linphone/model/account/AccountManager.cpp @@ -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(account); + mAccountModel->setSelf(mAccountModel); connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this, &AccountManager::onRegistrationStateChanged); core->addAccount(account); diff --git a/Linphone/model/core/CoreModel.hpp b/Linphone/model/core/CoreModel.hpp index f67ffd7d8..4200c0909 100644 --- a/Linphone/model/core/CoreModel.hpp +++ b/Linphone/model/core/CoreModel.hpp @@ -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 create(const QString &configPath, QThread * parent); + static QSharedPointer create(const QString &configPath, QThread *parent); static QSharedPointer getInstance(); std::shared_ptr 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 gCoreModel; }; diff --git a/Linphone/model/listener/Listener.hpp b/Linphone/model/listener/Listener.hpp index bffd0d58f..49e8fd63b 100644 --- a/Linphone/model/listener/Listener.hpp +++ b/Linphone/model/listener/Listener.hpp @@ -58,7 +58,7 @@ public: protected: std::shared_ptr mMonitor; - std::shared_ptr mSelf; + std::shared_ptr mSelf = nullptr; }; #endif diff --git a/Linphone/model/object/VariantObject.cpp b/Linphone/model/object/VariantObject.cpp new file mode 100644 index 000000000..220f29610 --- /dev/null +++ b/Linphone/model/object/VariantObject.cpp @@ -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 . + */ + +#include "VariantObject.hpp" + +#include +#include + +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); + } +} diff --git a/Linphone/model/object/VariantObject.hpp b/Linphone/model/object/VariantObject.hpp new file mode 100644 index 000000000..f97fad501 --- /dev/null +++ b/Linphone/model/object/VariantObject.hpp @@ -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 . + */ + +#ifndef VARIANT_OBJECT_H_ +#define VARIANT_OBJECT_H_ + +#include "tool/AbstractObject.hpp" + +#include +#include + +// 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 diff --git a/Linphone/model/tool/ToolModel.cpp b/Linphone/model/tool/ToolModel.cpp new file mode 100644 index 000000000..82bdd1473 --- /dev/null +++ b/Linphone/model/tool/ToolModel.cpp @@ -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 . + */ + +#include "ToolModel.hpp" +#include "model/core/CoreModel.hpp" +#include "tool/Utils.hpp" + +#include +#include + +DEFINE_ABSTRACT_OBJECT(ToolModel) + +ToolModel::ToolModel(QObject *parent) { +} +ToolModel::~ToolModel() { +} +std::shared_ptr 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 &address) { + QString displayName; + if (address) { + displayName = Utils::coreStringToAppString(address->getDisplayName()); + // TODO + // std::shared_ptr 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; +} diff --git a/Linphone/model/tool/ToolModel.hpp b/Linphone/model/tool/ToolModel.hpp new file mode 100644 index 000000000..c6352e360 --- /dev/null +++ b/Linphone/model/tool/ToolModel.hpp @@ -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 . + */ + +#ifndef TOOL_MODEL_H_ +#define TOOL_MODEL_H_ + +#include "tool/AbstractObject.hpp" + +#include +#include + +class ToolModel : public QObject, public AbstractObject { + Q_OBJECT +public: + ToolModel(QObject *parent = nullptr); + ~ToolModel(); + + static std::shared_ptr interpretUrl(const QString &address); + + static QString getDisplayName(const std::shared_ptr &address); + static QString getDisplayName(QString address); + +private: + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index 0c65ed723..bb27bf381 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -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; +} diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index 33e3cec08..3cee921c7 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -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 diff --git a/Linphone/view/Prototype/AccountsPrototype.qml b/Linphone/view/Prototype/AccountsPrototype.qml index 5b569c1f9..96c705b11 100644 --- a/Linphone/view/Prototype/AccountsPrototype.qml +++ b/Linphone/view/Prototype/AccountsPrototype.qml @@ -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