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/ListProxy.cpp
core/proxy/Proxy.cpp core/proxy/Proxy.cpp
core/proxy/SortFilterProxy.cpp core/proxy/SortFilterProxy.cpp
core/proxy/LimitProxy.cpp
core/variant/VariantList.cpp core/variant/VariantList.cpp

View file

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

View file

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

View file

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

View file

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

View file

@ -24,36 +24,24 @@
DEFINE_ABSTRACT_OBJECT(CarddavProxy) DEFINE_ABSTRACT_OBJECT(CarddavProxy)
CarddavProxy::CarddavProxy(QObject *parent) : SortFilterProxy(parent) { CarddavProxy::CarddavProxy(QObject *parent) : LimitProxy(parent) {
mCarddavList = CarddavList::create(); mCarddavList = CarddavList::create();
setSourceModel(mCarddavList.get()); setSourceModels(new SortFilterList(mCarddavList.get(), Qt::AscendingOrder));
} }
CarddavProxy::~CarddavProxy() { CarddavProxy::~CarddavProxy() {
setSourceModel(nullptr); 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() { void CarddavProxy::removeAllEntries() {
static_cast<CarddavList *>(sourceModel())->removeAllEntries(); static_cast<CarddavList *>(sourceModel())->removeAllEntries();
} }
void CarddavProxy::removeEntriesWithFilter() { void CarddavProxy::removeEntriesWithFilter() {
std::list<QSharedPointer<CarddavCore>> itemList(rowCount()); QList<QSharedPointer<CarddavCore>> itemList(rowCount());
for (auto i = rowCount() - 1; i >= 0; --i) { for (auto i = rowCount() - 1; i >= 0; --i) {
auto item = getItemAt<CarddavList, CarddavCore>(i); auto item = getItemAt<SortFilterList, CarddavList, CarddavCore>(i);
itemList.emplace_back(item); itemList[i] = item;
} }
for (auto item : itemList) { for (auto item : itemList) {
mCarddavList->ListProxy::remove(item.get()); 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; return true;
} }
bool CarddavProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool CarddavProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAt<CarddavList, CarddavCore>(left.row()); auto l = getItemAtSource<CarddavList, CarddavCore>(sourceLeft.row());
auto r = getItemAt<CarddavList, CarddavCore>(right.row()); auto r = getItemAtSource<CarddavList, CarddavCore>(sourceRight.row());
return l->mDisplayName < r->mDisplayName; return l->mDisplayName < r->mDisplayName;
} }

View file

@ -21,37 +21,27 @@
#ifndef CARDDAV_PROXY_H_ #ifndef CARDDAV_PROXY_H_
#define CARDDAV_PROXY_H_ #define CARDDAV_PROXY_H_
#include "../../proxy/SortFilterProxy.hpp" #include "../../proxy/LimitProxy.hpp"
#include "CarddavGui.hpp" #include "CarddavGui.hpp"
#include "CarddavList.hpp" #include "CarddavList.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
// ============================================================================= // =============================================================================
class CarddavProxy : public SortFilterProxy, public AbstractObject { class CarddavProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
CarddavProxy(QObject *parent = Q_NULLPTR); CarddavProxy(QObject *parent = Q_NULLPTR);
~CarddavProxy(); ~CarddavProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries(); Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter(); Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView(); Q_INVOKABLE void updateView();
signals:
void filterTextChanged();
protected: 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; QSharedPointer<CarddavList> mCarddavList;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

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

View file

@ -21,25 +21,21 @@
#ifndef LDAP_PROXY_H_ #ifndef LDAP_PROXY_H_
#define LDAP_PROXY_H_ #define LDAP_PROXY_H_
#include "../../proxy/SortFilterProxy.hpp" #include "../../proxy/LimitProxy.hpp"
#include "LdapGui.hpp"
#include "LdapList.hpp" #include "LdapList.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
// ============================================================================= // =============================================================================
class LdapProxy : public SortFilterProxy, public AbstractObject { class LdapProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
LdapProxy(QObject *parent = Q_NULLPTR); LdapProxy(QObject *parent = Q_NULLPTR);
~LdapProxy(); ~LdapProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries(); Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter(); Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView(); Q_INVOKABLE void updateView();
@ -48,10 +44,6 @@ signals:
void filterTextChanged(); void filterTextChanged();
protected: 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; QSharedPointer<LdapList> mLdapList;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -73,6 +73,18 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
mustBeInMainThread(getClassName()); mustBeInMainThread(getClassName());
resetData(); resetData();
add(*callLogs); 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; delete callLogs;
}); });
}); });
@ -109,3 +121,14 @@ QVariant CallHistoryList::data(const QModelIndex &index, int role) const {
} }
return QVariant(); 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"; // roles[Qt::DisplayRole + 2] = "date";
// return roles; // return roles;
// } // }
//void displayMore();
signals: signals:
void lUpdate(); void lUpdate();

View file

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

View file

@ -21,37 +21,27 @@
#ifndef CALL_HISTORY_PROXY_H_ #ifndef CALL_HISTORY_PROXY_H_
#define CALL_HISTORY_PROXY_H_ #define CALL_HISTORY_PROXY_H_
#include "../proxy/LimitProxy.hpp"
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/SortFilterProxy.hpp"
#include "CallHistoryGui.hpp"
#include "CallHistoryList.hpp" #include "CallHistoryList.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
#include <QSortFilterProxyModel>
// ============================================================================= // =============================================================================
class CallHistoryProxy : public SortFilterProxy, public AbstractObject { class CallHistoryProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
CallHistoryProxy(QObject *parent = Q_NULLPTR); CallHistoryProxy(QObject *parent = Q_NULLPTR);
~CallHistoryProxy(); ~CallHistoryProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries(); Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter(); Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView(); Q_INVOKABLE void updateView();
signals:
void filterTextChanged();
protected: 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; QSharedPointer<CallHistoryList> mHistoryList;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -25,34 +25,21 @@
DEFINE_ABSTRACT_OBJECT(CallProxy) DEFINE_ABSTRACT_OBJECT(CallProxy)
CallProxy::CallProxy(QObject *parent) : SortFilterProxy(parent) { CallProxy::CallProxy(QObject *parent) : LimitProxy(parent) {
setSourceModel(App::getInstance()->getCallList().get()); setSourceModel(App::getInstance()->getCallList().get());
sort(0);
} }
CallProxy::~CallProxy() { 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() { CallGui *CallProxy::getCurrentCall() {
if (!mCurrentCall) mCurrentCall = dynamic_cast<CallList *>(sourceModel())->getCurrentCall(); auto model = getListModel<CallList>();
if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall();
return mCurrentCall; return mCurrentCall;
} }
void CallProxy::setCurrentCall(CallGui *call) { 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. // Reset the default account to let UI build its new object if needed.
@ -62,11 +49,11 @@ void CallProxy::resetCurrentCall() {
} }
bool CallProxy::getHaveCall() const { bool CallProxy::getHaveCall() const {
return dynamic_cast<CallList *>(sourceModel())->getHaveCall(); return getListModel<CallList>()->getHaveCall();
} }
void CallProxy::setSourceModel(QAbstractItemModel *model) { void CallProxy::setSourceModel(QAbstractItemModel *model) {
auto oldCallList = dynamic_cast<CallList *>(sourceModel()); auto oldCallList = getListModel<CallList>();
if (oldCallList) { if (oldCallList) {
disconnect(oldCallList); disconnect(oldCallList);
} }
@ -76,27 +63,26 @@ void CallProxy::setSourceModel(QAbstractItemModel *model) {
connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection); connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection);
connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll); 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 == "*"); bool show = (mFilterText.isEmpty() || mFilterText == "*");
if (!show) { if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText), QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption | QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption); QRegularExpression::UseUnicodePropertiesOption);
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); auto call = qobject_cast<CallList *>(sourceModel())->getAt<CallCore>(sourceRow);
auto model = sourceModel()->data(index);
auto call = model.value<CallGui *>(); show = call->getPeerAddress().contains(search);
show = call->getCore()->getPeerAddress().contains(search);
} }
return show; return show;
} }
bool CallProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool CallProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = sourceModel()->data(left); auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row());
auto r = sourceModel()->data(right); 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_ #ifndef CALL_PROXY_H_
#define CALL_PROXY_H_ #define CALL_PROXY_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/LimitProxy.hpp"
#include "core/call/CallGui.hpp" #include "core/call/CallGui.hpp"
#include "core/call/CallList.hpp" #include "core/call/CallList.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
// ============================================================================= // =============================================================================
class CallProxy : public SortFilterProxy, public AbstractObject { class CallProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged) Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged) Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
CallProxy(QObject *parent = Q_NULLPTR); CallProxy(QObject *parent = Q_NULLPTR);
~CallProxy(); ~CallProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
// Get a new object from List or give the stored one. // Get a new object from List or give the stored one.
CallGui *getCurrentCall(); CallGui *getCurrentCall();
// TODO for manual setting. Changing the currentCall is automatically done by call->onStateChanged() on // TODO for manual setting. Changing the currentCall is automatically done by call->onStateChanged() on
@ -54,15 +52,10 @@ public:
signals: signals:
void lMergeAll(); void lMergeAll();
void filterTextChanged();
void currentCallChanged(); void currentCallChanged();
void haveCallChanged(); void haveCallChanged();
protected: 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 CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -25,15 +25,11 @@
DEFINE_ABSTRACT_OBJECT(ConferenceInfoProxy) DEFINE_ABSTRACT_OBJECT(ConferenceInfoProxy)
ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(parent) { ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) {
mList = ConferenceInfoList::create(); mList = ConferenceInfoList::create();
setSourceModel(mList.get()); setSourceModels(new SortFilterList(mList.get()));
connect( connect(
this, &ConferenceInfoProxy::searchTextChanged, this, this, &ConferenceInfoProxy::filterTextChanged, this, [this] { updateCurrentDateIndex(); },
[this] {
invalidate();
updateCurrentDateIndex();
},
Qt::QueuedConnection); Qt::QueuedConnection);
connect( connect(
mList.get(), &ConferenceInfoList::haveCurrentDateChanged, this, mList.get(), &ConferenceInfoList::haveCurrentDateChanged, this,
@ -49,16 +45,6 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(pare
} }
ConferenceInfoProxy::~ConferenceInfoProxy() { ConferenceInfoProxy::~ConferenceInfoProxy() {
setSourceModel(nullptr);
}
QString ConferenceInfoProxy::getSearchText() const {
return mSearchText;
}
void ConferenceInfoProxy::setSearchText(const QString &search) {
mSearchText = search;
emit searchTextChanged();
} }
bool ConferenceInfoProxy::haveCurrentDate() const { bool ConferenceInfoProxy::haveCurrentDate() const {
@ -77,15 +63,16 @@ void ConferenceInfoProxy::updateCurrentDateIndex() {
} }
} }
bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto ciCore = qobject_cast<ConferenceInfoList *>(sourceModel())->template getAt<ConferenceInfoCore>(sourceRow); auto list = qobject_cast<ConferenceInfoList *>(sourceModel());
auto ciCore = list->getAt<ConferenceInfoCore>(sourceRow);
if (ciCore) { if (ciCore) {
bool searchTextInSubject = false; bool searchTextInSubject = false;
bool searchTextInParticipant = 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()) { for (auto &contact : ciCore->getParticipants()) {
auto infos = contact.toMap(); auto infos = contact.toMap();
if (infos["displayName"].toString().contains(mSearchText, Qt::CaseInsensitive)) { if (infos["displayName"].toString().contains(mFilterText, Qt::CaseInsensitive)) {
searchTextInParticipant = true; searchTextInParticipant = true;
break; break;
} }
@ -99,7 +86,12 @@ bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou
return res; return res;
} else return mFilterType == -1; } else return mFilterType == -1;
} else { } else {
return !mList->haveCurrentDate() && mList->getCount() > 1 && return !list->haveCurrentDate() && list->getCount() > 1 && mFilterText.isEmpty();
mSearchText.isEmpty(); // if mlist count == 1 there is only the dummy row which we don't display alone // 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_ #ifndef CONFERENCE_INFO_PROXY_H_
#define CONFERENCE_INFO_PROXY_H_ #define CONFERENCE_INFO_PROXY_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/LimitProxy.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
class ConferenceInfoList; class ConferenceInfoList;
class ConferenceInfoProxy : public SortFilterProxy, public AbstractObject { class ConferenceInfoProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged)
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged) Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged) Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged)
@ -37,32 +36,24 @@ public:
enum ConferenceInfoFiltering { None = 0, Future = 1 }; enum ConferenceInfoFiltering { None = 0, Future = 1 };
Q_ENUM(ConferenceInfoFiltering) Q_ENUM(ConferenceInfoFiltering)
public: public:
DECLARE_SORTFILTER_CLASS()
ConferenceInfoProxy(QObject *parent = Q_NULLPTR); ConferenceInfoProxy(QObject *parent = Q_NULLPTR);
~ConferenceInfoProxy(); ~ConferenceInfoProxy();
QString getSearchText() const;
void setSearchText(const QString &search);
bool haveCurrentDate() const; bool haveCurrentDate() const;
int getCurrentDateIndex() const; int getCurrentDateIndex() const;
void updateCurrentDateIndex(); 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: signals:
void searchTextChanged();
void haveCurrentDateChanged(); void haveCurrentDateChanged();
void currentDateIndexChanged(); void currentDateIndexChanged();
private: private:
QString mSearchText;
QSharedPointer<ConferenceInfoList> mList; QSharedPointer<ConferenceInfoList> mList;
int mCurrentDateIndex = -1; int mCurrentDateIndex = -1;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -44,7 +44,7 @@ void FPSCounter::recalculateFPS() {
int currentCount = _times.length(); int currentCount = _times.length();
_currentFPS = (currentCount + _cacheCount) / 2; _currentFPS = (currentCount + _cacheCount) / 2;
lDebug() << _currentFPS; // lDebug() << _currentFPS;
if (currentCount != _cacheCount) fpsChanged(_currentFPS); if (currentCount != _cacheCount) fpsChanged(_currentFPS);
@ -58,11 +58,13 @@ int FPSCounter::fps() const {
void FPSCounter::paint(QPainter *painter) { void FPSCounter::paint(QPainter *painter) {
recalculateFPS(); recalculateFPS();
// lDebug()<< __FUNCTION__; // lDebug()<< __FUNCTION__;
/*
QBrush brush(Qt::yellow); QBrush brush(Qt::yellow);
painter->setBrush(brush); painter->setBrush(brush);
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
painter->setRenderHint(QPainter::Antialiasing); painter->setRenderHint(QPainter::Antialiasing);
painter->drawRoundedRect(0, 0, boundingRect().width(), boundingRect().height(), 0, 0); painter->drawRoundedRect(0, 0, boundingRect().width(), boundingRect().height(), 0, 0);
*/
update(); 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_ABSTRACT_OBJECT(ParticipantDeviceProxy)
DEFINE_GUI_OBJECT(ParticipantDeviceProxy) DEFINE_GUI_OBJECT(ParticipantDeviceProxy)
ParticipantDeviceProxy::ParticipantDeviceProxy(QObject *parent) : SortFilterProxy(parent) { ParticipantDeviceProxy::ParticipantDeviceProxy(QObject *parent) : LimitProxy(parent) {
mParticipants = ParticipantDeviceList::create(); mParticipants = ParticipantDeviceList::create();
connect(mParticipants.get(), &ParticipantDeviceList::countChanged, this, &ParticipantDeviceProxy::meChanged, connect(mParticipants.get(), &ParticipantDeviceList::countChanged, this, &ParticipantDeviceProxy::meChanged,
Qt::QueuedConnection); Qt::QueuedConnection);
setSourceModel(mParticipants.get()); setSourceModels(new SortFilterList(mParticipants.get(), Qt::AscendingOrder));
sort(0); //, Qt::DescendingOrder);
} }
ParticipantDeviceProxy::~ParticipantDeviceProxy() { ParticipantDeviceProxy::~ParticipantDeviceProxy() {
setSourceModel(nullptr);
} }
CallGui *ParticipantDeviceProxy::getCurrentCall() const { 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; return true;
} }
bool ParticipantDeviceProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool ParticipantDeviceProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
auto deviceA = sourceModel()->data(left).value<ParticipantDeviceGui *>()->getCore(); const QModelIndex &sourceRight) const {
auto deviceB = sourceModel()->data(right).value<ParticipantDeviceGui *>()->getCore(); 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_ #ifndef PARTICIPANT_DEVICE_PROXY_MODEL_H_
#define 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/call/CallGui.hpp"
#include "core/participant/ParticipantDeviceGui.hpp" #include "core/participant/ParticipantDeviceGui.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
@ -29,13 +29,15 @@
class ParticipantDeviceList; class ParticipantDeviceList;
class ParticipantDeviceGui; class ParticipantDeviceGui;
class ParticipantDeviceProxy : public SortFilterProxy, public AbstractObject { class ParticipantDeviceProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged) Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(ParticipantDeviceGui *me READ getMe NOTIFY meChanged) Q_PROPERTY(ParticipantDeviceGui *me READ getMe NOTIFY meChanged)
public: public:
DECLARE_GUI_OBJECT DECLARE_GUI_OBJECT
DECLARE_SORTFILTER_CLASS()
ParticipantDeviceProxy(QObject *parent = Q_NULLPTR); ParticipantDeviceProxy(QObject *parent = Q_NULLPTR);
~ParticipantDeviceProxy(); ~ParticipantDeviceProxy();
@ -44,17 +46,12 @@ public:
ParticipantDeviceGui *getMe() const; ParticipantDeviceGui *getMe() const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals: signals:
void lUpdate(); void lUpdate();
void currentCallChanged(); void currentCallChanged();
void meChanged(); void meChanged();
private: private:
QString mSearchText;
CallGui *mCurrentCall = nullptr; CallGui *mCurrentCall = nullptr;
QSharedPointer<ParticipantDeviceList> mParticipants; QSharedPointer<ParticipantDeviceList> mParticipants;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,34 +21,23 @@
#ifndef PHONE_NUMBER_PROXY_H_ #ifndef PHONE_NUMBER_PROXY_H_
#define PHONE_NUMBER_PROXY_H_ #define PHONE_NUMBER_PROXY_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/LimitProxy.hpp"
#include "PhoneNumberList.hpp" #include "PhoneNumberList.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
// ============================================================================= // =============================================================================
class PhoneNumberProxy : public SortFilterProxy, public AbstractObject { class PhoneNumberProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
PhoneNumberProxy(QObject *parent = Q_NULLPTR); PhoneNumberProxy(QObject *parent = Q_NULLPTR);
~PhoneNumberProxy(); ~PhoneNumberProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE int findIndexByCountryCallingCode(const QString &countryCallingCode); Q_INVOKABLE int findIndexByCountryCallingCode(const QString &countryCallingCode);
signals:
void filterTextChanged();
protected: 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; QSharedPointer<PhoneNumberList> mPhoneNumberList;
private: private:

View file

@ -35,9 +35,9 @@ public:
virtual ~AbstractListProxy() { virtual ~AbstractListProxy() {
clearData(); clearData();
} }
virtual int rowCount(const QModelIndex &index = QModelIndex()) const override { virtual int rowCount(const QModelIndex &index = QModelIndex()) const override {
return mList.count(); return getDisplayCount(mList.size());
} }
virtual QHash<int, QByteArray> roleNames() const override { virtual QHash<int, QByteArray> roleNames() const override {
@ -45,6 +45,7 @@ public:
roles[Qt::DisplayRole] = "$modelData"; roles[Qt::DisplayRole] = "$modelData";
return roles; return roles;
} }
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
int row = index.row(); int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
@ -59,37 +60,58 @@ public:
// Add functions // Add functions
virtual void add(T item) { virtual void add(T item) {
int row = mList.count(); int row = rowCount();
beginInsertRows(QModelIndex(), row, row); if (mMaxDisplayItems > 0 && row + 1 >= mMaxDisplayItems) {// New item is not in display range
mList << item; mList << item;
endInsertRows(); }else{
auto lastIndex = index(mList.size() - 1, 0); beginInsertRows(QModelIndex(), row, row);
emit dataChanged(lastIndex, lastIndex); mList << item;
}
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;
endInsertRows(); endInsertRows();
auto lastIndex = index(mList.size() - 1, 0); 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) { virtual void prepend(T item) {
int currentCount = rowCount();
beginInsertRows(QModelIndex(), 0, 0); beginInsertRows(QModelIndex(), 0, 0);
mList.prepend(item); mList.prepend(item);
endInsertRows(); endInsertRows();
if(mMaxDisplayItems > 0 && currentCount + 1 >= mMaxDisplayItems){
setMaxDisplayItems(mMaxDisplayItems+1);
}
emit dataChanged(index(0), index(0)); emit dataChanged(index(0), index(0));
} }
virtual void prepend(QList<T> items) { 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); beginInsertRows(QModelIndex(), 0, items.size() - 1);
items << mList; items << mList;
mList = items; mList = items;
endInsertRows(); endInsertRows();
if(mMaxDisplayItems > 0 && newCount >= mMaxDisplayItems){
setMaxDisplayItems(newCount);
}
emit dataChanged(index(0), index(items.size() - 1)); emit dataChanged(index(0), index(items.size() - 1));
} }
} }
@ -111,6 +133,7 @@ public:
virtual void clearData() override { virtual void clearData() override {
mList.clear(); mList.clear();
setMaxDisplayItems(getInitialDisplayItems());
} }
virtual void resetData() override { virtual void resetData() override {
@ -118,6 +141,16 @@ public:
clearData(); clearData();
endResetModel(); 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: protected:
QList<T> mList; 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> template <class T>
void add(QList<QSharedPointer<T>> items) { void add(QList<QSharedPointer<T>> items) {
if (items.size() > 0) { int count = items.size();
QModelIndex firstIndex = mList.size() > 0 ? index(mList.size() - 1, 0) : index(0, 0); if (count > 0 ) {
beginInsertRows(QModelIndex(), mList.size(), mList.size() + items.size() - 1); int currentCount = rowCount();
for (auto i : items) int newCount = getDisplayCount(mList.size() + count);
mList << i.template objectCast<QObject>(); if(newCount != currentCount){
endInsertRows(); beginInsertRows(QModelIndex(), currentCount, newCount - 1);
auto lastIndex = index(mList.size() - 1, 0); for (auto i : items)
emit dataChanged(firstIndex, lastIndex); 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> template <class T>
void prepend(QList<QSharedPointer<T>> items) { void prepend(QList<QSharedPointer<T>> items) {
if (items.size() > 0) { AbstractListProxy<QSharedPointer<QObject>>::prepend(items);
beginInsertRows(QModelIndex(), 0, items.size() - 1);
items << mList;
mList = items;
endInsertRows();
emit dataChanged(index(0), index(items.size() - 1));
}
} }
virtual bool remove(QObject *itemToRemove) override { 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::rowsInserted, this, &Proxy::countChanged);
connect(this, &Proxy::rowsRemoved, this, &Proxy::countChanged); connect(this, &Proxy::rowsRemoved, this, &Proxy::countChanged);
} }
int Proxy::getCount() const { int Proxy::getCount() const {
return rowCount(); return rowCount();
} }
int Proxy::getDisplayCount(int listCount) const {
return mMaxDisplayItems >= 0 ? qMin(listCount, mMaxDisplayItems) : listCount;
}
bool Proxy::remove(QObject *itemToRemove) { bool Proxy::remove(QObject *itemToRemove) {
return false; return false;
} }
void Proxy::clearData() { void Proxy::clearData() {
} }
void Proxy::resetData() { 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: public:
Q_PROPERTY(int count READ getCount NOTIFY countChanged) Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(int length 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); Proxy(QObject *parent = nullptr);
Q_INVOKABLE virtual int getCount() const; Q_INVOKABLE virtual int getCount() const;
int getDisplayCount(int listCount) const;
Q_INVOKABLE virtual bool remove(QObject *itemToRemove); Q_INVOKABLE virtual bool remove(QObject *itemToRemove);
Q_INVOKABLE virtual void clearData(); Q_INVOKABLE virtual void clearData();
Q_INVOKABLE virtual void resetData(); 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: signals:
void countChanged(); void countChanged();
void initialDisplayItemsChanged();
void maxDisplayItemsChanged();
void displayItemsStepChanged();
}; };
#endif #endif

View file

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

View file

@ -22,37 +22,62 @@
#define SORT_FILTER_PROXY_H_ #define SORT_FILTER_PROXY_H_
#include <QSortFilterProxyModel> #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 { class SortFilterProxy : public QSortFilterProxyModel {
Q_OBJECT Q_OBJECT
public: public:
Q_PROPERTY(int count READ getCount NOTIFY countChanged) Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(int filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged) 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 ~SortFilterProxy();
virtual void deleteSourceModel(); virtual void deleteSourceModel();
virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
virtual int getCount() const; virtual int getCount() const;
virtual int getFilterType() const;
Q_INVOKABLE QVariant getAt(const int &index) const; Q_INVOKABLE QVariant getAt(const int &index) const;
template <class A, class B> template <class A, class B>
QSharedPointer<B> getItemAt(const int &atIndex) const { QSharedPointer<B> getItemAt(const int &atIndex) const {
auto modelIndex = index(atIndex, 0); auto modelIndex = index(atIndex, 0);
return qobject_cast<A *>(sourceModel())->template getAt<B>(mapToSource(modelIndex).row()); 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); 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); Q_INVOKABLE void remove(int index, int count = 1);
signals: signals:
void countChanged(); void countChanged();
void filterTypeChanged(int filterType); void filterTypeChanged(int filterType);
void filterTextChanged();
protected: protected:
int mFilterType = 0; int mFilterType = 0;
QString mFilterText;
bool mDeleteSourceModel = false; bool mDeleteSourceModel = false;
}; };

View file

@ -24,18 +24,28 @@
#include "ScreenProxy.hpp" #include "ScreenProxy.hpp"
// ============================================================================= // =============================================================================
ScreenProxy::ScreenProxy(QObject *parent) : SortFilterProxy(parent) { ScreenProxy::ScreenProxy(QObject *parent) : LimitProxy(parent) {
setSourceModel(new ScreenList(this)); setSourceModels(new SortFilterList(new ScreenList(this), Qt::AscendingOrder));
sort(0);
} }
ScreenList::Mode ScreenProxy::getMode() const { ScreenList::Mode ScreenProxy::getMode() const {
return dynamic_cast<ScreenList *>(sourceModel())->getMode(); return getListModel<ScreenList>()->getMode();
} }
void ScreenProxy::setMode(ScreenList::Mode data) { void ScreenProxy::setMode(ScreenList::Mode data) {
dynamic_cast<ScreenList *>(sourceModel())->setMode(data); getListModel<ScreenList>()->setMode(data);
} }
void ScreenProxy::update() { 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_ #define SCREEN_PROXY_H_
#include "ScreenList.hpp" #include "ScreenList.hpp"
#include "core/proxy/SortFilterProxy.hpp" #include "core/proxy/LimitProxy.hpp"
// ============================================================================= // =============================================================================
class QWindow; class QWindow;
class ScreenProxy : public SortFilterProxy { class ScreenProxy : public LimitProxy {
class ScreenModelFilter; class ScreenModelFilter;
Q_OBJECT Q_OBJECT
Q_PROPERTY(ScreenList::Mode mode READ getMode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(ScreenList::Mode mode READ getMode WRITE setMode NOTIFY modeChanged)
public: public:
DECLARE_SORTFILTER_CLASS()
ScreenProxy(QObject *parent = Q_NULLPTR); ScreenProxy(QObject *parent = Q_NULLPTR);
ScreenList::Mode getMode() const; ScreenList::Mode getMode() const;

View file

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

View file

@ -21,13 +21,13 @@
#ifndef MAGIC_SEARCH_PROXY_H_ #ifndef MAGIC_SEARCH_PROXY_H_
#define MAGIC_SEARCH_PROXY_H_ #define MAGIC_SEARCH_PROXY_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/LimitProxy.hpp"
#include "core/search/MagicSearchList.hpp" #include "core/search/MagicSearchList.hpp"
#include "tool/LinphoneEnums.hpp" #include "tool/LinphoneEnums.hpp"
// ============================================================================= // =============================================================================
class MagicSearchProxy : public SortFilterProxy { class MagicSearchProxy : public LimitProxy {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString searchText READ getSearchText WRITE setSearchText NOTIFY searchTextChanged) 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) Q_PROPERTY(MagicSearchProxy *parentProxy WRITE setParentProxy NOTIFY parentProxyChanged)
public: public:
DECLARE_SORTFILTER_CLASS(bool mShowFavoritesOnly = false;)
MagicSearchProxy(QObject *parent = Q_NULLPTR); MagicSearchProxy(QObject *parent = Q_NULLPTR);
~MagicSearchProxy(); ~MagicSearchProxy();
@ -72,11 +73,8 @@ signals:
protected: protected:
QString mSearchText; QString mSearchText;
int mSourceFlags; int mSourceFlags;
bool mShowFavoritesOnly = false;
LinphoneEnums::MagicSearchAggregation mAggregationFlag; LinphoneEnums::MagicSearchAggregation mAggregationFlag;
QSharedPointer<MagicSearchList> mList; 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 #endif

View file

@ -80,6 +80,7 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(DisableBroadcastFeature, settingsModel) INIT_CORE_MEMBER(DisableBroadcastFeature, settingsModel)
INIT_CORE_MEMBER(HideSettings, settingsModel) INIT_CORE_MEMBER(HideSettings, settingsModel)
INIT_CORE_MEMBER(HideAccountSettings, settingsModel) INIT_CORE_MEMBER(HideAccountSettings, settingsModel)
INIT_CORE_MEMBER(HideFps, settingsModel)
INIT_CORE_MEMBER(DisableCallRecordings, settingsModel) INIT_CORE_MEMBER(DisableCallRecordings, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel) INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel) INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
@ -311,6 +312,8 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
HideSettings) HideSettings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
hideAccountSettings, HideAccountSettings) hideAccountSettings, HideAccountSettings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
hideFps, HideFps)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCallRecordings, DisableCallRecordings) disableCallRecordings, DisableCallRecordings)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, 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, disableBroadcastFeature, DisableBroadcastFeature)
DECLARE_CORE_GETSET_MEMBER(bool, hideSettings, HideSettings) DECLARE_CORE_GETSET_MEMBER(bool, hideSettings, HideSettings)
DECLARE_CORE_GETSET_MEMBER(bool, hideAccountSettings, HideAccountSettings) 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, disableCallRecordings, DisableCallRecordings)
DECLARE_CORE_GETSET_MEMBER(bool, assistantHideCreateAccount, AssistantHideCreateAccount) DECLARE_CORE_GETSET_MEMBER(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
DECLARE_CORE_GETSET_MEMBER(bool, assistantDisableQrCode, AssistantDisableQrCode) DECLARE_CORE_GETSET_MEMBER(bool, assistantDisableQrCode, AssistantDisableQrCode)

View file

@ -24,19 +24,20 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
TimeZoneProxy::TimeZoneProxy(QObject *parent) : SortFilterProxy(parent) { TimeZoneProxy::TimeZoneProxy(QObject *parent) : LimitProxy(parent) {
mDeleteSourceModel = true;
mList = TimeZoneList::create(); mList = TimeZoneList::create();
setSourceModel(mList.get()); setSourceModels(new SortFilterList(mList.get(), Qt::AscendingOrder));
sort(0);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool TimeZoneProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { bool TimeZoneProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto test = sourceModel()->data(left); return true;
auto l = getItemAt<TimeZoneList, TimeZoneModel>(left.row()); }
auto r = getItemAt<TimeZoneList, TimeZoneModel>(right.row());
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; if (!l || !r) return true;
auto timeA = l->getStandardTimeOffset() / 3600; auto timeA = l->getStandardTimeOffset() / 3600;
auto timeB = r->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 TimeZoneProxy::getIndex(TimeZoneModel *model) const {
int index = 0; int index = 0;
index = mList->get(model ? model->getTimeZone() : QTimeZone::systemTimeZone()); 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_ #ifndef TIME_ZONE_PROXY_MODEL_H_
#define TIME_ZONE_PROXY_MODEL_H_ #define TIME_ZONE_PROXY_MODEL_H_
#include "../proxy/SortFilterProxy.hpp" #include "../proxy/LimitProxy.hpp"
// ============================================================================= // =============================================================================
class TimeZoneModel; class TimeZoneModel;
class TimeZoneList; class TimeZoneList;
class TimeZoneProxy : public SortFilterProxy { class TimeZoneProxy : public LimitProxy {
Q_OBJECT Q_OBJECT
public: public:
DECLARE_SORTFILTER_CLASS()
TimeZoneProxy(QObject *parent = Q_NULLPTR); TimeZoneProxy(QObject *parent = Q_NULLPTR);
Q_PROPERTY(int defaultIndex READ getIndex CONSTANT) Q_PROPERTY(int defaultIndex READ getIndex CONSTANT)
@ -38,7 +40,6 @@ public:
protected: protected:
QSharedPointer<TimeZoneList> mList; QSharedPointer<TimeZoneList> mList;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
}; };
#endif #endif

View file

@ -38,13 +38,15 @@ void cleanStream() {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
#if defined _WIN32 /*
// log in console only if launched from console #if defined _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS)) { // log in console only if launched from console
freopen_s(&gStream, "CONOUT$", "w", stdout); if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen_s(&gStream, "CONOUT$", "w", stderr); freopen_s(&gStream, "CONOUT$", "w", stdout);
} freopen_s(&gStream, "CONOUT$", "w", stderr);
#endif }
#endif
*/
// Useful to share camera on Fullscreen (other context) or multiscreens // Useful to share camera on Fullscreen (other context) or multiscreens
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Disable QML cache. Avoid malformed cache. // 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(disableMeetingsFeature, DisableMeetingsFeature)
DEFINE_NOTIFY_CONFIG_READY(hideSettings,HideSettings) DEFINE_NOTIFY_CONFIG_READY(hideSettings,HideSettings)
DEFINE_NOTIFY_CONFIG_READY(hideAccountSettings, HideAccountSettings) DEFINE_NOTIFY_CONFIG_READY(hideAccountSettings, HideAccountSettings)
DEFINE_NOTIFY_CONFIG_READY(hideFps, HideFps)
DEFINE_NOTIFY_CONFIG_READY(disableCallRecordings, DisableCallRecordings) DEFINE_NOTIFY_CONFIG_READY(disableCallRecordings, DisableCallRecordings)
DEFINE_NOTIFY_CONFIG_READY(assistantHideCreateAccount, AssistantHideCreateAccount) DEFINE_NOTIFY_CONFIG_READY(assistantHideCreateAccount, AssistantHideCreateAccount)
DEFINE_NOTIFY_CONFIG_READY(assistantDisableQrCode, AssistantDisableQrCode) 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, hideSettings, HideSettings, "hide_settings", false)
DEFINE_GETSET_CONFIG( DEFINE_GETSET_CONFIG(
SettingsModel, bool, Bool, hideAccountSettings, HideAccountSettings, "hide_account_settings", false) SettingsModel, bool, Bool, hideAccountSettings, HideAccountSettings, "hide_account_settings", false)
DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, hideFps, HideFps, "hide_fps", true )
DEFINE_GETSET_CONFIG(SettingsModel, DEFINE_GETSET_CONFIG(SettingsModel,
bool, bool,
Bool, Bool,

View file

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

View file

@ -3,7 +3,7 @@ import QtQuick.Controls.Basic as Control
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts import QtQuick.Layouts
import Linphone import Linphone
Control.Button { Control.Button {
id: mainItem id: mainItem
property int capitalization property int capitalization
@ -26,7 +26,8 @@ Control.Button {
// rightPadding: 20 * DefaultStyle.dp // rightPadding: 20 * DefaultStyle.dp
// topPadding: 11 * DefaultStyle.dp // topPadding: 11 * DefaultStyle.dp
// bottomPadding: 11 * DefaultStyle.dp // bottomPadding: 11 * DefaultStyle.dp
implicitHeight: contentItem.implicitHeight + bottomPadding + topPadding
implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
@ -34,42 +35,48 @@ Control.Button {
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
} }
background: Item { background: Loader{
Rectangle { asynchronous: true
anchors.fill: parent anchors.fill: parent
id: buttonBackground
color: mainItem.enabled sourceComponent:
? inversedColors Item {
? mainItem.pressed || mainItem.shadowEnabled Rectangle {
? DefaultStyle.grey_100 id: buttonBackground
: 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 anchors.fill: parent
hoverEnabled: true color: mainItem.enabled
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor ? 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 { component ButtonText: Text {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -90,7 +97,7 @@ Control.Button {
bold: mainItem.font.bold bold: mainItem.font.bold
} }
} }
component ButtonImage: EffectImage { component ButtonImage: EffectImage {
// Layout.fillWidth: true // Layout.fillWidth: true
// Layout.fillHeight: true // Layout.fillHeight: true
@ -100,7 +107,70 @@ Control.Button {
colorizationColor: mainItem.contentImageColor colorizationColor: mainItem.contentImageColor
shadowEnabled: mainItem.shadowEnabled 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 { contentItem: StackLayout {
id: stacklayout id: stacklayout
currentIndex: mainItem.text.length != 0 && mainItem.icon.source.toString().length != 0 currentIndex: mainItem.text.length != 0 && mainItem.icon.source.toString().length != 0
@ -110,7 +180,7 @@ Control.Button {
: mainItem.icon.source.toString().length != 0 : mainItem.icon.source.toString().length != 0
? 2 ? 2
: 3 : 3
width: mainItem.width width: mainItem.width
RowLayout { RowLayout {
spacing: mainItem.spacing spacing: mainItem.spacing
@ -126,5 +196,5 @@ Control.Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
} }
} }*/
} }

View file

@ -10,176 +10,199 @@ import SettingsCpp
// Fill contact, account or call // Fill contact, account or call
// Initials will be displayed if there isn't any avatar. // Initials will be displayed if there isn't any avatar.
// TODO : get FriendGui from Call. // TODO : get FriendGui from Call.
Loader{
StackView {
id: mainItem id: mainItem
property AccountGui account: null property AccountGui account: null
property FriendGui contact: null property FriendGui contact: null
property CallGui call: null property CallGui call: null
property string _address: account property string _address: account
? account.core?.identityAddress || "" ? account.core?.identityAddress || ""
: call : call
? call.core.peerAddress ? call.core.peerAddress
: contact : contact
? contact.core.defaultAddress ? contact.core.defaultAddress
: '' : ''
readonly property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_address) : _address readonly property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_address) : _address
property var displayNameObj: UtilsCpp.getDisplayName(_address) property var displayNameObj: UtilsCpp.getDisplayName(_address)
property string displayNameVal: displayNameObj ? displayNameObj.value : "" property string displayNameVal: displayNameObj ? displayNameObj.value : ""
property bool haveAvatar: (account && account.core?.pictureUri || false) property bool haveAvatar: (account && account.core?.pictureUri || false)
|| (contact && contact.core.pictureUri) || (contact && contact.core.pictureUri)
|| computedAvatarUri.length != 0 || computedAvatarUri.length != 0
property string computedAvatarUri: UtilsCpp.findAvatarByAddress(_address) property string computedAvatarUri: UtilsCpp.findAvatarByAddress(_address)
onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate) onHaveAvatarChanged: replace(haveAvatar ? avatar : initials, StackView.Immediate)
property var securityLevelObj: UtilsCpp.getFriendAddressSecurityLevel(_address) property var securityLevelObj: UtilsCpp.getFriendAddressSecurityLevel(_address)
property var securityLevel: securityLevelObj ? securityLevelObj.value : LinphoneEnums.SecurityLevel.None property var securityLevel: securityLevelObj ? securityLevelObj.value : LinphoneEnums.SecurityLevel.None
property bool secured: call && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp property bool secured: call && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp
? call.core.tokenVerified ? call.core.tokenVerified
: contact : contact
? contact.core.devices.length != 0 && contact.core.verifiedDeviceCount === contact.core.devices.length ? contact.core.devices.length != 0 && contact.core.verifiedDeviceCount === contact.core.devices.length
: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncrypted : 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
initialItem: haveAvatar ? avatar : initials property bool securityBreach: securityLevel === LinphoneEnums.SecurityLevel.Unsafe
Rectangle { property bool displayPresence: account
visible: mainItem.secured || mainItem.securityBreach ? account.core?.registrationState != LinphoneEnums.RegistrationState.Progress && account.core?.registrationState != LinphoneEnums.RegistrationState.Refreshing || false
anchors.fill: mainItem.currentItem : contact
radius: mainItem.width / 2 ? contact.core?.consolidatedPresence != LinphoneEnums.ConsolidatedPresence.Offline || false
z: 1 : false
color: "transparent"
border {
width: 3 * DefaultStyle.dp asynchronous: true
color: mainItem.secured ? DefaultStyle.info_500_main : DefaultStyle.danger_500main sourceComponent: Component{
}
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
Item { Item {
id: avatarItem anchors.fill: parent
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
}
}
MultiEffect { MultiEffect {
source: initialItem source: stackView
anchors.fill: initialItem anchors.fill: stackView
shadowEnabled: true shadowEnabled: true
shadowBlur: 0.1 shadowBlur: 0.1
shadowColor: DefaultStyle.grey_1000 shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.1 shadowOpacity: 0.1
} }
} StackView {
} id: stackView
Component{
id: avatar initialItem: haveAvatar ? avatar : initials
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
anchors.fill: parent 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 { popup.contentItem: ColumnLayout {
Button { 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{} background: Item{}
icon.source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart icon.source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart
icon.width: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp

View file

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

View file

@ -16,8 +16,12 @@ ListView {
property var delegateButtons property var delegateButtons
property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null
signal conferenceSelected(var contact)
spacing: 8 * DefaultStyle.dp spacing: 8 * DefaultStyle.dp
currentIndex: confInfoProxy.currentDateIndex 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 onCountChanged: selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null
onCurrentIndexChanged: { onCurrentIndexChanged: {
@ -27,20 +31,20 @@ ListView {
mainItem.positionViewAtIndex(currentIndex, ListView.Center)// First approximative move mainItem.positionViewAtIndex(currentIndex, ListView.Center)// First approximative move
delayMove.restart() // Move to exact position after load. delayMove.restart() // Move to exact position after load.
} }
onAtYEndChanged: if(atYEnd) confInfoProxy.displayMore()
Timer{ Timer{
id: delayMove id: delayMove
interval: 60 interval: 60
onTriggered: mainItem.positionViewAtIndex(currentIndex, ListView.Center) 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 { model: ConferenceInfoProxy {
id: confInfoProxy id: confInfoProxy
searchText: searchBarText filterText: searchBarText
filterType: ConferenceInfoProxy.None filterType: ConferenceInfoProxy.None
initialDisplayItems: mainItem.height / (63 * DefaultStyle.dp) + 5
displayItemsStep: initialDisplayItems/2
} }
section { section {

View file

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

View file

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

View file

@ -249,4 +249,19 @@ ApplicationWindow {
underlineColor: DefaultStyle.main1_500_main underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp 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
}
}
} }