Commit 8240c265 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(app):

  - better `SmartSearchBarModel`, it uses only `SipAddressesModel`
  - remove useless `UnregisteredSipAddresses[Proxy]Model`
  - little fixes
  - ...
parent c27e33a1
......@@ -67,10 +67,7 @@ set(SOURCES
src/components/settings/AccountSettingsModel.cpp
src/components/settings/SettingsModel.cpp
src/components/sip-addresses/SipAddressesModel.cpp
src/components/sip-addresses/UnregisteredSipAddressesModel.cpp
src/components/sip-addresses/UnregisteredSipAddressesProxyModel.cpp
src/components/smart-search-bar/SmartSearchBarModel.cpp
src/components/smart-search-bar/SmartSearchBarProxyModel.cpp
src/components/timeline/TimelineModel.cpp
src/main.cpp
)
......@@ -94,10 +91,7 @@ set(HEADERS
src/components/settings/AccountSettingsModel.hpp
src/components/settings/SettingsModel.hpp
src/components/sip-addresses/SipAddressesModel.hpp
src/components/sip-addresses/UnregisteredSipAddressesModel.hpp
src/components/sip-addresses/UnregisteredSipAddressesProxyModel.hpp
src/components/smart-search-bar/SmartSearchBarModel.hpp
src/components/smart-search-bar/SmartSearchBarProxyModel.hpp
src/components/timeline/TimelineModel.hpp
src/utils.hpp
)
......
......@@ -10,9 +10,8 @@
#include "../components/core/CoreManager.hpp"
#include "../components/notifier/Notifier.hpp"
#include "../components/settings/AccountSettingsModel.hpp"
#include "../components/sip-addresses/UnregisteredSipAddressesProxyModel.hpp"
#include "../components/timeline/TimelineModel.hpp"
#include "../components/smart-search-bar/SmartSearchBarProxyModel.hpp"
#include "../components/smart-search-bar/SmartSearchBarModel.hpp"
#include "App.hpp"
......@@ -143,8 +142,7 @@ void App::registerTypes () {
qmlRegisterType<ContactsListProxyModel>("Linphone", 1, 0, "ContactsListProxyModel");
qmlRegisterType<ChatModel>("Linphone", 1, 0, "ChatModel");
qmlRegisterType<ChatProxyModel>("Linphone", 1, 0, "ChatProxyModel");
qmlRegisterType<UnregisteredSipAddressesProxyModel>("Linphone", 1, 0, "UnregisteredSipAddressesProxyModel");
qmlRegisterType<SmartSearchBarProxyModel>("Linphone", 1, 0, "SmartSearchBarProxyModel");
qmlRegisterType<SmartSearchBarModel>("Linphone", 1, 0, "SmartSearchBarModel");
qRegisterMetaType<ChatModel::EntryType>("ChatModel::EntryType");
}
......
......@@ -15,6 +15,7 @@ class ContactModel : public QObject {
friend class ContactsListModel;
friend class ContactsListProxyModel;
friend class SmartSearchBarModel;
public:
ContactModel (std::shared_ptr<linphone::Friend> linphone_friend);
......
......@@ -35,7 +35,6 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr
m_list = CoreManager::getInstance()->getContactsListModel();
setSourceModel(m_list);
setDynamicSortFilter(false);
for (const ContactModel *contact : m_list->m_list)
m_weights[contact] = 0;
......@@ -43,11 +42,20 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr
sort(0);
}
// -----------------------------------------------------------------------------
void ContactsListProxyModel::setFilter (const QString &pattern) {
m_filter = pattern;
invalidate();
}
// -----------------------------------------------------------------------------
bool ContactsListProxyModel::filterAcceptsRow (
int source_row,
const QModelIndex &source_parent
) const {
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
const QModelIndex &index = sourceModel()->index(source_row, 0, source_parent);
const ContactModel *contact = index.data().value<ContactModel *>();
m_weights[contact] = static_cast<unsigned int>(computeContactWeight(*contact));
......@@ -79,7 +87,7 @@ float ContactsListProxyModel::computeStringWeight (const QString &string, float
int offset = -1;
// Search pattern.
while ((index = filterRegExp().indexIn(string, index + 1)) != -1) {
while ((index = string.indexOf(m_filter, index + 1, Qt::CaseInsensitive)) != -1) {
// Search n chars between one separator and index.
int tmp_offset = index - string.lastIndexOf(m_search_separators, index) - 1;
......
......@@ -23,10 +23,7 @@ public:
~ContactsListProxyModel () = default;
public slots:
void setFilter (const QString &pattern) {
setFilterFixedString(pattern);
invalidate();
}
void setFilter (const QString &pattern);
protected:
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
......@@ -43,6 +40,7 @@ private:
void setConnectedFilter (bool use_connected_filter);
ContactsListModel *m_list;
QString m_filter;
bool m_use_connected_filter = false;
// It's just a cache to save values computed by `filterAcceptsRow`
......
......@@ -19,7 +19,6 @@ void CoreManager::init () {
m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance);
m_instance->m_unregistered_sip_addresses_model = new UnregisteredSipAddressesModel(m_instance);
}
}
......
......@@ -4,7 +4,6 @@
#include "../contact/VcardModel.hpp"
#include "../contacts/ContactsListModel.hpp"
#include "../sip-addresses/SipAddressesModel.hpp"
#include "../sip-addresses/UnregisteredSipAddressesModel.hpp"
// =============================================================================
......@@ -30,10 +29,6 @@ public:
return m_sip_addresses_model;
}
UnregisteredSipAddressesModel *getUnregisteredSipAddressesModel () {
return m_unregistered_sip_addresses_model;
}
static void init ();
static CoreManager *getInstance () {
......@@ -53,7 +48,6 @@ private:
std::shared_ptr<linphone::Core> m_core;
ContactsListModel *m_contacts_list_model;
SipAddressesModel *m_sip_addresses_model;
UnregisteredSipAddressesModel *m_unregistered_sip_addresses_model;
static CoreManager *m_instance;
};
......
#include "../core/CoreManager.hpp"
#include "UnregisteredSipAddressesModel.hpp"
// =============================================================================
UnregisteredSipAddressesModel::UnregisteredSipAddressesModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getSipAddressesModel());
}
bool UnregisteredSipAddressesModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
return !index.data().toMap().contains("contact");
}
#ifndef UNREGISTERED_SIP_ADDRESSES_MODEL_H_
#define UNREGISTERED_SIP_ADDRESSES_MODEL_H_
#include <QSortFilterProxyModel>
// =============================================================================
class UnregisteredSipAddressesModel : public QSortFilterProxyModel {
Q_OBJECT;
public:
UnregisteredSipAddressesModel (QObject *parent = Q_NULLPTR);
~UnregisteredSipAddressesModel () = default;
protected:
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
};
#endif // UNREGISTERED_SIP_ADDRESSES_MODEL_H_
#include "../core/CoreManager.hpp"
#include "UnregisteredSipAddressesProxyModel.hpp"
#define WEIGHT_POS_0 5
#define WEIGHT_POS_1 4
#define WEIGHT_POS_2 3
#define WEIGHT_POS_3 2
#define WEIGHT_POS_OTHER 1
// =============================================================================
const QRegExp UnregisteredSipAddressesProxyModel::m_search_separators("^[^_.-;@ ][_.-;@ ]");
// -----------------------------------------------------------------------------
UnregisteredSipAddressesProxyModel::UnregisteredSipAddressesProxyModel (QObject *parent) :
QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getUnregisteredSipAddressesModel());
setDynamicSortFilter(false);
sort(0);
}
bool UnregisteredSipAddressesProxyModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
return computeStringWeight(index.data().toMap()["sipAddress"].toString()) > 0;
}
bool UnregisteredSipAddressesProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
QString sip_address_a = sourceModel()->data(left).toMap()["sipAddress"].toString();
QString sip_address_b = sourceModel()->data(right).toMap()["sipAddress"].toString();
int weight_a = computeStringWeight(sip_address_a);
int weight_b = computeStringWeight(sip_address_b);
return weight_a > weight_b || (
weight_a == weight_b && sip_address_a >= sip_address_b
);
}
int UnregisteredSipAddressesProxyModel::computeStringWeight (const QString &string) const {
int index = -1;
int offset = -1;
while ((index = filterRegExp().indexIn(string, index + 1)) != -1) {
int tmp_offset = index - string.lastIndexOf(m_search_separators, index) - 1;
if ((tmp_offset != -1 && tmp_offset < offset) || offset == -1)
if ((offset = tmp_offset) == 0) break;
}
switch (offset) {
case -1: return 0;
case 0: return WEIGHT_POS_0;
case 1: return WEIGHT_POS_1;
case 2: return WEIGHT_POS_2;
case 3: return WEIGHT_POS_3;
default: break;
}
return WEIGHT_POS_OTHER;
}
#ifndef UNREGISTERED_SIP_ADDRESSES_PROXY_MODEL_H_
#define UNREGISTERED_SIP_ADDRESSES_PROXY_MODEL_H_
#include "UnregisteredSipAddressesModel.hpp"
// =============================================================================
class UnregisteredSipAddressesProxyModel : public QSortFilterProxyModel {
Q_OBJECT;
public:
UnregisteredSipAddressesProxyModel (QObject *parent = Q_NULLPTR);
~UnregisteredSipAddressesProxyModel () = default;
public slots:
void setFilter (const QString &pattern) {
setFilterFixedString(pattern);
invalidate();
}
protected:
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
private:
int computeStringWeight (const QString &string) const;
static const QRegExp m_search_separators;
};
#endif // UNREGISTERED_SIP_ADDRESSES_PROXY_MODEL_H_
#include "../core/CoreManager.hpp"
#include "SmartSearchBarModel.hpp"
#define WEIGHT_POS_0 5
#define WEIGHT_POS_1 4
#define WEIGHT_POS_2 3
#define WEIGHT_POS_3 2
#define WEIGHT_POS_OTHER 1
// =============================================================================
int SmartSearchBarModel::rowCount (const QModelIndex &) const {
return m_contacts.rowCount() + m_sip_addresses.rowCount();
const QRegExp SmartSearchBarModel::m_search_separators("^[^_.-;@ ][_.-;@ ]");
// -----------------------------------------------------------------------------
SmartSearchBarModel::SmartSearchBarModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getSipAddressesModel());
sort(0);
}
QHash<int, QByteArray> SmartSearchBarModel::roleNames () const {
......@@ -12,20 +25,78 @@ QHash<int, QByteArray> SmartSearchBarModel::roleNames () const {
return roles;
}
QVariant SmartSearchBarModel::data (const QModelIndex &index, int role) const {
int row = index.row();
int n_contacts = m_contacts.rowCount();
int n_sip_addresses = m_sip_addresses.rowCount();
// -----------------------------------------------------------------------------
void SmartSearchBarModel::setFilter (const QString &pattern) {
m_filter = pattern;
invalidate();
}
// -----------------------------------------------------------------------------
bool SmartSearchBarModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
const QModelIndex &index = sourceModel()->index(source_row, 0, source_parent);
const QVariantMap &map = index.data().toMap();
return computeStringWeight(map["sipAddress"].toString()) > 0;
}
bool SmartSearchBarModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const QVariantMap &map_a = sourceModel()->data(left).toMap();
const QVariantMap &map_b = sourceModel()->data(right).toMap();
if (row < 0 || row >= n_contacts + n_sip_addresses)
return QVariant();
const QString &sip_address_a = map_a["sipAddress"].toString();
const QString &sip_address_b = map_b["sipAddress"].toString();
if (role == Qt::DisplayRole) {
if (row < n_contacts)
return QVariant::fromValue(m_contacts.data(m_contacts.index(row, 0), role));
int weight_a = computeStringWeight(sip_address_a);
int weight_b = computeStringWeight(sip_address_b);
// 1. Not the same weight.
if (weight_a != weight_b)
return weight_a > weight_b;
const ContactModel *contact_a = map_a.value("contact").value<ContactModel *>();
const ContactModel *contact_b = map_b.value("contact").value<ContactModel *>();
// 2. No contacts.
if (!contact_a && !contact_b)
return sip_address_a <= sip_address_b;
// 3. No contact for a or b.
if (!contact_a || !contact_b)
return !!contact_a;
// 4. Same contact (address).
if (contact_a == contact_b)
return sip_address_a <= sip_address_b;
// 5. Not the same contact name.
int diff = contact_a->m_linphone_friend->getName().compare(contact_b->m_linphone_friend->getName());
if (diff)
return diff <= 0;
// 6. Same contact name, so compare sip addresses.
return sip_address_a <= sip_address_b;
}
int SmartSearchBarModel::computeStringWeight (const QString &string) const {
int index = -1;
int offset = -1;
while ((index = string.indexOf(m_filter, index + 1, Qt::CaseInsensitive)) != -1) {
int tmp_offset = index - string.lastIndexOf(m_search_separators, index) - 1;
if ((tmp_offset != -1 && tmp_offset < offset) || offset == -1)
if ((offset = tmp_offset) == 0) break;
}
return QVariant::fromValue(m_sip_addresses.data(m_sip_addresses.index(row - n_contacts, 0), role));
switch (offset) {
case -1: return 0;
case 0: return WEIGHT_POS_0;
case 1: return WEIGHT_POS_1;
case 2: return WEIGHT_POS_2;
case 3: return WEIGHT_POS_3;
default: break;
}
return QVariant();
return WEIGHT_POS_OTHER;
}
#ifndef SMART_SEARCH_BAR_MODEL_H_
#define SMART_SEARCH_BAR_MODEL_H_
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
#include "../contacts/ContactsListProxyModel.hpp"
#include "../sip-addresses/UnregisteredSipAddressesProxyModel.hpp"
#include "../sip-addresses/SipAddressesModel.hpp"
// =============================================================================
class SmartSearchBarModel : public QAbstractListModel {
class SmartSearchBarModel : public QSortFilterProxyModel {
Q_OBJECT;
public:
SmartSearchBarModel (QObject *parent = Q_NULLPTR) : QAbstractListModel(parent) {}
virtual ~SmartSearchBarModel () = default;
int rowCount (const QModelIndex &index = QModelIndex()) const override;
SmartSearchBarModel (QObject *parent = Q_NULLPTR);
~SmartSearchBarModel () = default;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role) const override;
public slots:
void setFilter (const QString &pattern);
protected:
ContactsListProxyModel m_contacts;
UnregisteredSipAddressesProxyModel m_sip_addresses;
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
private:
int computeStringWeight (const QString &string) const;
QString m_filter;
static const QRegExp m_search_separators;
};
#endif // SMART_SEARCH_BAR_MODEL_H_
#include "SmartSearchBarProxyModel.hpp"
// =============================================================================
void SmartSearchBarProxyModel::setFilter (const QString &pattern) {
m_contacts.setFilter(pattern);
m_sip_addresses.setFilter(pattern);
}
#ifndef SMART_SEARCH_BAR_PROXY_MODEL_H_
#define SMART_SEARCH_BAR_PROXY_MODEL_H_
#include "SmartSearchBarModel.hpp"
// =============================================================================
class SmartSearchBarProxyModel : public SmartSearchBarModel {
Q_OBJECT;
public:
SmartSearchBarProxyModel (QObject *parent = Q_NULLPTR) : SmartSearchBarModel(parent) {}
~SmartSearchBarProxyModel () = default;
public slots:
void setFilter (const QString &pattern);
};
#endif // SMART_SEARCH_BAR_PROXY_MODEL_H_
......@@ -18,8 +18,10 @@ QHash<int, QByteArray> TimelineModel::roleNames () const {
// -----------------------------------------------------------------------------
bool TimelineModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
return index.data().toMap().contains("timestamp");
const QModelIndex &index = sourceModel()->index(source_row, 0, source_parent);
const QVariantMap &map = index.data().toMap();
return map.contains("timestamp");
}
bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
......
......@@ -14,7 +14,7 @@ SearchBox {
id: searchBoxEntry
height: searchBox.entryHeight
width: parent.width
width: parent ? parent.width : 0
Rectangle {
id: indicator
......@@ -47,9 +47,9 @@ SearchBox {
id: avatar
Layout.preferredHeight: 30
Layout.preferredWidth: 30
image: $entry.vcard && $entry.vcard.avatar
presenceLevel: $entry.presenceLevel != null ? $entry.presenceLevel : -1
username: LinphoneUtils.getContactUsername($entry.sipAddress || $entry)
image: $entry.contact && $entry.contact.vcard.avatar
presenceLevel: $entry.contact ? $entry.contact.presenceLevel : -1
username: LinphoneUtils.getContactUsername($entry.contact || $entry.sipAddress)
}
Text {
......@@ -62,7 +62,7 @@ SearchBox {
pointSize: 9
}
text: $entry.vcard ? $entry.vcard.username : $entry.sipAddress
text: $entry.contact ? $entry.contact.vcard.username : $entry.sipAddress
}
// ---------------------------------------------------------------------
......
......@@ -145,7 +145,7 @@ ApplicationWindow {
maxMenuHeight: MainWindowStyle.searchBox.maxHeight
placeholderText: qsTr('mainSearchBarPlaceholder')
model: SmartSearchBarProxyModel {}
model: SmartSearchBarModel {}
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment