SmartSearchBarModel.cpp 3.5 KB
Newer Older
Ronan Abhamon's avatar
Ronan Abhamon committed
1 2
#include "../core/CoreManager.hpp"

3 4
#include "SmartSearchBarModel.hpp"

Ronan Abhamon's avatar
Ronan Abhamon committed
5 6 7 8 9 10
#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

11 12
// =============================================================================

Ronan Abhamon's avatar
Ronan Abhamon committed
13 14 15 16 17 18 19
const QRegExp SmartSearchBarModel::m_search_separators("^[^_.-;@ ][_.-;@ ]");

// -----------------------------------------------------------------------------

SmartSearchBarModel::SmartSearchBarModel (QObject *parent) : QSortFilterProxyModel(parent) {
  setSourceModel(CoreManager::getInstance()->getSipAddressesModel());
  sort(0);
20 21 22 23 24 25 26 27
}

QHash<int, QByteArray> SmartSearchBarModel::roleNames () const {
  QHash<int, QByteArray> roles;
  roles[Qt::DisplayRole] = "$entry";
  return roles;
}

Ronan Abhamon's avatar
Ronan Abhamon committed
28 29 30 31 32 33 34 35 36 37
// -----------------------------------------------------------------------------

void SmartSearchBarModel::setFilter (const QString &pattern) {
  m_filter = pattern;
  invalidate();
}

// -----------------------------------------------------------------------------

bool SmartSearchBarModel::filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
38
  const QModelIndex &index = sourceModel()->index(source_row, 0, source_parent);
39
  return computeEntryWeight(index.data().toMap()) > 0;
Ronan Abhamon's avatar
Ronan Abhamon committed
40 41 42
}

bool SmartSearchBarModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
43 44
  const QVariantMap &map_a = sourceModel()->data(left).toMap();
  const QVariantMap &map_b = sourceModel()->data(right).toMap();
45

46 47
  const QString &sip_address_a = map_a["sipAddress"].toString();
  const QString &sip_address_b = map_b["sipAddress"].toString();
48

49 50 51
  // TODO: Use a cache, do not compute the same value as `filterAcceptsRow`.
  int weight_a = computeEntryWeight(map_a);
  int weight_b = computeEntryWeight(map_b);
Ronan Abhamon's avatar
Ronan Abhamon committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

  // 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;
}

81 82 83 84 85 86 87 88 89 90
int SmartSearchBarModel::computeEntryWeight (const QVariantMap &entry) const {
  int weight = computeStringWeight(entry["sipAddress"].toString().mid(4));

  const ContactModel *contact = entry.value("contact").value<ContactModel *>();
  if (contact)
    weight += computeStringWeight(contact->getVcardModel()->getUsername());

  return weight;
}

Ronan Abhamon's avatar
Ronan Abhamon committed
91 92 93 94 95 96 97 98 99
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;
  }
100

Ronan Abhamon's avatar
Ronan Abhamon committed
101 102 103 104 105 106 107
  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;
108 109
  }

Ronan Abhamon's avatar
Ronan Abhamon committed
110
  return WEIGHT_POS_OTHER;
111
}