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 ...@@ -67,10 +67,7 @@ set(SOURCES
src/components/settings/AccountSettingsModel.cpp src/components/settings/AccountSettingsModel.cpp
src/components/settings/SettingsModel.cpp src/components/settings/SettingsModel.cpp
src/components/sip-addresses/SipAddressesModel.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/SmartSearchBarModel.cpp
src/components/smart-search-bar/SmartSearchBarProxyModel.cpp
src/components/timeline/TimelineModel.cpp src/components/timeline/TimelineModel.cpp
src/main.cpp src/main.cpp
) )
...@@ -94,10 +91,7 @@ set(HEADERS ...@@ -94,10 +91,7 @@ set(HEADERS
src/components/settings/AccountSettingsModel.hpp src/components/settings/AccountSettingsModel.hpp
src/components/settings/SettingsModel.hpp src/components/settings/SettingsModel.hpp
src/components/sip-addresses/SipAddressesModel.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/SmartSearchBarModel.hpp
src/components/smart-search-bar/SmartSearchBarProxyModel.hpp
src/components/timeline/TimelineModel.hpp src/components/timeline/TimelineModel.hpp
src/utils.hpp src/utils.hpp
) )
......
...@@ -10,9 +10,8 @@ ...@@ -10,9 +10,8 @@
#include "../components/core/CoreManager.hpp" #include "../components/core/CoreManager.hpp"
#include "../components/notifier/Notifier.hpp" #include "../components/notifier/Notifier.hpp"
#include "../components/settings/AccountSettingsModel.hpp" #include "../components/settings/AccountSettingsModel.hpp"
#include "../components/sip-addresses/UnregisteredSipAddressesProxyModel.hpp"
#include "../components/timeline/TimelineModel.hpp" #include "../components/timeline/TimelineModel.hpp"
#include "../components/smart-search-bar/SmartSearchBarProxyModel.hpp" #include "../components/smart-search-bar/SmartSearchBarModel.hpp"
#include "App.hpp" #include "App.hpp"
...@@ -143,8 +142,7 @@ void App::registerTypes () { ...@@ -143,8 +142,7 @@ void App::registerTypes () {
qmlRegisterType<ContactsListProxyModel>("Linphone", 1, 0, "ContactsListProxyModel"); qmlRegisterType<ContactsListProxyModel>("Linphone", 1, 0, "ContactsListProxyModel");
qmlRegisterType<ChatModel>("Linphone", 1, 0, "ChatModel"); qmlRegisterType<ChatModel>("Linphone", 1, 0, "ChatModel");
qmlRegisterType<ChatProxyModel>("Linphone", 1, 0, "ChatProxyModel"); qmlRegisterType<ChatProxyModel>("Linphone", 1, 0, "ChatProxyModel");
qmlRegisterType<UnregisteredSipAddressesProxyModel>("Linphone", 1, 0, "UnregisteredSipAddressesProxyModel"); qmlRegisterType<SmartSearchBarModel>("Linphone", 1, 0, "SmartSearchBarModel");
qmlRegisterType<SmartSearchBarProxyModel>("Linphone", 1, 0, "SmartSearchBarProxyModel");
qRegisterMetaType<ChatModel::EntryType>("ChatModel::EntryType"); qRegisterMetaType<ChatModel::EntryType>("ChatModel::EntryType");
} }
......
...@@ -15,6 +15,7 @@ class ContactModel : public QObject { ...@@ -15,6 +15,7 @@ class ContactModel : public QObject {
friend class ContactsListModel; friend class ContactsListModel;
friend class ContactsListProxyModel; friend class ContactsListProxyModel;
friend class SmartSearchBarModel;
public: public:
ContactModel (std::shared_ptr<linphone::Friend> linphone_friend); ContactModel (std::shared_ptr<linphone::Friend> linphone_friend);
......
...@@ -35,7 +35,6 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr ...@@ -35,7 +35,6 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr
m_list = CoreManager::getInstance()->getContactsListModel(); m_list = CoreManager::getInstance()->getContactsListModel();
setSourceModel(m_list); setSourceModel(m_list);
setDynamicSortFilter(false);
for (const ContactModel *contact : m_list->m_list) for (const ContactModel *contact : m_list->m_list)
m_weights[contact] = 0; m_weights[contact] = 0;
...@@ -43,11 +42,20 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr ...@@ -43,11 +42,20 @@ ContactsListProxyModel::ContactsListProxyModel (QObject *parent) : QSortFilterPr
sort(0); sort(0);
} }
// -----------------------------------------------------------------------------
void ContactsListProxyModel::setFilter (const QString &pattern) {
m_filter = pattern;
invalidate();
}
// -----------------------------------------------------------------------------
bool ContactsListProxyModel::filterAcceptsRow ( bool ContactsListProxyModel::filterAcceptsRow (
int source_row, int source_row,
const QModelIndex &source_parent const QModelIndex &source_parent
) const { ) 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 *>(); const ContactModel *contact = index.data().value<ContactModel *>();
m_weights[contact] = static_cast<unsigned int>(computeContactWeight(*contact)); m_weights[contact] = static_cast<unsigned int>(computeContactWeight(*contact));
...@@ -79,7 +87,7 @@ float ContactsListProxyModel::computeStringWeight (const QString &string, float ...@@ -79,7 +87,7 @@ float ContactsListProxyModel::computeStringWeight (const QString &string, float
int offset = -1; int offset = -1;
// Search pattern. // 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. // Search n chars between one separator and index.
int tmp_offset = index - string.lastIndexOf(m_search_separators, index) - 1; int tmp_offset = index - string.lastIndexOf(m_search_separators, index) - 1;
......
...@@ -23,10 +23,7 @@ public: ...@@ -23,10 +23,7 @@ public:
~ContactsListProxyModel () = default; ~ContactsListProxyModel () = default;
public slots: public slots:
void setFilter (const QString &pattern) { void setFilter (const QString &pattern);
setFilterFixedString(pattern);
invalidate();
}
protected: protected:
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override; bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
...@@ -43,6 +40,7 @@ private: ...@@ -43,6 +40,7 @@ private:
void setConnectedFilter (bool use_connected_filter); void setConnectedFilter (bool use_connected_filter);
ContactsListModel *m_list; ContactsListModel *m_list;
QString m_filter;
bool m_use_connected_filter = false; bool m_use_connected_filter = false;
// It's just a cache to save values computed by `filterAcceptsRow` // It's just a cache to save values computed by `filterAcceptsRow`
......
...@@ -19,7 +19,6 @@ void CoreManager::init () { ...@@ -19,7 +19,6 @@ void CoreManager::init () {
m_instance->m_contacts_list_model = new ContactsListModel(m_instance); m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(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 @@ ...@@ -4,7 +4,6 @@
#include "../contact/VcardModel.hpp" #include "../contact/VcardModel.hpp"
#include "../contacts/ContactsListModel.hpp" #include "../contacts/ContactsListModel.hpp"
#include "../sip-addresses/SipAddressesModel.hpp" #include "../sip-addresses/SipAddressesModel.hpp"
#include "../sip-addresses/UnregisteredSipAddressesModel.hpp"
// ============================================================================= // =============================================================================
...@@ -30,10 +29,6 @@ public: ...@@ -30,10 +29,6 @@ public:
return m_sip_addresses_model; return m_sip_addresses_model;
} }
UnregisteredSipAddressesModel *getUnregisteredSipAddressesModel () {
return m_unregistered_sip_addresses_model;
}
static void init (); static void init ();
static CoreManager *getInstance () { static CoreManager *getInstance () {
...@@ -53,7 +48,6 @@ private: ...@@ -53,7 +48,6 @@ private:
std::shared_ptr<linphone::Core> m_core; std::shared_ptr<linphone::Core> m_core;
ContactsListModel *m_contacts_list_model; ContactsListModel *m_contacts_list_model;
SipAddressesModel *m_sip_addresses_model; SipAddressesModel *m_sip_addresses_model;
UnregisteredSipAddressesModel *m_unregistered_sip_addresses_model;
static CoreManager *m_instance; 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" #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 { const QRegExp SmartSearchBarModel::m_search_separators("^[^_.-;@ ][_.-;@ ]");
return m_contacts.rowCount() + m_sip_addresses.rowCount();
// -----------------------------------------------------------------------------
SmartSearchBarModel::SmartSearchBarModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getSipAddressesModel());
sort(0);
} }
QHash<int, QByteArray> SmartSearchBarModel::roleNames () const { QHash<int, QByteArray> SmartSearchBarModel::roleNames () const {
...@@ -12,20 +25,78 @@ QHash<int, QByteArray> SmartSearchBarModel::roleNames () const { ...@@ -12,20 +25,78 @@ QHash<int, QByteArray> SmartSearchBarModel::roleNames () const {
return roles; return roles;
} }
QVariant SmartSearchBarModel::data (const QModelIndex &index, int role) const { // -----------------------------------------------------------------------------
int row = index.row();
int n_contacts = m_contacts.rowCount(); void SmartSearchBarModel::setFilter (const QString &pattern) {
int n_sip_addresses = m_sip_addresses.rowCount(); 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) const QString &sip_address_a = map_a["sipAddress"].toString();
return QVariant(); const QString &sip_address_b = map_b["sipAddress"].toString();
if (role == Qt::DisplayRole) { int weight_a = computeStringWeight(sip_address_a);
if (row < n_contacts) int weight_b = computeStringWeight(sip_address_b);
return QVariant::fromValue(m_contacts.data(m_contacts.index(row, 0), role));
// 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_ #ifndef SMART_SEARCH_BAR_MODEL_H_
#define SMART_SEARCH_BAR_MODEL_H_ #define SMART_SEARCH_BAR_MODEL_H_
#include <QAbstractListModel> #include <QSortFilterProxyModel>
#include "../contacts/ContactsListProxyModel.hpp" #include "../sip-addresses/SipAddressesModel.hpp"
#include "../sip-addresses/UnregisteredSipAddressesProxyModel.hpp"
// ============================================================================= // =============================================================================
class SmartSearchBarModel : public QAbstractListModel { class SmartSearchBarModel : public QSortFilterProxyModel {
Q_OBJECT; Q_OBJECT;
public: public:
SmartSearchBarModel (QObject *parent = Q_NULLPTR) : QAbstractListModel(parent) {} SmartSearchBarModel (QObject *parent = Q_NULLPTR);
~SmartSearchBarModel () = default;
virtual ~SmartSearchBarModel () = default;
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override; QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role) const override;
public slots:
void setFilter (const QString &pattern);
protected: protected:
ContactsListProxyModel m_contacts; bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const override;
UnregisteredSipAddressesProxyModel m_sip_addresses; 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_ #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 { ...@@ -18,8 +18,10 @@ QHash<int, QByteArray> TimelineModel::roleNames () const {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool TimelineModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const { bool TimelineModel::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);
return index.data().toMap().contains("timestamp"); const QVariantMap &map = index.data().toMap();
return map.contains("timestamp");
} }
bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const { bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
......
...@@ -14,7 +14,7 @@ SearchBox { ...@@ -14,7 +14,7 @@ SearchBox {
id: searchBoxEntry id: searchBoxEntry
height: searchBox.entryHeight height: searchBox.entryHeight
width: parent.width width: parent ? parent.width : 0
Rectangle { Rectangle {
id: indicator id: indicator
...@@ -47,9 +47,9 @@ SearchBox { ...@@ -47,9 +47,9 @@ SearchBox {
id: avatar id: avatar
Layout.preferredHeight: 30 Layout.preferredHeight: 30
Layout.preferredWidth: 30 Layout.preferredWidth: 30
image: $entry.vcard && $entry.vcard.avatar image: $entry.contact && $entry.contact.vcard.avatar
presenceLevel: $entry.presenceLevel != null ? $entry.presenceLevel : -1 presenceLevel: $entry.contact ? $entry.contact.presenceLevel : -1
username: LinphoneUtils.getContactUsername($entry.sipAddress || $entry) username: LinphoneUtils.getContactUsername($entry.contact || $entry.sipAddress)
} }
Text { Text {
...@@ -62,7 +62,7 @@ SearchBox { ...@@ -62,7 +62,7 @@ SearchBox {
pointSize: 9 pointSize: 9
} }
text: $entry.vcard ? $entry.vcard.username : $entry.sipAddress text: $entry.contact ? $entry.contact.vcard.username : $entry.sipAddress
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
......
...@@ -145,7 +145,7 @@ ApplicationWindow { ...@@ -145,7 +145,7 @@ ApplicationWindow {
maxMenuHeight: MainWindowStyle.searchBox.maxHeight maxMenuHeight: MainWindowStyle.searchBox.maxHeight
placeholderText: qsTr('mainSearchBarPlaceholder') 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