Optimizations: Paging and asynchronous loaders.

This commit is contained in:
Julien Wadel 2024-10-10 17:33:58 +02:00
parent 8b3abc7f6d
commit e1b8befde4
57 changed files with 1171 additions and 872 deletions

View file

@ -39,6 +39,7 @@ list(APPEND _LINPHONEAPP_SOURCES
core/proxy/ListProxy.cpp
core/proxy/Proxy.cpp
core/proxy/SortFilterProxy.cpp
core/proxy/LimitProxy.cpp
core/variant/VariantList.cpp

View file

@ -30,10 +30,9 @@
DEFINE_ABSTRACT_OBJECT(AccountDeviceProxy)
DEFINE_GUI_OBJECT(AccountDeviceProxy)
AccountDeviceProxy::AccountDeviceProxy(QObject *parent) : SortFilterProxy(parent) {
AccountDeviceProxy::AccountDeviceProxy(QObject *parent) : LimitProxy(parent) {
mAccountDeviceList = AccountDeviceList::create();
setSourceModel(mAccountDeviceList.get());
sort(0); //, Qt::DescendingOrder);
setSourceModels(new SortFilterList(mAccountDeviceList.get(), Qt::DescendingOrder));
}
AccountDeviceProxy::~AccountDeviceProxy() {
@ -53,13 +52,10 @@ void AccountDeviceProxy::deleteDevice(AccountDeviceGui *device) {
mAccountDeviceList->deleteDevice(device);
}
bool AccountDeviceProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool AccountDeviceProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool AccountDeviceProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto deviceA = sourceModel()->data(left).value<AccountDeviceGui *>()->getCore();
auto deviceB = sourceModel()->data(right).value<AccountDeviceGui *>()->getCore();
return left.row() < right.row();
bool AccountDeviceProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
return sourceLeft.row() < sourceRight.row();
}

View file

@ -21,21 +21,22 @@
#ifndef ACCOUNT_DEVICE_PROXY_MODEL_H_
#define ACCOUNT_DEVICE_PROXY_MODEL_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "core/account/AccountDeviceGui.hpp"
#include "core/account/AccountGui.hpp"
#include "core/call/CallGui.hpp"
#include "tool/AbstractObject.hpp"
class AccountDeviceList;
class AccountDeviceGui;
class AccountDeviceProxy : public SortFilterProxy, public AbstractObject {
class AccountDeviceProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(AccountGui *account READ getAccount WRITE setAccount NOTIFY accountChanged)
public:
DECLARE_GUI_OBJECT
DECLARE_SORTFILTER_CLASS()
AccountDeviceProxy(QObject *parent = Q_NULLPTR);
~AccountDeviceProxy();
@ -44,9 +45,6 @@ public:
Q_INVOKABLE void deleteDevice(AccountDeviceGui *device);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals:
void lUpdate();
void accountChanged();

View file

@ -23,29 +23,18 @@
#include "AccountList.hpp"
#include "core/App.hpp"
AccountProxy::AccountProxy(QObject *parent) : SortFilterProxy(parent) {
setSourceModel(App::getInstance()->getAccountList().get());
sort(0);
AccountProxy::AccountProxy(QObject *parent) : LimitProxy(parent) {
setSourceModels(new SortFilterList(App::getInstance()->getAccountList().get(), Qt::AscendingOrder));
}
AccountProxy::~AccountProxy() {
setSourceModel(nullptr);
}
QString AccountProxy::getFilterText() const {
return mFilterText;
}
void AccountProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
AccountGui *AccountProxy::getDefaultAccount() {
if (!mDefaultAccount) mDefaultAccount = dynamic_cast<AccountList *>(sourceModel())->getDefaultAccountCore();
if (!mDefaultAccount)
mDefaultAccount = dynamic_cast<AccountList *>(dynamic_cast<SortFilterList *>(sourceModel())->sourceModel())
->getDefaultAccountCore();
return new AccountGui(mDefaultAccount);
}
@ -59,19 +48,19 @@ void AccountProxy::resetDefaultAccount() {
}
AccountGui *AccountProxy::findAccountByAddress(const QString &address) {
return dynamic_cast<AccountList *>(sourceModel())->findAccountByAddress(address);
return getListModel<AccountList>()->findAccountByAddress(address);
}
AccountGui *AccountProxy::firstAccount() {
return dynamic_cast<AccountList *>(sourceModel())->firstAccount();
return getListModel<AccountList>()->firstAccount();
}
bool AccountProxy::getHaveAccount() const {
return dynamic_cast<AccountList *>(sourceModel())->getHaveAccount();
return getListModel<AccountList>()->getHaveAccount();
}
void AccountProxy::setSourceModel(QAbstractItemModel *model) {
auto oldAccountList = dynamic_cast<AccountList *>(sourceModel());
auto oldAccountList = getListModel<AccountList>();
if (oldAccountList) {
disconnect(oldAccountList);
}
@ -87,25 +76,24 @@ void AccountProxy::setSourceModel(QAbstractItemModel *model) {
QSortFilterProxyModel::setSourceModel(model);
}
bool AccountProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
//------------------------------------------------------------------------------------------
bool AccountProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption);
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
auto model = sourceModel()->data(index);
auto account = model.value<AccountGui *>();
show = account->getCore()->getIdentityAddress().contains(search);
auto account = getItemAtSource<AccountList, AccountCore>(sourceRow);
show = account->getIdentityAddress().contains(search);
}
return show;
}
bool AccountProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
bool AccountProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<AccountList, AccountCore>(sourceLeft.row());
auto r = getItemAtSource<AccountList, AccountCore>(sourceRight.row());
return l.value<AccountGui *>()->getCore()->getIdentityAddress() <
r.value<AccountGui *>()->getCore()->getIdentityAddress();
return l->getIdentityAddress() < r->getIdentityAddress();
}

View file

@ -21,26 +21,25 @@
#ifndef ACCOUNT_PROXY_H_
#define ACCOUNT_PROXY_H_
#include "../proxy/LimitProxy.hpp"
#include "../proxy/SortFilterProxy.hpp"
#include "core/account/AccountGui.hpp"
#include "core/account/AccountList.hpp"
// =============================================================================
class AccountProxy : public SortFilterProxy {
class AccountProxy : public LimitProxy {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(AccountGui *defaultAccount READ getDefaultAccount WRITE setDefaultAccount NOTIFY defaultAccountChanged)
Q_PROPERTY(bool haveAccount READ getHaveAccount NOTIFY haveAccountChanged)
public:
DECLARE_SORTFILTER_CLASS()
AccountProxy(QObject *parent = Q_NULLPTR);
~AccountProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
AccountGui *getDefaultAccount(); // Get a new object from List or give the stored one.
void setDefaultAccount(AccountGui *account); // TODO
void resetDefaultAccount(); // Reset the default account to let UI build its new object if needed.
@ -52,16 +51,11 @@ public:
void setSourceModel(QAbstractItemModel *sourceModel) override;
signals:
void filterTextChanged();
void defaultAccountChanged();
void haveAccountChanged();
void initialized();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<AccountCore> mDefaultAccount; // When null, a new UI object is build from List
};

View file

@ -24,36 +24,24 @@
DEFINE_ABSTRACT_OBJECT(CarddavProxy)
CarddavProxy::CarddavProxy(QObject *parent) : SortFilterProxy(parent) {
CarddavProxy::CarddavProxy(QObject *parent) : LimitProxy(parent) {
mCarddavList = CarddavList::create();
setSourceModel(mCarddavList.get());
setSourceModels(new SortFilterList(mCarddavList.get(), Qt::AscendingOrder));
}
CarddavProxy::~CarddavProxy() {
setSourceModel(nullptr);
}
QString CarddavProxy::getFilterText() const {
return mFilterText;
}
void CarddavProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
void CarddavProxy::removeAllEntries() {
static_cast<CarddavList *>(sourceModel())->removeAllEntries();
}
void CarddavProxy::removeEntriesWithFilter() {
std::list<QSharedPointer<CarddavCore>> itemList(rowCount());
QList<QSharedPointer<CarddavCore>> itemList(rowCount());
for (auto i = rowCount() - 1; i >= 0; --i) {
auto item = getItemAt<CarddavList, CarddavCore>(i);
itemList.emplace_back(item);
auto item = getItemAt<SortFilterList, CarddavList, CarddavCore>(i);
itemList[i] = item;
}
for (auto item : itemList) {
mCarddavList->ListProxy::remove(item.get());
@ -61,13 +49,13 @@ void CarddavProxy::removeEntriesWithFilter() {
}
}
bool CarddavProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool CarddavProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool CarddavProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<CarddavList, CarddavCore>(left.row());
auto r = getItemAt<CarddavList, CarddavCore>(right.row());
bool CarddavProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<CarddavList, CarddavCore>(sourceLeft.row());
auto r = getItemAtSource<CarddavList, CarddavCore>(sourceRight.row());
return l->mDisplayName < r->mDisplayName;
}

View file

@ -21,37 +21,27 @@
#ifndef CARDDAV_PROXY_H_
#define CARDDAV_PROXY_H_
#include "../../proxy/SortFilterProxy.hpp"
#include "../../proxy/LimitProxy.hpp"
#include "CarddavGui.hpp"
#include "CarddavList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class CarddavProxy : public SortFilterProxy, public AbstractObject {
class CarddavProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
DECLARE_SORTFILTER_CLASS()
CarddavProxy(QObject *parent = Q_NULLPTR);
~CarddavProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView();
signals:
void filterTextChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<CarddavList> mCarddavList;
DECLARE_ABSTRACT_OBJECT

View file

@ -19,55 +19,42 @@
*/
#include "LdapProxy.hpp"
#include "LdapGui.hpp"
#include "LdapCore.hpp"
#include "LdapList.hpp"
DEFINE_ABSTRACT_OBJECT(LdapProxy)
LdapProxy::LdapProxy(QObject *parent) : SortFilterProxy(parent) {
LdapProxy::LdapProxy(QObject *parent) : LimitProxy(parent) {
mLdapList = LdapList::create();
setSourceModel(mLdapList.get());
setSourceModels(new SortFilterList(mLdapList.get(), Qt::AscendingOrder));
}
LdapProxy::~LdapProxy() {
setSourceModel(nullptr);
}
QString LdapProxy::getFilterText() const {
return mFilterText;
}
void LdapProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
void LdapProxy::removeAllEntries() {
static_cast<LdapList *>(sourceModel())->removeAllEntries();
getListModel<LdapList>()->removeAllEntries();
}
void LdapProxy::removeEntriesWithFilter() {
std::list<QSharedPointer<LdapCore>> itemList(rowCount());
QList<QSharedPointer<LdapCore>> itemList(rowCount());
for (auto i = rowCount() - 1; i >= 0; --i) {
auto item = getItemAt<LdapList, LdapCore>(i);
itemList.emplace_back(item);
auto item = getItemAt<SortFilterList, LdapList, LdapCore>(i);
itemList[i] = item;
}
for (auto item : itemList) {
mLdapList->ListProxy::remove(item.get());
if (item) item->remove();
}
}
bool LdapProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool LdapProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool LdapProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<LdapList, LdapCore>(left.row());
auto r = getItemAt<LdapList, LdapCore>(right.row());
bool LdapProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<LdapList, LdapCore>(sourceLeft.row());
auto r = getItemAtSource<LdapList, LdapCore>(sourceRight.row());
return l->mSipDomain < r->mSipDomain;
}

View file

@ -21,25 +21,21 @@
#ifndef LDAP_PROXY_H_
#define LDAP_PROXY_H_
#include "../../proxy/SortFilterProxy.hpp"
#include "LdapGui.hpp"
#include "../../proxy/LimitProxy.hpp"
#include "LdapList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class LdapProxy : public SortFilterProxy, public AbstractObject {
class LdapProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
DECLARE_SORTFILTER_CLASS()
LdapProxy(QObject *parent = Q_NULLPTR);
~LdapProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView();
@ -48,10 +44,6 @@ signals:
void filterTextChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<LdapList> mLdapList;
DECLARE_ABSTRACT_OBJECT

View file

@ -73,6 +73,18 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
mustBeInMainThread(getClassName());
resetData();
add(*callLogs);
/*
if (callLogs->size() > 0) {
int count = qMin(callLogs->size(), mMaxDisplayItems);
// QModelIndex firstIndex = index(0, 0);
beginInsertRows(QModelIndex(), 0, count - 1);
for (auto i : *callLogs)
mList << i.template objectCast<QObject>();
endInsertRows();
// auto lastIndex = index(count - 1, 0);
// emit dataChanged(firstIndex, lastIndex);
}*/
delete callLogs;
});
});
@ -109,3 +121,14 @@ QVariant CallHistoryList::data(const QModelIndex &index, int role) const {
}
return QVariant();
}
/*
void CallHistoryList::displayMore() {
int oldCount = qMin(mList.size(), mDisplayCount);
int newCount = qMin(mList.size(), mDisplayCount + mDisplayStep);
if (newCount != oldCount) {
mDisplayCount = newCount;
beginInsertRows(QModelIndex(), oldCount, mDisplayCount - 1);
endInsertRows();
}
}
*/

View file

@ -54,6 +54,7 @@ public:
// roles[Qt::DisplayRole + 2] = "date";
// return roles;
// }
//void displayMore();
signals:
void lUpdate();

View file

@ -24,41 +24,26 @@
DEFINE_ABSTRACT_OBJECT(CallHistoryProxy)
CallHistoryProxy::CallHistoryProxy(QObject *parent) : SortFilterProxy(parent) {
CallHistoryProxy::CallHistoryProxy(QObject *parent) : LimitProxy(parent) {
mHistoryList = CallHistoryList::create();
setSourceModel(mHistoryList.get());
// sort(0);
setSourceModels(new SortFilterList(mHistoryList.get(), Qt::DescendingOrder));
}
CallHistoryProxy::~CallHistoryProxy() {
setSourceModel(nullptr);
}
QString CallHistoryProxy::getFilterText() const {
return mFilterText;
}
void CallHistoryProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
void CallHistoryProxy::removeAllEntries() {
static_cast<CallHistoryList *>(sourceModel())->removeAllEntries();
mHistoryList->removeAllEntries();
}
void CallHistoryProxy::removeEntriesWithFilter() {
std::list<QSharedPointer<CallHistoryCore>> itemList(rowCount());
QList<QSharedPointer<CallHistoryCore>> itemList(rowCount());
for (auto i = rowCount() - 1; i >= 0; --i) {
auto item = getItemAt<CallHistoryList, CallHistoryCore>(i);
itemList.emplace_back(item);
auto item = getItemAt<SortFilterList, CallHistoryList, CallHistoryCore>(i);
itemList[i] = item;
}
for (auto item : itemList) {
mHistoryList->ListProxy::remove(item.get());
if (item) item->remove();
}
}
@ -66,8 +51,12 @@ void CallHistoryProxy::updateView() {
mHistoryList->lUpdate();
}
bool CallHistoryProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
//------------------------------------------------------------------------------------------
bool CallHistoryProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
auto sortProxy = dynamic_cast<SortFilterList *>(sourceModel());
if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption |
@ -76,13 +65,12 @@ bool CallHistoryProxy::filterAcceptsRow(int sourceRow, const QModelIndex &source
show =
callLog->mIsConference ? callLog->mDisplayName.contains(search) : callLog->mRemoteAddress.contains(search);
}
return show;
}
bool CallHistoryProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<CallHistoryList, CallHistoryCore>(left.row());
auto r = getItemAt<CallHistoryList, CallHistoryCore>(right.row());
bool CallHistoryProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<CallHistoryList, CallHistoryCore>(sourceLeft.row());
auto r = getItemAtSource<CallHistoryList, CallHistoryCore>(sourceRight.row());
return l->mDate < r->mDate;
}

View file

@ -21,37 +21,27 @@
#ifndef CALL_HISTORY_PROXY_H_
#define CALL_HISTORY_PROXY_H_
#include "../proxy/LimitProxy.hpp"
#include "../proxy/SortFilterProxy.hpp"
#include "CallHistoryGui.hpp"
#include "CallHistoryList.hpp"
#include "tool/AbstractObject.hpp"
#include <QSortFilterProxyModel>
// =============================================================================
class CallHistoryProxy : public SortFilterProxy, public AbstractObject {
class CallHistoryProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
DECLARE_SORTFILTER_CLASS()
CallHistoryProxy(QObject *parent = Q_NULLPTR);
~CallHistoryProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView();
signals:
void filterTextChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<CallHistoryList> mHistoryList;
DECLARE_ABSTRACT_OBJECT

View file

@ -25,34 +25,21 @@
DEFINE_ABSTRACT_OBJECT(CallProxy)
CallProxy::CallProxy(QObject *parent) : SortFilterProxy(parent) {
CallProxy::CallProxy(QObject *parent) : LimitProxy(parent) {
setSourceModel(App::getInstance()->getCallList().get());
sort(0);
}
CallProxy::~CallProxy() {
setSourceModel(nullptr);
}
QString CallProxy::getFilterText() const {
return mFilterText;
}
void CallProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
CallGui *CallProxy::getCurrentCall() {
if (!mCurrentCall) mCurrentCall = dynamic_cast<CallList *>(sourceModel())->getCurrentCall();
auto model = getListModel<CallList>();
if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall();
return mCurrentCall;
}
void CallProxy::setCurrentCall(CallGui *call) {
dynamic_cast<CallList *>(sourceModel())->setCurrentCall(call->mCore);
getListModel<CallList>()->setCurrentCall(call->mCore);
}
// Reset the default account to let UI build its new object if needed.
@ -62,11 +49,11 @@ void CallProxy::resetCurrentCall() {
}
bool CallProxy::getHaveCall() const {
return dynamic_cast<CallList *>(sourceModel())->getHaveCall();
return getListModel<CallList>()->getHaveCall();
}
void CallProxy::setSourceModel(QAbstractItemModel *model) {
auto oldCallList = dynamic_cast<CallList *>(sourceModel());
auto oldCallList = getListModel<CallList>();
if (oldCallList) {
disconnect(oldCallList);
}
@ -76,27 +63,26 @@ void CallProxy::setSourceModel(QAbstractItemModel *model) {
connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection);
connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll);
}
QSortFilterProxyModel::setSourceModel(model);
setSourceModels(new SortFilterList(model, Qt::AscendingOrder));
}
bool CallProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool CallProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption);
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
auto model = sourceModel()->data(index);
auto call = model.value<CallGui *>();
show = call->getCore()->getPeerAddress().contains(search);
auto call = qobject_cast<CallList *>(sourceModel())->getAt<CallCore>(sourceRow);
show = call->getPeerAddress().contains(search);
}
return show;
}
bool CallProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
bool CallProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row());
auto r = getItemAtSource<CallList, CallCore>(sourceRight.row());
return l.value<CallGui *>()->getCore()->getPeerAddress() < r.value<CallGui *>()->getCore()->getPeerAddress();
return l->getPeerAddress() < r->getPeerAddress();
}

View file

@ -21,26 +21,24 @@
#ifndef CALL_PROXY_H_
#define CALL_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "core/call/CallGui.hpp"
#include "core/call/CallList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class CallProxy : public SortFilterProxy, public AbstractObject {
class CallProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged)
public:
DECLARE_SORTFILTER_CLASS()
CallProxy(QObject *parent = Q_NULLPTR);
~CallProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
// Get a new object from List or give the stored one.
CallGui *getCurrentCall();
// TODO for manual setting. Changing the currentCall is automatically done by call->onStateChanged() on
@ -54,15 +52,10 @@ public:
signals:
void lMergeAll();
void filterTextChanged();
void currentCallChanged();
void haveCallChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List
DECLARE_ABSTRACT_OBJECT

View file

@ -25,15 +25,11 @@
DEFINE_ABSTRACT_OBJECT(ConferenceInfoProxy)
ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(parent) {
ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) {
mList = ConferenceInfoList::create();
setSourceModel(mList.get());
setSourceModels(new SortFilterList(mList.get()));
connect(
this, &ConferenceInfoProxy::searchTextChanged, this,
[this] {
invalidate();
updateCurrentDateIndex();
},
this, &ConferenceInfoProxy::filterTextChanged, this, [this] { updateCurrentDateIndex(); },
Qt::QueuedConnection);
connect(
mList.get(), &ConferenceInfoList::haveCurrentDateChanged, this,
@ -49,16 +45,6 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(pare
}
ConferenceInfoProxy::~ConferenceInfoProxy() {
setSourceModel(nullptr);
}
QString ConferenceInfoProxy::getSearchText() const {
return mSearchText;
}
void ConferenceInfoProxy::setSearchText(const QString &search) {
mSearchText = search;
emit searchTextChanged();
}
bool ConferenceInfoProxy::haveCurrentDate() const {
@ -77,15 +63,16 @@ void ConferenceInfoProxy::updateCurrentDateIndex() {
}
}
bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto ciCore = qobject_cast<ConferenceInfoList *>(sourceModel())->template getAt<ConferenceInfoCore>(sourceRow);
bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto list = qobject_cast<ConferenceInfoList *>(sourceModel());
auto ciCore = list->getAt<ConferenceInfoCore>(sourceRow);
if (ciCore) {
bool searchTextInSubject = false;
bool searchTextInParticipant = false;
if (ciCore->getSubject().contains(mSearchText, Qt::CaseInsensitive)) searchTextInSubject = true;
if (ciCore->getSubject().contains(mFilterText, Qt::CaseInsensitive)) searchTextInSubject = true;
for (auto &contact : ciCore->getParticipants()) {
auto infos = contact.toMap();
if (infos["displayName"].toString().contains(mSearchText, Qt::CaseInsensitive)) {
if (infos["displayName"].toString().contains(mFilterText, Qt::CaseInsensitive)) {
searchTextInParticipant = true;
break;
}
@ -99,7 +86,12 @@ bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou
return res;
} else return mFilterType == -1;
} else {
return !mList->haveCurrentDate() && mList->getCount() > 1 &&
mSearchText.isEmpty(); // if mlist count == 1 there is only the dummy row which we don't display alone
return !list->haveCurrentDate() && list->getCount() > 1 && mFilterText.isEmpty();
// if mlist count == 1 there is only the dummy row which we don't display alone
}
}
bool ConferenceInfoProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
const QModelIndex &sourceRight) const {
return true; // Not used
}

View file

@ -21,15 +21,14 @@
#ifndef CONFERENCE_INFO_PROXY_H_
#define CONFERENCE_INFO_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "tool/AbstractObject.hpp"
class ConferenceInfoList;
class ConferenceInfoProxy : public SortFilterProxy, public AbstractObject {
class ConferenceInfoProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged)
@ -37,32 +36,24 @@ public:
enum ConferenceInfoFiltering { None = 0, Future = 1 };
Q_ENUM(ConferenceInfoFiltering)
public:
DECLARE_SORTFILTER_CLASS()
ConferenceInfoProxy(QObject *parent = Q_NULLPTR);
~ConferenceInfoProxy();
QString getSearchText() const;
void setSearchText(const QString &search);
bool haveCurrentDate() const;
int getCurrentDateIndex() const;
void updateCurrentDateIndex();
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
// Do not use the sort feature. We cannot retrieve indexes with mapToSource because Qt return -1 for items that are
// not displayed. We need it to know where The workaround is to implement ourself the sort into the List.
// bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals:
void searchTextChanged();
void haveCurrentDateChanged();
void currentDateIndexChanged();
private:
QString mSearchText;
QSharedPointer<ConferenceInfoList> mList;
int mCurrentDateIndex = -1;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -44,7 +44,7 @@ void FPSCounter::recalculateFPS() {
int currentCount = _times.length();
_currentFPS = (currentCount + _cacheCount) / 2;
lDebug() << _currentFPS;
// lDebug() << _currentFPS;
if (currentCount != _cacheCount) fpsChanged(_currentFPS);
@ -58,11 +58,13 @@ int FPSCounter::fps() const {
void FPSCounter::paint(QPainter *painter) {
recalculateFPS();
// lDebug()<< __FUNCTION__;
/*
QBrush brush(Qt::yellow);
painter->setBrush(brush);
painter->setPen(Qt::NoPen);
painter->setRenderHint(QPainter::Antialiasing);
painter->drawRoundedRect(0, 0, boundingRect().width(), boundingRect().height(), 0, 0);
*/
update();
}

View file

@ -1,67 +0,0 @@
/*
* 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 "FriendInitialProxy.hpp"
#include "FriendCore.hpp"
#include "FriendGui.hpp"
DEFINE_ABSTRACT_OBJECT(FriendInitialProxy)
FriendInitialProxy::FriendInitialProxy(QObject *parent) : SortFilterProxy(parent) {
}
FriendInitialProxy::~FriendInitialProxy() {
setSourceModel(nullptr);
}
QString FriendInitialProxy::getFilterText() const {
return mFilterText;
}
void FriendInitialProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
bool FriendInitialProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
if (!show) {
QRegularExpression search(mFilterText, QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption);
auto friendData = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<FriendGui *>();
auto friendCore = friendData->getCore();
show = friendCore->getGivenName().indexOf(search) == 0 || friendCore->getFamilyName().indexOf(search) == 0;
}
return show;
}
// bool FriendInitialProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
// // auto l = getItemAt<MagicSearchProxy, FriendCore>(left.row());
// // auto r = getItemAt<MagicSearchProxy, FriendCore>(right.row());
// // return l->getName() < r->getName();
// }
QVariant FriendInitialProxy::data(const QModelIndex &index, int role) const {
return sourceModel()->data(mapToSource(index));
}

View file

@ -1,59 +0,0 @@
/*
* 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 FRIEND_INITIAL_PROXY_H_
#define FRIEND_INITIAL_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "core/search/MagicSearchList.hpp"
#include "core/search/MagicSearchProxy.hpp"
#include "tool/AbstractObject.hpp"
/**
* A proxy to filter the friends list with the first letter of the names
**/
// =============================================================================
class FriendInitialProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
FriendInitialProxy(QObject *parent = Q_NULLPTR);
~FriendInitialProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void filterTextChanged();
void sourceModelChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
QString mFilterText;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -30,17 +30,15 @@
DEFINE_ABSTRACT_OBJECT(ParticipantDeviceProxy)
DEFINE_GUI_OBJECT(ParticipantDeviceProxy)
ParticipantDeviceProxy::ParticipantDeviceProxy(QObject *parent) : SortFilterProxy(parent) {
ParticipantDeviceProxy::ParticipantDeviceProxy(QObject *parent) : LimitProxy(parent) {
mParticipants = ParticipantDeviceList::create();
connect(mParticipants.get(), &ParticipantDeviceList::countChanged, this, &ParticipantDeviceProxy::meChanged,
Qt::QueuedConnection);
setSourceModel(mParticipants.get());
sort(0); //, Qt::DescendingOrder);
setSourceModels(new SortFilterList(mParticipants.get(), Qt::AscendingOrder));
}
ParticipantDeviceProxy::~ParticipantDeviceProxy() {
setSourceModel(nullptr);
}
CallGui *ParticipantDeviceProxy::getCurrentCall() const {
@ -86,13 +84,14 @@ ParticipantDeviceGui *ParticipantDeviceProxy::getMe() const {
}
}
bool ParticipantDeviceProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool ParticipantDeviceProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool ParticipantDeviceProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto deviceA = sourceModel()->data(left).value<ParticipantDeviceGui *>()->getCore();
auto deviceB = sourceModel()->data(right).value<ParticipantDeviceGui *>()->getCore();
bool ParticipantDeviceProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
const QModelIndex &sourceRight) const {
auto l = getItemAtSource<ParticipantDeviceList, ParticipantDeviceCore>(sourceLeft.row());
auto r = getItemAtSource<ParticipantDeviceList, ParticipantDeviceCore>(sourceRight.row());
return deviceB->isMe() || (!deviceB->isMe() && left.row() < right.row());
return r->isMe() || (!r->isMe() && sourceLeft.row() < sourceRight.row());
}

View file

@ -21,7 +21,7 @@
#ifndef PARTICIPANT_DEVICE_PROXY_MODEL_H_
#define PARTICIPANT_DEVICE_PROXY_MODEL_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "core/call/CallGui.hpp"
#include "core/participant/ParticipantDeviceGui.hpp"
#include "tool/AbstractObject.hpp"
@ -29,13 +29,15 @@
class ParticipantDeviceList;
class ParticipantDeviceGui;
class ParticipantDeviceProxy : public SortFilterProxy, public AbstractObject {
class ParticipantDeviceProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(ParticipantDeviceGui *me READ getMe NOTIFY meChanged)
public:
DECLARE_GUI_OBJECT
DECLARE_SORTFILTER_CLASS()
ParticipantDeviceProxy(QObject *parent = Q_NULLPTR);
~ParticipantDeviceProxy();
@ -44,17 +46,12 @@ public:
ParticipantDeviceGui *getMe() const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals:
void lUpdate();
void currentCallChanged();
void meChanged();
private:
QString mSearchText;
CallGui *mCurrentCall = nullptr;
QSharedPointer<ParticipantDeviceList> mParticipants;
DECLARE_ABSTRACT_OBJECT

View file

@ -34,15 +34,14 @@
DEFINE_ABSTRACT_OBJECT(ParticipantProxy)
ParticipantProxy::ParticipantProxy(QObject *parent) : SortFilterProxy(parent) {
ParticipantProxy::ParticipantProxy(QObject *parent) : LimitProxy(parent) {
mParticipants = ParticipantList::create();
connect(this, &ParticipantProxy::chatRoomModelChanged, this, &ParticipantProxy::countChanged);
connect(this, &ParticipantProxy::conferenceModelChanged, this, &ParticipantProxy::countChanged);
setSourceModel(mParticipants.get());
setSourceModels(new SortFilterList(mParticipants.get(), Qt::AscendingOrder));
}
ParticipantProxy::~ParticipantProxy() {
setSourceModel(nullptr);
}
CallGui *ParticipantProxy::getCurrentCall() const {
@ -77,7 +76,7 @@ void ParticipantProxy::setCurrentCall(CallGui *call) {
}
bool ParticipantProxy::getShowMe() const {
return mShowMe;
return dynamic_cast<SortFilterList *>(sourceModel())->mShowMe;
}
// -----------------------------------------------------------------------------
@ -107,10 +106,11 @@ bool ParticipantProxy::getShowMe() const {
// }
void ParticipantProxy::setShowMe(const bool &show) {
if (mShowMe != show) {
mShowMe = show;
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mShowMe != show) {
list->mShowMe = show;
emit showMeChanged();
invalidate();
invalidateFilter();
}
}
@ -135,16 +135,15 @@ void ParticipantProxy::setParticipantAdminStatus(ParticipantCore *participant, b
// -----------------------------------------------------------------------------
bool ParticipantProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool ParticipantProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
if (mShowMe) return true;
else {
const ParticipantCore *a =
sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<ParticipantCore *>();
return !a->isMe();
auto participant = qobject_cast<ParticipantList *>(sourceModel())->getAt<ParticipantCore>(sourceRow);
return !participant->isMe();
}
}
bool ParticipantProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
bool ParticipantProxy::SortFilterList::lessThan(const QModelIndex &left, const QModelIndex &right) const {
const ParticipantCore *a = sourceModel()->data(left).value<ParticipantCore *>();
const ParticipantCore *b = sourceModel()->data(right).value<ParticipantCore *>();

View file

@ -21,7 +21,7 @@
#ifndef PARTICIPANT_PROXY_H_
#define PARTICIPANT_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "core/call/CallGui.hpp"
#include "tool/AbstractObject.hpp"
@ -36,22 +36,21 @@ class ConferenceInfoModel;
class QWindow;
class ParticipantProxy : public SortFilterProxy, public AbstractObject {
class ParticipantProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(bool showMe READ getShowMe WRITE setShowMe NOTIFY showMeChanged)
public:
DECLARE_SORTFILTER_CLASS(bool mShowMe;)
ParticipantProxy(QObject *parent = Q_NULLPTR);
~ParticipantProxy();
CallGui *getCurrentCall() const;
void setCurrentCall(CallGui *callGui);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool getShowMe() const;
void setShowMe(const bool &show);
@ -71,7 +70,6 @@ signals:
void currentCallChanged();
private:
bool mShowMe = true;
CallGui *mCurrentCall = nullptr;
QSharedPointer<ParticipantList> mParticipants;
DECLARE_ABSTRACT_OBJECT

View file

@ -24,23 +24,34 @@
DEFINE_ABSTRACT_OBJECT(PayloadTypeProxy)
PayloadTypeProxy::PayloadTypeProxy(QObject *parent) : SortFilterProxy(parent) {
PayloadTypeProxy::PayloadTypeProxy(QObject *parent) : LimitProxy(parent) {
mPayloadTypeList = PayloadTypeList::create();
setSourceModel(mPayloadTypeList.get());
setSourceModels(new SortFilterList(mPayloadTypeList.get(), Qt::AscendingOrder));
}
PayloadTypeProxy::~PayloadTypeProxy() {
setSourceModel(nullptr);
}
bool PayloadTypeProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto data = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<PayloadTypeGui *>();
return data->getCore()->getFamily() == mFamily;
PayloadTypeCore::Family PayloadTypeProxy::getFamily() const {
return dynamic_cast<SortFilterList *>(sourceModel())->mFamily;
}
bool PayloadTypeProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<PayloadTypeList, PayloadTypeCore>(left.row());
auto r = getItemAt<PayloadTypeList, PayloadTypeCore>(right.row());
void PayloadTypeProxy::setFamily(PayloadTypeCore::Family data) {
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mFamily != data) {
list->mFamily = data;
familyChanged();
}
}
bool PayloadTypeProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto payload = qobject_cast<PayloadTypeList *>(sourceModel())->getAt<PayloadTypeCore>(sourceRow);
return payload->getFamily() == mFamily;
}
bool PayloadTypeProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<PayloadTypeList, PayloadTypeCore>(sourceLeft.row());
auto r = getItemAtSource<PayloadTypeList, PayloadTypeCore>(sourceRight.row());
return l->getMimeType() < r->getMimeType();
}

View file

@ -21,27 +21,30 @@
#ifndef PAYLOAD_TYPE_PROXY_H_
#define PAYLOAD_TYPE_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "PayloadTypeGui.hpp"
#include "../proxy/LimitProxy.hpp"
#include "PayloadTypeList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class PayloadTypeProxy : public SortFilterProxy, public AbstractObject {
class PayloadTypeProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(PayloadTypeCore::Family family MEMBER mFamily)
Q_PROPERTY(PayloadTypeCore::Family family READ getFamily WRITE setFamily NOTIFY familyChanged)
public:
DECLARE_SORTFILTER_CLASS(PayloadTypeCore::Family mFamily;)
PayloadTypeProxy(QObject *parent = Q_NULLPTR);
~PayloadTypeProxy();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
PayloadTypeCore::Family getFamily() const;
void setFamily(PayloadTypeCore::Family data);
PayloadTypeCore::Family mFamily;
signals:
void familyChanged();
protected:
QSharedPointer<PayloadTypeList> mPayloadTypeList;
DECLARE_ABSTRACT_OBJECT

View file

@ -23,30 +23,16 @@
DEFINE_ABSTRACT_OBJECT(PhoneNumberProxy)
PhoneNumberProxy::PhoneNumberProxy(QObject *parent) : SortFilterProxy(parent) {
PhoneNumberProxy::PhoneNumberProxy(QObject *parent) : LimitProxy(parent) {
mPhoneNumberList = PhoneNumberList::create();
setSourceModel(mPhoneNumberList.get());
sort(0);
setSourceModels(new SortFilterList(mPhoneNumberList.get(), Qt::AscendingOrder));
}
PhoneNumberProxy::~PhoneNumberProxy() {
setSourceModel(nullptr);
}
QString PhoneNumberProxy::getFilterText() const {
return mFilterText;
}
void PhoneNumberProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
int PhoneNumberProxy::findIndexByCountryCallingCode(const QString &countryCallingCode) {
auto model = qobject_cast<PhoneNumberList *>(sourceModel());
auto model = getListModel<PhoneNumberList>();
if (!model) return -1;
if (countryCallingCode.isEmpty()) return -1;
@ -58,24 +44,22 @@ int PhoneNumberProxy::findIndexByCountryCallingCode(const QString &countryCallin
return proxyModelIndex.row();
}
bool PhoneNumberProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool PhoneNumberProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption);
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
auto model = sourceModel()->data(index);
auto phoneNumber = model.value<PhoneNumber *>();
auto phoneNumber = qobject_cast<PhoneNumberList *>(sourceModel())->getAt<PhoneNumber>(sourceRow);
show = phoneNumber->mCountry.contains(search) || phoneNumber->mCountryCallingCode.contains(search);
}
return show;
}
bool PhoneNumberProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
return l.value<PhoneNumber *>()->mCountry < r.value<PhoneNumber *>()->mCountry;
bool PhoneNumberProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<PhoneNumberList, PhoneNumber>(sourceLeft.row());
auto r = getItemAtSource<PhoneNumberList, PhoneNumber>(sourceRight.row());
return l->mCountry < r->mCountry;
}

View file

@ -21,34 +21,23 @@
#ifndef PHONE_NUMBER_PROXY_H_
#define PHONE_NUMBER_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "PhoneNumberList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class PhoneNumberProxy : public SortFilterProxy, public AbstractObject {
class PhoneNumberProxy : public LimitProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
DECLARE_SORTFILTER_CLASS()
PhoneNumberProxy(QObject *parent = Q_NULLPTR);
~PhoneNumberProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE int findIndexByCountryCallingCode(const QString &countryCallingCode);
signals:
void filterTextChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<PhoneNumberList> mPhoneNumberList;
private:

View file

@ -35,9 +35,9 @@ public:
virtual ~AbstractListProxy() {
clearData();
}
virtual int rowCount(const QModelIndex &index = QModelIndex()) const override {
return mList.count();
return getDisplayCount(mList.size());
}
virtual QHash<int, QByteArray> roleNames() const override {
@ -45,6 +45,7 @@ public:
roles[Qt::DisplayRole] = "$modelData";
return roles;
}
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
@ -59,37 +60,58 @@ public:
// Add functions
virtual void add(T item) {
int row = mList.count();
beginInsertRows(QModelIndex(), row, row);
mList << item;
endInsertRows();
auto lastIndex = index(mList.size() - 1, 0);
emit dataChanged(lastIndex, lastIndex);
}
virtual void add(QList<T> items) {
if (items.size() > 0) {
QModelIndex firstIndex = mList.size() > 0 ? index(mList.size() - 1, 0) : index(0, 0);
beginInsertRows(QModelIndex(), mList.size(), mList.size() + items.size() - 1);
mList << items;
int row = rowCount();
if (mMaxDisplayItems > 0 && row + 1 >= mMaxDisplayItems) {// New item is not in display range
mList << item;
}else{
beginInsertRows(QModelIndex(), row, row);
mList << item;
endInsertRows();
auto lastIndex = index(mList.size() - 1, 0);
emit dataChanged(firstIndex, lastIndex);
emit dataChanged(lastIndex, lastIndex);
}
}
virtual void add(QList<T> items) {
int count = items.size();
if (count > 0 ) {
int currentCount = rowCount();
int newCount = getDisplayCount(mList.size() + count);
if(newCount != currentCount){
beginInsertRows(QModelIndex(), currentCount, newCount - 1);
mList << items;
endInsertRows();
QModelIndex firstIndex = currentCount > 0 ? index(currentCount-1, 0) : index(0, 0);
auto lastIndex = index(newCount - 1, 0);
emit dataChanged(firstIndex, lastIndex);
}else
mList << items;
}
}
virtual void prepend(T item) {
int currentCount = rowCount();
beginInsertRows(QModelIndex(), 0, 0);
mList.prepend(item);
endInsertRows();
if(mMaxDisplayItems > 0 && currentCount + 1 >= mMaxDisplayItems){
setMaxDisplayItems(mMaxDisplayItems+1);
}
emit dataChanged(index(0), index(0));
}
virtual void prepend(QList<T> items) {
if (items.size() > 0) {
int count = items.size();
if (count > 0) {
int currentCount = rowCount();
int newCount = currentCount + count;
beginInsertRows(QModelIndex(), 0, items.size() - 1);
items << mList;
mList = items;
endInsertRows();
if(mMaxDisplayItems > 0 && newCount >= mMaxDisplayItems){
setMaxDisplayItems(newCount);
}
emit dataChanged(index(0), index(items.size() - 1));
}
}
@ -111,6 +133,7 @@ public:
virtual void clearData() override {
mList.clear();
setMaxDisplayItems(getInitialDisplayItems());
}
virtual void resetData() override {
@ -118,6 +141,16 @@ public:
clearData();
endResetModel();
}
/*
void displayMore() {
int oldCount = rowCount();
int newCount = getDisplayCount(oldCount + mList.size(), mMaxDisplayItems + mDisplayItemsStep);
if (newCount != oldCount) {
setMaxDisplayItems(newCount);
beginInsertRows(QModelIndex(), oldCount, newCount - 1);
endInsertRows();
}
}*/
protected:
QList<T> mList;

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2022-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 "LimitProxy.hpp"
LimitProxy::LimitProxy(QObject *parent) : QSortFilterProxyModel(parent) {
connect(this, &LimitProxy::rowsInserted, this, &LimitProxy::countChanged);
connect(this, &LimitProxy::rowsRemoved, this, &LimitProxy::countChanged);
}
/*
LimitProxy::LimitProxy(QAbstractItemModel *sortFilterProxy, QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(sortFilterProxy);
}*/
LimitProxy::~LimitProxy() {
// if (mDeleteSourceModel) deleteSourceModel();
}
bool LimitProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return mMaxDisplayItems == -1 || sourceRow < mMaxDisplayItems;
}
void LimitProxy::setSourceModels(SortFilterProxy *firstList) {
auto secondList = firstList->sourceModel();
connect(secondList, &QAbstractItemModel::rowsInserted, this, &LimitProxy::invalidateFilter);
connect(secondList, &QAbstractItemModel::rowsRemoved, this, &LimitProxy::invalidateFilter);
connect(firstList, &SortFilterProxy::filterTextChanged, this, &LimitProxy::filterTextChanged);
connect(firstList, &SortFilterProxy::filterTypeChanged, this, &LimitProxy::filterTypeChanged);
// Restore old values
auto oldModel = dynamic_cast<SortFilterProxy *>(sourceModel());
if (oldModel) {
firstList->setFilterType(oldModel->getFilterType());
firstList->setFilterText(oldModel->getFilterText());
}
QSortFilterProxyModel::setSourceModel(firstList);
}
/*
void LimitProxy::setSourceModels(SortFilterProxy *firstList, QAbstractItemModel *secondList) {
connect(secondList, &QAbstractItemModel::rowsInserted, this, &LimitProxy::invalidateFilter);
connect(secondList, &QAbstractItemModel::rowsRemoved, this, &LimitProxy::invalidateFilter);
connect(firstList, &SortFilterProxy::filterTextChanged, this, &LimitProxy::filterTextChanged);
setSourceModel(firstList);
}*/
QVariant LimitProxy::getAt(const int &atIndex) const {
auto modelIndex = index(atIndex, 0);
return sourceModel()->data(mapToSource(modelIndex), 0);
}
int LimitProxy::getCount() const {
return rowCount();
}
int LimitProxy::getInitialDisplayItems() const {
return mInitialDisplayItems;
}
void LimitProxy::setInitialDisplayItems(int initialItems) {
if (initialItems != 0 && mInitialDisplayItems != initialItems) {
mInitialDisplayItems = initialItems;
if (getMaxDisplayItems() <= mInitialDisplayItems) setMaxDisplayItems(initialItems);
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(initialItems);
emit initialDisplayItemsChanged();
}
}
int LimitProxy::getDisplayCount(int listCount, int maxCount) {
return maxCount >= 0 ? qMin(listCount, maxCount) : listCount;
}
int LimitProxy::getDisplayCount(int listCount) const {
return getDisplayCount(listCount, mMaxDisplayItems);
}
int LimitProxy::getMaxDisplayItems() const {
return mMaxDisplayItems;
}
void LimitProxy::setMaxDisplayItems(int maxItems) {
if (maxItems != 0 && mMaxDisplayItems != maxItems) {
auto model = sourceModel();
int modelCount = model ? model->rowCount() : 0;
int oldCount = getDisplayCount(modelCount);
mMaxDisplayItems = maxItems;
if (getInitialDisplayItems() > mMaxDisplayItems) setInitialDisplayItems(maxItems);
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(maxItems);
emit maxDisplayItemsChanged();
if (model && getDisplayCount(modelCount) != oldCount) {
invalidateFilter();
}
}
}
int LimitProxy::getDisplayItemsStep() const {
return mDisplayItemsStep;
}
void LimitProxy::setDisplayItemsStep(int step) {
if (step > 0 && mDisplayItemsStep != step) {
mDisplayItemsStep = step;
emit displayItemsStepChanged();
}
}
//--------------------------------------------------------------------------------------------------
QString LimitProxy::getFilterText() const {
return dynamic_cast<SortFilterProxy *>(sourceModel())->getFilterText();
}
void LimitProxy::setFilterText(const QString &filter) {
dynamic_cast<SortFilterProxy *>(sourceModel())->setFilterText(filter);
}
int LimitProxy::getFilterType() const {
return dynamic_cast<SortFilterProxy *>(sourceModel())->getFilterType();
}
void LimitProxy::setFilterType(int filter) {
dynamic_cast<SortFilterProxy *>(sourceModel())->setFilterType(filter);
}
//--------------------------------------------------------------------------------------------------
void LimitProxy::displayMore() {
int oldCount = rowCount();
auto model = sourceModel();
int newCount = getDisplayCount(model ? model->rowCount() : 0, mMaxDisplayItems + mDisplayItemsStep);
if (newCount != oldCount) {
setMaxDisplayItems(mMaxDisplayItems + mDisplayItemsStep);
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2022-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 LIMIT_PROXY_H_
#define LIMIT_PROXY_H_
#include "SortFilterProxy.hpp"
#include <QSortFilterProxyModel>
class LimitProxy : public QSortFilterProxyModel {
Q_OBJECT
public:
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(int initialDisplayItems READ getInitialDisplayItems WRITE setInitialDisplayItems NOTIFY
initialDisplayItemsChanged)
Q_PROPERTY(int maxDisplayItems READ getMaxDisplayItems WRITE setMaxDisplayItems NOTIFY maxDisplayItemsChanged)
Q_PROPERTY(int displayItemsStep READ getDisplayItemsStep WRITE setDisplayItemsStep NOTIFY displayItemsStepChanged)
// Propagation
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(int filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged)
LimitProxy(QObject *parent = nullptr);
virtual ~LimitProxy();
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
// Helper for setting the limit with sorted/filtered list
void setSourceModels(SortFilterProxy *firstList);
Q_INVOKABLE void displayMore();
Q_INVOKABLE QVariant getAt(const int &index) const;
virtual int getCount() const;
// Get the item following by what is shown from 2 lists
template <class A, class B, class C>
QSharedPointer<C> getItemAt(const int &atIndex) const {
return dynamic_cast<A *>(sourceModel())->template getItemAt<B, C>(atIndex);
}
template <class A>
inline A *getListModel() const {
auto model = dynamic_cast<SortFilterProxy *>(sourceModel());
if (model) return dynamic_cast<A *>(model->sourceModel());
else return nullptr;
}
static int getDisplayCount(int listCount, int maxCount);
int getDisplayCount(int listCount) const;
int getInitialDisplayItems() const;
void setInitialDisplayItems(int initialItems);
int getMaxDisplayItems() const;
void setMaxDisplayItems(int maxItems);
int getDisplayItemsStep() const;
void setDisplayItemsStep(int step);
//-------------------------------------------------------------
QString getFilterText() const;
void setFilterText(const QString &filter);
virtual int getFilterType() const;
virtual void setFilterType(int filterType);
//-------------------------------------------------------------
int mInitialDisplayItems = -1;
int mMaxDisplayItems = -1;
int mDisplayItemsStep = 5;
signals:
void countChanged();
void initialDisplayItemsChanged();
void maxDisplayItemsChanged();
void displayItemsStepChanged();
//-----------------------------------------------------------------
void filterTypeChanged(int filterType);
void filterTextChanged();
};
#endif

View file

@ -63,14 +63,21 @@ public:
template <class T>
void add(QList<QSharedPointer<T>> items) {
if (items.size() > 0) {
QModelIndex firstIndex = mList.size() > 0 ? index(mList.size() - 1, 0) : index(0, 0);
beginInsertRows(QModelIndex(), mList.size(), mList.size() + items.size() - 1);
for (auto i : items)
mList << i.template objectCast<QObject>();
endInsertRows();
auto lastIndex = index(mList.size() - 1, 0);
emit dataChanged(firstIndex, lastIndex);
int count = items.size();
if (count > 0 ) {
int currentCount = rowCount();
int newCount = getDisplayCount(mList.size() + count);
if(newCount != currentCount){
beginInsertRows(QModelIndex(), currentCount, newCount - 1);
for (auto i : items)
mList << i.template objectCast<QObject>();
endInsertRows();
QModelIndex firstIndex = currentCount > 0 ? index(currentCount-1, 0) : index(0, 0);
auto lastIndex = index(newCount - 1, 0);
emit dataChanged(firstIndex, lastIndex);
}else
for (auto i : items)
mList << i.template objectCast<QObject>();
}
}
@ -81,13 +88,7 @@ public:
template <class T>
void prepend(QList<QSharedPointer<T>> items) {
if (items.size() > 0) {
beginInsertRows(QModelIndex(), 0, items.size() - 1);
items << mList;
mList = items;
endInsertRows();
emit dataChanged(index(0), index(items.size() - 1));
}
AbstractListProxy<QSharedPointer<QObject>>::prepend(items);
}
virtual bool remove(QObject *itemToRemove) override {

View file

@ -24,13 +24,57 @@ Proxy::Proxy(QObject *parent) : QAbstractListModel(parent) {
connect(this, &Proxy::rowsInserted, this, &Proxy::countChanged);
connect(this, &Proxy::rowsRemoved, this, &Proxy::countChanged);
}
int Proxy::getCount() const {
return rowCount();
}
int Proxy::getDisplayCount(int listCount) const {
return mMaxDisplayItems >= 0 ? qMin(listCount, mMaxDisplayItems) : listCount;
}
bool Proxy::remove(QObject *itemToRemove) {
return false;
}
void Proxy::clearData() {
}
void Proxy::resetData() {
}
int Proxy::getInitialDisplayItems() const {
return mInitialDisplayItems;
}
void Proxy::setInitialDisplayItems(int initialItems) {
if (mInitialDisplayItems != initialItems) {
mInitialDisplayItems = initialItems;
if(getMaxDisplayItems() == -1)
setMaxDisplayItems(initialItems);
emit initialDisplayItemsChanged();
}
}
int Proxy::getMaxDisplayItems() const {
return mMaxDisplayItems;
}
void Proxy::setMaxDisplayItems(int maxItems) {
if (mMaxDisplayItems != maxItems) {
mMaxDisplayItems = maxItems;
if( getInitialDisplayItems() == -1)
setInitialDisplayItems(maxItems);
emit maxDisplayItemsChanged();
}
}
int Proxy::getDisplayItemsStep() const {
return mDisplayItemsStep;
}
void Proxy::setDisplayItemsStep(int step) {
if (mDisplayItemsStep != step) {
mDisplayItemsStep = step;
emit displayItemsStepChanged();
}
}

View file

@ -30,15 +30,35 @@ class Proxy : public QAbstractListModel {
public:
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(int length READ getCount NOTIFY countChanged)
Q_PROPERTY(int initialDisplayItems READ getInitialDisplayItems WRITE setInitialDisplayItems NOTIFY initialDisplayItemsChanged)
Q_PROPERTY(int maxDisplayItems READ getMaxDisplayItems WRITE setMaxDisplayItems NOTIFY maxDisplayItemsChanged)
Q_PROPERTY(int displayItemsStep READ getDisplayItemsStep WRITE setDisplayItemsStep NOTIFY displayItemsStepChanged)
Proxy(QObject *parent = nullptr);
Q_INVOKABLE virtual int getCount() const;
int getDisplayCount(int listCount) const;
Q_INVOKABLE virtual bool remove(QObject *itemToRemove);
Q_INVOKABLE virtual void clearData();
Q_INVOKABLE virtual void resetData();
int getInitialDisplayItems() const;
void setInitialDisplayItems(int initialItems);
int getMaxDisplayItems() const;
void setMaxDisplayItems(int maxItems);
int getDisplayItemsStep() const;
void setDisplayItemsStep(int step);
int mInitialDisplayItems = -1;
int mMaxDisplayItems = -1;
int mDisplayItemsStep = -1;
signals:
void countChanged();
void initialDisplayItemsChanged();
void maxDisplayItemsChanged();
void displayItemsStepChanged();
};
#endif

View file

@ -19,10 +19,15 @@
*/
#include "SortFilterProxy.hpp"
SortFilterProxy::SortFilterProxy(QObject *parent) : QSortFilterProxyModel(parent) {
#include "Proxy.hpp"
SortFilterProxy::SortFilterProxy(QAbstractItemModel *list) : QSortFilterProxyModel(list) {
connect(this, &SortFilterProxy::rowsInserted, this, &SortFilterProxy::countChanged);
connect(this, &SortFilterProxy::rowsRemoved, this, &SortFilterProxy::countChanged);
setSourceModel(list);
}
SortFilterProxy::SortFilterProxy(QAbstractItemModel *list, Qt::SortOrder order) : SortFilterProxy(list) {
sort(0, order);
}
SortFilterProxy::~SortFilterProxy() {
@ -37,12 +42,15 @@ void SortFilterProxy::deleteSourceModel() {
}
}
int SortFilterProxy::getCount() const {
return rowCount();
void SortFilterProxy::setSourceModel(QAbstractItemModel *model) {
auto listModel = dynamic_cast<Proxy *>(model);
auto oldSourceModel = sourceModel();
if (oldSourceModel) disconnect(oldSourceModel);
QSortFilterProxyModel::setSourceModel(model);
}
int SortFilterProxy::getFilterType() const {
return mFilterType;
int SortFilterProxy::getCount() const {
return rowCount();
}
QVariant SortFilterProxy::getAt(const int &atIndex) const {
@ -50,8 +58,8 @@ QVariant SortFilterProxy::getAt(const int &atIndex) const {
return sourceModel()->data(mapToSource(modelIndex), 0);
}
void SortFilterProxy::setSortOrder(const Qt::SortOrder &order) {
sort(0, order);
int SortFilterProxy::getFilterType() const {
return mFilterType;
}
void SortFilterProxy::setFilterType(int filterType) {
@ -62,6 +70,22 @@ void SortFilterProxy::setFilterType(int filterType) {
}
}
QString SortFilterProxy::getFilterText() const {
return mFilterText;
}
void SortFilterProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidateFilter();
emit filterTextChanged();
}
}
void SortFilterProxy::setSortOrder(const Qt::SortOrder &order) {
sort(0, order);
}
void SortFilterProxy::remove(int index, int count) {
QSortFilterProxyModel::removeRows(index, count);
}

View file

@ -22,37 +22,62 @@
#define SORT_FILTER_PROXY_H_
#include <QSortFilterProxyModel>
#define DECLARE_SORTFILTER_CLASS(...) \
class SortFilterList : public SortFilterProxy { \
public: \
SortFilterList(QAbstractItemModel *list) : SortFilterProxy(list) { \
} \
SortFilterList(QAbstractItemModel *list, Qt::SortOrder order) : SortFilterProxy(list, order) { \
} \
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; \
virtual bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override; \
__VA_ARGS__ \
};
class SortFilterProxy : public QSortFilterProxyModel {
Q_OBJECT
public:
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(int filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged)
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
SortFilterProxy(QObject *parent = nullptr);
SortFilterProxy(QAbstractItemModel *parent);
SortFilterProxy(QAbstractItemModel *parent, Qt::SortOrder order);
virtual ~SortFilterProxy();
virtual void deleteSourceModel();
virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
virtual int getCount() const;
virtual int getFilterType() const;
Q_INVOKABLE QVariant getAt(const int &index) const;
template <class A, class B>
QSharedPointer<B> getItemAt(const int &atIndex) const {
auto modelIndex = index(atIndex, 0);
return qobject_cast<A *>(sourceModel())->template getAt<B>(mapToSource(modelIndex).row());
}
template <class A, class B>
QSharedPointer<B> getItemAtSource(const int &atIndex) const {
return qobject_cast<A *>(sourceModel())->template getAt<B>(atIndex);
}
virtual int getFilterType() const;
virtual void setFilterType(int filterType);
Q_INVOKABLE void setSortOrder(const Qt::SortOrder &order);
virtual void setFilterType(int filterType);
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void remove(int index, int count = 1);
signals:
void countChanged();
void filterTypeChanged(int filterType);
void filterTextChanged();
protected:
int mFilterType = 0;
QString mFilterText;
bool mDeleteSourceModel = false;
};

View file

@ -24,18 +24,28 @@
#include "ScreenProxy.hpp"
// =============================================================================
ScreenProxy::ScreenProxy(QObject *parent) : SortFilterProxy(parent) {
setSourceModel(new ScreenList(this));
sort(0);
ScreenProxy::ScreenProxy(QObject *parent) : LimitProxy(parent) {
setSourceModels(new SortFilterList(new ScreenList(this), Qt::AscendingOrder));
}
ScreenList::Mode ScreenProxy::getMode() const {
return dynamic_cast<ScreenList *>(sourceModel())->getMode();
return getListModel<ScreenList>()->getMode();
}
void ScreenProxy::setMode(ScreenList::Mode data) {
dynamic_cast<ScreenList *>(sourceModel())->setMode(data);
getListModel<ScreenList>()->setMode(data);
}
void ScreenProxy::update() {
dynamic_cast<ScreenList *>(sourceModel())->update();
getListModel<ScreenList>()->update();
}
bool ScreenProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool ScreenProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = qobject_cast<ScreenList *>(sourceModel())->getAt(sourceLeft.row());
auto r = qobject_cast<ScreenList *>(sourceModel())->getAt(sourceRight.row());
return l["screenIndex"].toInt() < r["screenIndex"].toInt();
}

View file

@ -22,17 +22,18 @@
#define SCREEN_PROXY_H_
#include "ScreenList.hpp"
#include "core/proxy/SortFilterProxy.hpp"
#include "core/proxy/LimitProxy.hpp"
// =============================================================================
class QWindow;
class ScreenProxy : public SortFilterProxy {
class ScreenProxy : public LimitProxy {
class ScreenModelFilter;
Q_OBJECT
Q_PROPERTY(ScreenList::Mode mode READ getMode WRITE setMode NOTIFY modeChanged)
public:
DECLARE_SORTFILTER_CLASS()
ScreenProxy(QObject *parent = Q_NULLPTR);
ScreenList::Mode getMode() const;

View file

@ -22,7 +22,7 @@
#include "MagicSearchList.hpp"
#include "core/friend/FriendGui.hpp"
MagicSearchProxy::MagicSearchProxy(QObject *parent) : SortFilterProxy(parent) {
MagicSearchProxy::MagicSearchProxy(QObject *parent) : LimitProxy(parent) {
mSourceFlags = (int)LinphoneEnums::MagicSearchSource::Friends | (int)LinphoneEnums::MagicSearchSource::LdapServers;
mAggregationFlag = LinphoneEnums::MagicSearchAggregation::Friend;
setList(MagicSearchList::create());
@ -41,6 +41,7 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
if (mList) {
disconnect(mList.get());
}
auto oldModel = dynamic_cast<SortFilterList *>(sourceModel());
mList = newList;
if (mList) {
connect(mList.get(), &MagicSearchList::sourceFlagsChanged, this, &MagicSearchProxy::sourceFlagsChanged,
@ -50,8 +51,11 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
connect(
mList.get(), &MagicSearchList::friendCreated, this,
[this](int index) {
auto proxyIndex = mapFromSource(sourceModel()->index(index, 0));
emit friendCreated(proxyIndex.row());
auto proxyIndex =
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(mList->index(index, 0)).row();
// auto proxyIndex = mapFromSource(sourceModel()->index(index, 0)); // OLD (keep for checking new proxy
// behavior)
emit friendCreated(proxyIndex);
},
Qt::QueuedConnection);
connect(
@ -63,11 +67,13 @@ void MagicSearchProxy::setList(QSharedPointer<MagicSearchList> newList) {
},
Qt::QueuedConnection);
}
setSourceModel(mList.get());
auto sortFilterList = new SortFilterList(mList.get(), Qt::AscendingOrder);
if (oldModel) sortFilterList->mShowFavoritesOnly = oldModel->mShowFavoritesOnly;
setSourceModels(sortFilterList);
}
int MagicSearchProxy::findFriendIndexByAddress(const QString &address) {
auto magicSearchList = qobject_cast<MagicSearchList *>(sourceModel());
auto magicSearchList = getListModel<MagicSearchList>();
if (magicSearchList)
return mapFromSource(magicSearchList->index(magicSearchList->findFriendIndexByAddress(address), 0)).row();
else return -1;
@ -96,12 +102,14 @@ void MagicSearchProxy::setSourceFlags(int flags) {
}
bool MagicSearchProxy::showFavoritesOnly() const {
return mShowFavoritesOnly;
return dynamic_cast<SortFilterList *>(sourceModel())->mShowFavoritesOnly;
}
void MagicSearchProxy::setShowFavoritesOnly(bool show) {
if (mShowFavoritesOnly != show) {
mShowFavoritesOnly = show;
auto list = dynamic_cast<SortFilterList *>(sourceModel());
if (list->mShowFavoritesOnly != show) {
list->mShowFavoritesOnly = show;
list->invalidate();
emit showFavoriteOnlyChanged();
}
}
@ -122,27 +130,21 @@ void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation
}
}
bool MagicSearchProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
auto model = sourceModel()->data(index);
auto friendGui = model.value<FriendGui *>();
auto friendCore = friendGui->getCore();
bool MagicSearchProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto friendCore = getItemAtSource<MagicSearchList, FriendCore>(sourceRow);
if (friendCore) {
return !mShowFavoritesOnly || friendCore->getStarred();
}
return false;
}
bool MagicSearchProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
bool MagicSearchProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<MagicSearchList, FriendCore>(sourceLeft.row());
auto r = getItemAtSource<MagicSearchList, FriendCore>(sourceRight.row());
auto lIsFriend = l.value<FriendGui *>();
auto rIsFriend = r.value<FriendGui *>();
if (lIsFriend && rIsFriend) {
auto lName = lIsFriend->getCore()->getDisplayName().toLower();
auto rName = rIsFriend->getCore()->getDisplayName().toLower();
if (l && r) {
auto lName = l->getDisplayName().toLower();
auto rName = r->getDisplayName().toLower();
return lName < rName;
}
return true;

View file

@ -21,13 +21,13 @@
#ifndef MAGIC_SEARCH_PROXY_H_
#define MAGIC_SEARCH_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
#include "core/search/MagicSearchList.hpp"
#include "tool/LinphoneEnums.hpp"
// =============================================================================
class MagicSearchProxy : public SortFilterProxy {
class MagicSearchProxy : public LimitProxy {
Q_OBJECT
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
@ -38,6 +38,7 @@ class MagicSearchProxy : public SortFilterProxy {
Q_PROPERTY(MagicSearchProxy *parentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
public:
DECLARE_SORTFILTER_CLASS(bool mShowFavoritesOnly = false;)
MagicSearchProxy(QObject *parent = Q_NULLPTR);
~MagicSearchProxy();
@ -72,11 +73,8 @@ signals:
protected:
QString mSearchText;
int mSourceFlags;
bool mShowFavoritesOnly = false;
LinphoneEnums::MagicSearchAggregation mAggregationFlag;
QSharedPointer<MagicSearchList> mList;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
};
#endif

View file

@ -80,6 +80,7 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(DisableBroadcastFeature, settingsModel)
INIT_CORE_MEMBER(HideSettings, settingsModel)
INIT_CORE_MEMBER(HideAccountSettings, settingsModel)
INIT_CORE_MEMBER(HideFps, settingsModel)
INIT_CORE_MEMBER(DisableCallRecordings, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
@ -311,6 +312,8 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
HideSettings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
hideAccountSettings, HideAccountSettings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
hideFps, HideFps)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCallRecordings, DisableCallRecordings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,

View file

@ -148,6 +148,7 @@ public:
DECLARE_CORE_GETSET_MEMBER(bool, disableBroadcastFeature, DisableBroadcastFeature)
DECLARE_CORE_GETSET_MEMBER(bool, hideSettings, HideSettings)
DECLARE_CORE_GETSET_MEMBER(bool, hideAccountSettings, HideAccountSettings)
DECLARE_CORE_GETSET_MEMBER(bool, hideFps, HideFps)
DECLARE_CORE_GETSET_MEMBER(bool, disableCallRecordings, DisableCallRecordings)
DECLARE_CORE_GETSET_MEMBER(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
DECLARE_CORE_GETSET_MEMBER(bool, assistantDisableQrCode, AssistantDisableQrCode)

View file

@ -24,19 +24,20 @@
// -----------------------------------------------------------------------------
TimeZoneProxy::TimeZoneProxy(QObject *parent) : SortFilterProxy(parent) {
mDeleteSourceModel = true;
TimeZoneProxy::TimeZoneProxy(QObject *parent) : LimitProxy(parent) {
mList = TimeZoneList::create();
setSourceModel(mList.get());
sort(0);
setSourceModels(new SortFilterList(mList.get(), Qt::AscendingOrder));
}
// -----------------------------------------------------------------------------
bool TimeZoneProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto test = sourceModel()->data(left);
auto l = getItemAt<TimeZoneList, TimeZoneModel>(left.row());
auto r = getItemAt<TimeZoneList, TimeZoneModel>(right.row());
bool TimeZoneProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool TimeZoneProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<TimeZoneList, TimeZoneModel>(sourceLeft.row());
auto r = getItemAtSource<TimeZoneList, TimeZoneModel>(sourceRight.row());
if (!l || !r) return true;
auto timeA = l->getStandardTimeOffset() / 3600;
auto timeB = r->getStandardTimeOffset() / 3600;
@ -47,5 +48,5 @@ bool TimeZoneProxy::lessThan(const QModelIndex &left, const QModelIndex &right)
int TimeZoneProxy::getIndex(TimeZoneModel *model) const {
int index = 0;
index = mList->get(model ? model->getTimeZone() : QTimeZone::systemTimeZone());
return mapFromSource(mList->index(index, 0)).row();
return dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(mList->index(index, 0)).row();
}

View file

@ -21,16 +21,18 @@
#ifndef TIME_ZONE_PROXY_MODEL_H_
#define TIME_ZONE_PROXY_MODEL_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../proxy/LimitProxy.hpp"
// =============================================================================
class TimeZoneModel;
class TimeZoneList;
class TimeZoneProxy : public SortFilterProxy {
class TimeZoneProxy : public LimitProxy {
Q_OBJECT
public:
DECLARE_SORTFILTER_CLASS()
TimeZoneProxy(QObject *parent = Q_NULLPTR);
Q_PROPERTY(int defaultIndex READ getIndex CONSTANT)
@ -38,7 +40,6 @@ public:
protected:
QSharedPointer<TimeZoneList> mList;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
#endif

View file

@ -38,13 +38,15 @@ void cleanStream() {
}
int main(int argc, char *argv[]) {
#if defined _WIN32
// log in console only if launched from console
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen_s(&gStream, "CONOUT$", "w", stdout);
freopen_s(&gStream, "CONOUT$", "w", stderr);
}
#endif
/*
#if defined _WIN32
// log in console only if launched from console
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen_s(&gStream, "CONOUT$", "w", stdout);
freopen_s(&gStream, "CONOUT$", "w", stderr);
}
#endif
*/
// Useful to share camera on Fullscreen (other context) or multiscreens
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Disable QML cache. Avoid malformed cache.

View file

@ -568,6 +568,7 @@ void SettingsModel::notifyConfigReady(){
DEFINE_NOTIFY_CONFIG_READY(disableMeetingsFeature, DisableMeetingsFeature)
DEFINE_NOTIFY_CONFIG_READY(hideSettings,HideSettings)
DEFINE_NOTIFY_CONFIG_READY(hideAccountSettings, HideAccountSettings)
DEFINE_NOTIFY_CONFIG_READY(hideFps, HideFps)
DEFINE_NOTIFY_CONFIG_READY(disableCallRecordings, DisableCallRecordings)
DEFINE_NOTIFY_CONFIG_READY(assistantHideCreateAccount, AssistantHideCreateAccount)
DEFINE_NOTIFY_CONFIG_READY(assistantDisableQrCode, AssistantDisableQrCode)
@ -596,6 +597,7 @@ DEFINE_GETSET_CONFIG(SettingsModel,
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, hideSettings, HideSettings, "hide_settings", false)
DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, hideAccountSettings, HideAccountSettings, "hide_account_settings", false)
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, hideFps, HideFps, "hide_fps", true )
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,

View file

@ -139,6 +139,7 @@ public:
DECLARE_GETSET(bool, disableBroadcastFeature, DisableBroadcastFeature)
DECLARE_GETSET(bool, hideSettings, HideSettings)
DECLARE_GETSET(bool, hideAccountSettings, HideAccountSettings)
DECLARE_GETSET(bool, hideFps, HideFps)
DECLARE_GETSET(bool, disableCallRecordings, DisableCallRecordings)
DECLARE_GETSET(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
DECLARE_GETSET(bool, assistantDisableQrCode, AssistantDisableQrCode)

View file

@ -3,7 +3,7 @@ import QtQuick.Controls.Basic as Control
import QtQuick.Effects
import QtQuick.Layouts
import Linphone
Control.Button {
id: mainItem
property int capitalization
@ -26,7 +26,8 @@ Control.Button {
// rightPadding: 20 * DefaultStyle.dp
// topPadding: 11 * DefaultStyle.dp
// bottomPadding: 11 * DefaultStyle.dp
implicitHeight: contentItem.implicitHeight + bottomPadding + topPadding
implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
MouseArea {
id: mouseArea
anchors.fill: parent
@ -34,42 +35,48 @@ Control.Button {
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
}
background: Item {
Rectangle {
anchors.fill: parent
id: buttonBackground
color: mainItem.enabled
? inversedColors
? mainItem.pressed || mainItem.shadowEnabled
? DefaultStyle.grey_100
: mainItem.borderColor
: mainItem.pressed || mainItem.shadowEnabled
? mainItem.pressedColor
: mainItem.color
: mainItem.disabledColor
radius: mainItem.radius
border.color: inversedColors ? mainItem.color : mainItem.borderColor
MouseArea {
background: Loader{
asynchronous: true
anchors.fill: parent
sourceComponent:
Item {
Rectangle {
id: buttonBackground
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
color: mainItem.enabled
? inversedColors
? mainItem.pressed || mainItem.shadowEnabled
? DefaultStyle.grey_100
: mainItem.borderColor
: mainItem.pressed || mainItem.shadowEnabled
? mainItem.pressedColor
: mainItem.color
: mainItem.disabledColor
radius: mainItem.radius
border.color: inversedColors ? mainItem.color : mainItem.borderColor
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
MultiEffect {
enabled: mainItem.shadowEnabled
anchors.fill: buttonBackground
source: buttonBackground
visible: mainItem.shadowEnabled
// Crash : https://bugreports.qt.io/browse/QTBUG-124730
shadowEnabled: true //mainItem.shadowEnabled
shadowColor: DefaultStyle.grey_1000
shadowBlur: 0.1
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
}
}
MultiEffect {
enabled: mainItem.shadowEnabled
anchors.fill: buttonBackground
source: buttonBackground
visible: mainItem.shadowEnabled
// Crash : https://bugreports.qt.io/browse/QTBUG-124730
shadowEnabled: true //mainItem.shadowEnabled
shadowColor: DefaultStyle.grey_1000
shadowBlur: 0.1
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
}
}
component ButtonText: Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
@ -90,7 +97,7 @@ Control.Button {
bold: mainItem.font.bold
}
}
component ButtonImage: EffectImage {
// Layout.fillWidth: true
// Layout.fillHeight: true
@ -100,7 +107,70 @@ Control.Button {
colorizationColor: mainItem.contentImageColor
shadowEnabled: mainItem.shadowEnabled
}
contentItem: Control.StackView{
id: stacklayout
width: mainItem.width
// TODO Qt bug : contentItem is never changed....
implicitHeight: contentItem && contentItem.implicitHeight? contentItem.implicitHeight : 0
implicitWidth: contentItem && contentItem.implicitWidth? contentItem.implicitWidth: 0
function updateComponent(){
var item
var component = mainItem.text.length != 0 && mainItem.icon.source.toString().length != 0
? imageTextComponent
: mainItem.text.length != 0
? textComponent
: mainItem.icon.source.toString().length != 0
? imageComponent
: emptyComponent
if( stacklayout.depth == 0)
item = stacklayout.push(component, Control.StackView.Immediate)
else if( component != stacklayout.get(0))
item = stacklayout.replace(component, Control.StackView.Immediate)
if(item){// Workaround for Qt bug : set from the item and not from the contentItem
implicitHeight = item.implicitHeight
implicitWidth = item.implicitWidth
}
}
Component.onCompleted: {
updateComponent()
}
Connections{
target: mainItem
function onTextChanged(){stacklayout.updateComponent()}
function onIconChanged(){stacklayout.updateComponent()}
}
Component{
id: imageTextComponent
RowLayout {
spacing: mainItem.spacing
ButtonImage{
Layout.preferredWidth: mainItem.icon.width
Layout.preferredHeight: mainItem.icon.height
}
ButtonText{}
}
}
Component{
id: textComponent
ButtonText {}
}
Component{
id: imageComponent
ButtonImage{}
}
Component{
id: emptyComponent
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
/*
contentItem: StackLayout {
id: stacklayout
currentIndex: mainItem.text.length != 0 && mainItem.icon.source.toString().length != 0
@ -110,7 +180,7 @@ Control.Button {
: mainItem.icon.source.toString().length != 0
? 2
: 3
width: mainItem.width
RowLayout {
spacing: mainItem.spacing
@ -126,5 +196,5 @@ Control.Button {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}*/
}

View file

@ -10,176 +10,199 @@ import SettingsCpp
// Fill contact, account or call
// Initials will be displayed if there isn't any avatar.
// TODO : get FriendGui from Call.
StackView {
Loader{
id: mainItem
property AccountGui account: null
property FriendGui contact: null
property CallGui call: null
property string _address: account
? account.core?.identityAddress || ""
: call
? call.core.peerAddress
: contact
? contact.core.defaultAddress
: ''
? account.core?.identityAddress || ""
: call
? call.core.peerAddress
: contact
? contact.core.defaultAddress
: ''
readonly property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_address) : _address
property var displayNameObj: UtilsCpp.getDisplayName(_address)
property string displayNameVal: displayNameObj ? displayNameObj.value : ""
property bool haveAvatar: (account && account.core?.pictureUri || false)
|| (contact && contact.core.pictureUri)
|| computedAvatarUri.length != 0
|| (contact && contact.core.pictureUri)
|| computedAvatarUri.length != 0
property string computedAvatarUri: UtilsCpp.findAvatarByAddress(_address)
onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate)
property var securityLevelObj: UtilsCpp.getFriendAddressSecurityLevel(_address)
property var securityLevel: securityLevelObj ? securityLevelObj.value : LinphoneEnums.SecurityLevel.None
property bool secured: call && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? call.core.tokenVerified
: contact
? contact.core.devices.length != 0 && contact.core.verifiedDeviceCount === contact.core.devices.length
: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncrypted
property bool securityBreach: securityLevel === LinphoneEnums.SecurityLevel.Unsafe
property bool displayPresence: account
? account.core?.registrationState != LinphoneEnums.RegistrationState.Progress && account.core?.registrationState != LinphoneEnums.RegistrationState.Refreshing || false
: contact
? contact.core?.consolidatedPresence != LinphoneEnums.ConsolidatedPresence.Offline || false
: false
? call.core.tokenVerified
: contact
? contact.core.devices.length != 0 && contact.core.verifiedDeviceCount === contact.core.devices.length
: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncrypted
initialItem: haveAvatar ? avatar : initials
Rectangle {
visible: mainItem.secured || mainItem.securityBreach
anchors.fill: mainItem.currentItem
radius: mainItem.width / 2
z: 1
color: "transparent"
border {
width: 3 * DefaultStyle.dp
color: mainItem.secured ? DefaultStyle.info_500_main : DefaultStyle.danger_500main
}
Image {
source: mainItem.secured ? AppIcons.trusted : AppIcons.notTrusted
x: mainItem.width / 7
width: mainItem.width / 4.5
height: width
sourceSize.width: width
sourceSize.height: height
fillMode: Image.PreserveAspectFit
anchors.bottom: parent.bottom
}
}
Rectangle {
visible: mainItem.displayPresence
width: mainItem.width/4.5
height: width
radius: width / 2
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: mainItem.width / 15
z: 1
color: account
? account.core?.registrationState == LinphoneEnums.RegistrationState.Ok
? DefaultStyle.success_500main
: account.core?.registrationState == LinphoneEnums.RegistrationState.Cleared || account.core?.registrationState == LinphoneEnums.RegistrationState.None
? DefaultStyle.warning_600
: account.core?.registrationState == LinphoneEnums.RegistrationState.Progress || account.core?.registrationState == LinphoneEnums.RegistrationState.Refreshing
? DefaultStyle.main2_500main
: DefaultStyle.danger_500main
: contact
? contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Online
? DefaultStyle.success_500main
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Busy
? DefaultStyle.warning_600
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
: "transparent"
border {
width: 2 * DefaultStyle.dp
color: DefaultStyle.grey_0
}
}
Component{
id: initials
property bool securityBreach: securityLevel === LinphoneEnums.SecurityLevel.Unsafe
property bool displayPresence: account
? account.core?.registrationState != LinphoneEnums.RegistrationState.Progress && account.core?.registrationState != LinphoneEnums.RegistrationState.Refreshing || false
: contact
? contact.core?.consolidatedPresence != LinphoneEnums.ConsolidatedPresence.Offline || false
: false
asynchronous: true
sourceComponent: Component{
Item {
id: avatarItem
height: mainItem.height
width: height
Rectangle {
id: initialItem
property string initials: UtilsCpp.getInitials(mainItem.displayNameVal)
radius: width / 2
color: DefaultStyle.main2_200
height: mainItem.height
width: height
Text {
anchors.fill: parent
anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: initialItem.initials
font {
pixelSize: initialItem.height * 36 / 120
weight: 800 * DefaultStyle.dp
capitalization: Font.AllUppercase
}
}
Image {
id: initialImg
visible: initialItem.initials == ''
width: mainItem.width/3
height: width
source: AppIcons.profile
sourceSize.width: width
sourceSize.height: height
anchors.centerIn: parent
}
}
anchors.fill: parent
MultiEffect {
source: initialItem
anchors.fill: initialItem
source: stackView
anchors.fill: stackView
shadowEnabled: true
shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1
}
}
}
Component{
id: avatar
Item {
id: avatarItem
height: mainItem.height
width: height
Image {
id: image
visible: false
width: parent.width
height: parent.height
sourceSize.width: avatarItem.width
sourceSize.height: avatarItem.height
fillMode: Image.PreserveAspectCrop
anchors.centerIn: parent
source: mainItem.account && mainItem.account.core.pictureUri
|| mainItem.contact && mainItem.contact.core.pictureUri
|| computedAvatarUri
mipmap: true
layer.enabled: true
}
ShaderEffect {
id: roundEffect
property variant src: image
property real edge: 0.9
property real edgeSoftness: 0.9
property real radius: width / 2.0
property real shadowSoftness: 0.5
property real shadowOffset: 0.01
StackView {
id: stackView
initialItem: haveAvatar ? avatar : initials
anchors.fill: parent
fragmentShader: 'qrc:/data/shaders/roundEffect.frag.qsb'
Rectangle {
visible: mainItem.secured || mainItem.securityBreach
anchors.fill: stackView.currentItem
radius: stackView.width / 2
z: 1
color: "transparent"
border {
width: 3 * DefaultStyle.dp
color: mainItem.secured ? DefaultStyle.info_500_main : DefaultStyle.danger_500main
}
Image {
x: stackView.width / 7
anchors.bottom: parent.bottom
width: stackView.width / 4.5
height: width
asynchronous: true
source: mainItem.secured ? AppIcons.trusted : AppIcons.notTrusted
sourceSize.width: width
sourceSize.height: height
fillMode: Image.PreserveAspectFit
}
}
Rectangle {
visible: mainItem.displayPresence
width: stackView.width/4.5
height: width
radius: width / 2
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: stackView.width / 15
z: 1
color: account
? account.core?.registrationState == LinphoneEnums.RegistrationState.Ok
? DefaultStyle.success_500main
: account.core?.registrationState == LinphoneEnums.RegistrationState.Cleared || account.core?.registrationState == LinphoneEnums.RegistrationState.None
? DefaultStyle.warning_600
: account.core?.registrationState == LinphoneEnums.RegistrationState.Progress || account.core?.registrationState == LinphoneEnums.RegistrationState.Refreshing
? DefaultStyle.main2_500main
: DefaultStyle.danger_500main
: contact
? contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Online
? DefaultStyle.success_500main
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.Busy
? DefaultStyle.warning_600
: contact.core.consolidatedPresence === LinphoneEnums.ConsolidatedPresence.DoNotDisturb
? DefaultStyle.danger_500main
: DefaultStyle.main2_500main
: "transparent"
border {
width: 2 * DefaultStyle.dp
color: DefaultStyle.grey_0
}
}
Component{
id: initials
Item {
id: avatarItem
height: stackView.height
width: height
Rectangle {
id: initialItem
property string initials: UtilsCpp.getInitials(mainItem.displayNameVal)
radius: width / 2
color: DefaultStyle.main2_200
height: stackView.height
width: height
Text {
anchors.fill: parent
anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: initialItem.initials
font {
pixelSize: initialItem.height * 36 / 120
weight: 800 * DefaultStyle.dp
capitalization: Font.AllUppercase
}
}
Image {
id: initialImg
visible: initialItem.initials == ''
width: stackView.width/3
height: width
source: AppIcons.profile
sourceSize.width: width
sourceSize.height: height
anchors.centerIn: parent
}
}
MultiEffect {
source: initialItem
anchors.fill: initialItem
shadowEnabled: true
shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1
}
}
}
Component{
id: avatar
Item {
id: avatarItem
height: stackView.height
width: height
Image {
id: image
visible: false
width: parent.width
height: parent.height
sourceSize.width: avatarItem.width
sourceSize.height: avatarItem.height
fillMode: Image.PreserveAspectCrop
anchors.centerIn: parent
source: mainItem.account && mainItem.account.core.pictureUri
|| mainItem.contact && mainItem.contact.core.pictureUri
|| computedAvatarUri
mipmap: true
layer.enabled: true
}
ShaderEffect {
id: roundEffect
property variant src: image
property real edge: 0.9
property real edgeSoftness: 0.9
property real radius: width / 2.0
property real shadowSoftness: 0.5
property real shadowOffset: 0.01
anchors.fill: parent
fragmentShader: 'qrc:/data/shaders/roundEffect.frag.qsb'
}
}
}
}
}
}

View file

@ -275,7 +275,7 @@ ListView {
popup.contentItem: ColumnLayout {
Button {
text: modelData.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
text: $modelData.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
background: Item{}
icon.source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart
icon.width: 24 * DefaultStyle.dp

View file

@ -17,7 +17,8 @@ Loader {
property int imageHeight: height
property bool useColor: colorizationColor != undefined
property bool shadowEnabled: false
sourceComponent: Item {
asynchronous: true
sourceComponent: Component{Item {
Image {
id: image
visible: !effect2.effectEnabled
@ -80,4 +81,5 @@ Loader {
shadowOpacity: mainItem.shadowEnabled ? 0.7 : 0.0
}
}
}
}

View file

@ -16,8 +16,12 @@ ListView {
property var delegateButtons
property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null
signal conferenceSelected(var contact)
spacing: 8 * DefaultStyle.dp
currentIndex: confInfoProxy.currentDateIndex
// using highlight doesn't center, take time before moving and don't work for not visible item (like not loaded)
highlightFollowsCurrentItem: false
onCountChanged: selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null
onCurrentIndexChanged: {
@ -27,20 +31,20 @@ ListView {
mainItem.positionViewAtIndex(currentIndex, ListView.Center)// First approximative move
delayMove.restart() // Move to exact position after load.
}
onAtYEndChanged: if(atYEnd) confInfoProxy.displayMore()
Timer{
id: delayMove
interval: 60
onTriggered: mainItem.positionViewAtIndex(currentIndex, ListView.Center)
}
// using highlight doesn't center, take time before moving and don't work for not visible item (like not loaded)
highlightFollowsCurrentItem: false
signal conferenceSelected(var contact)
model: ConferenceInfoProxy {
id: confInfoProxy
searchText: searchBarText
filterText: searchBarText
filterType: ConferenceInfoProxy.None
initialDisplayItems: mainItem.height / (63 * DefaultStyle.dp) + 5
displayItemsStep: initialDisplayItems/2
}
section {

View file

@ -44,7 +44,7 @@ Window{
model: MagicSearchProxy{
id: search
searchText: ''
filterText: ''
}
delegate: Rectangle{
height: 50
@ -92,7 +92,7 @@ Window{
text: 'Get'
Layout.rightMargin: 20
onClicked: {
search.searchText = '*'
search.filterText = '*'
}
}
}

View file

@ -162,6 +162,26 @@ AbstractSettingsLayout {
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.topMargin: 35 * DefaultStyle.dp
Layout.bottomMargin: 9 * DefaultStyle.dp
height: 1 * DefaultStyle.dp
color: DefaultStyle.main2_500main
}
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Item {
Layout.preferredWidth: 341 * DefaultStyle.dp
}
SwitchSetting {
Layout.rightMargin: 44 * DefaultStyle.dp
titleText:qsTr("Cacher les FPS")
propertyName: "hideFps"
propertyOwner: SettingsCpp
}
}
}
}
}

View file

@ -242,10 +242,13 @@ AbstractMainPage {
Layout.fillWidth: true
Layout.fillHeight: true
model: CallHistoryProxy {
id: callHistoryProxy
filterText: searchBar.text
onFilterTextChanged: maxDisplayItems = initialDisplayItems
initialDisplayItems: historyListView.height / (56 * DefaultStyle.dp) + 5
displayItemsStep: initialDisplayItems / 2
}
currentIndex: -1
cacheBuffer: contentHeight>0 ? contentHeight : 0// cache all items
flickDeceleration: 10000
spacing: 10 * DefaultStyle.dp
highlightFollowsCurrentItem: true
@ -267,145 +270,137 @@ AbstractMainPage {
historyListView.model.removeAllEntries()
}
}
onAtYEndChanged: if(atYEnd) callHistoryProxy.displayMore()
delegate: FocusScope {
width:historyListView.width
height: 56 * DefaultStyle.dp
anchors.topMargin: 5 * DefaultStyle.dp
anchors.bottomMargin: 5 * DefaultStyle.dp
RowLayout {
z: 1
anchors.fill: parent
spacing: 10 * DefaultStyle.dp
Item {
Layout.preferredWidth: historyAvatar.width
Layout.preferredHeight: historyAvatar.height
Layout.leftMargin: 5 * DefaultStyle.dp
MultiEffect {
source: historyAvatar
anchors.fill: historyAvatar
shadowEnabled: true
shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1
}
width:historyListView.width
height: 56 * DefaultStyle.dp
anchors.topMargin: 5 * DefaultStyle.dp
anchors.bottomMargin: 5 * DefaultStyle.dp
visible: !!modelData
RowLayout {
z: 1
anchors.fill: parent
spacing: 10 * DefaultStyle.dp
Avatar {
id: historyAvatar
_address: modelData.core.remoteAddress
width: 45 * DefaultStyle.dp
height: 45 * DefaultStyle.dp
}
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
Text {
id: friendAddress
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
maximumLineCount: 1
text: modelData.core.displayName
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
capitalization: Font.Capitalize
spacing: 5 * DefaultStyle.dp
Text {
id: friendAddress
Layout.fillWidth: true
maximumLineCount: 1
text: modelData.core.displayName
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
capitalization: Font.Capitalize
}
}
}
RowLayout {
spacing: 6 * DefaultStyle.dp
EffectImage {
id: statusIcon
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
? AppIcons.arrowElbow
: modelData.core.isOutgoing
? AppIcons.arrowUpRight
: AppIcons.arrowDownLeft
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|| modelData.core.status === LinphoneEnums.CallStatus.Missed
? DefaultStyle.danger_500main
: modelData.core.isOutgoing
? DefaultStyle.info_500_main
: DefaultStyle.success_500main
Layout.preferredWidth: 12 * DefaultStyle.dp
Layout.preferredHeight: 12 * DefaultStyle.dp
transform: Rotation {
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
origin {
x: statusIcon.width/2
y: statusIcon.height/2
RowLayout {
spacing: 6 * DefaultStyle.dp
EffectImage {
id: statusIcon
imageSource: modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
? AppIcons.arrowElbow
: modelData.core.isOutgoing
? AppIcons.arrowUpRight
: AppIcons.arrowDownLeft
colorizationColor: modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|| modelData.core.status === LinphoneEnums.CallStatus.Missed
? DefaultStyle.danger_500main
: modelData.core.isOutgoing
? DefaultStyle.info_500_main
: DefaultStyle.success_500main
Layout.preferredWidth: 12 * DefaultStyle.dp
Layout.preferredHeight: 12 * DefaultStyle.dp
transform: Rotation {
angle: modelData.core.isOutgoing && (modelData.core.status === LinphoneEnums.CallStatus.Declined
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted) ? 180 : 0
origin {
x: statusIcon.width/2
y: statusIcon.height/2
}
}
}
Text {
// text: modelData.core.date
text: UtilsCpp.formatDate(modelData.core.date)
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
Text {
// text: modelData.core.date
text: UtilsCpp.formatDate(modelData.core.date, true)
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
Button {
Layout.rightMargin: 5 * DefaultStyle.dp
padding: 0
background: Item {
visible: false
}
icon.source: AppIcons.phone
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
focus: true
activeFocusOnTab: false
onClicked: {
if (modelData.core.isConference) {
var callsWindow = UtilsCpp.getCallsWindow()
callsWindow.setupConference(modelData.core.conferenceInfo)
callsWindow.show()
}
else {
UtilsCpp.createCall(modelData.core.remoteAddress)
}
}
}
}
Button {
Layout.rightMargin: 5 * DefaultStyle.dp
padding: 0
background: Item {
visible: false
}
icon.source: AppIcons.phone
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
MouseArea {
hoverEnabled: true
anchors.fill: parent
focus: true
activeFocusOnTab: false
onClicked: {
if (modelData.core.isConference) {
var callsWindow = UtilsCpp.getCallsWindow()
callsWindow.setupConference(modelData.core.conferenceInfo)
callsWindow.show()
}
else {
UtilsCpp.createCall(modelData.core.remoteAddress)
}
Rectangle {
anchors.fill: parent
opacity: 0.1
color: DefaultStyle.main2_500main
visible: parent.containsMouse
}
Rectangle {
anchors.fill: parent
visible: historyListView.currentIndex === model.index
color: DefaultStyle.main2_100
}
onPressed: {
historyListView.currentIndex = model.index
historyListView.forceActiveFocus()
}
}
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
focus: true
Rectangle {
anchors.fill: parent
opacity: 0.1
color: DefaultStyle.main2_500main
visible: parent.containsMouse
}
Rectangle {
anchors.fill: parent
visible: historyListView.currentIndex === model.index
color: DefaultStyle.main2_100
}
onPressed: {
historyListView.currentIndex = model.index
historyListView.forceActiveFocus()
}
}
}
//}
//}
onCurrentIndexChanged: {
positionViewAtIndex(currentIndex, ListView.Visible)
mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
}
onCountChanged: mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
onCountChanged: {
mainItem.selectedRowHistoryGui = model.getAt(currentIndex)
}
onVisibleChanged: {
if (!visible) currentIndex = -1
}

View file

@ -188,7 +188,6 @@ AbstractMainPage {
Layout.topMargin: 38 * DefaultStyle.dp - 24 * DefaultStyle.dp
Layout.fillWidth: true
Layout.fillHeight: true
visible: count != 0
hoverEnabled: mainItem.leftPanelEnabled
highlightFollowsCurrentItem: true
preferredHighlightBegin: height/2 - 10

View file

@ -249,4 +249,19 @@ ApplicationWindow {
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
}
FPSCounter{
anchors.top: parent.top
anchors.left: parent.left
height: 50
width: 120
z: 100
visible: !SettingsCpp.hideFps
Text{
font.bold: true
font.italic: true
font.pixelSize: 14 * DefaultStyle.dp
text: parent.fps + " FPS"
color: parent.fps < 30 ? DefaultStyle.danger_500main : DefaultStyle.main2_900
}
}
}