presentation/QuickContactModel.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "QuickContactModel.h" | ||
| 2 | |||
| 3 | #include "ContactEditorFields.h" | ||
| 4 | #include "ContactPeopleView.h" | ||
| 5 | #include "data/ContactIndex.h" | ||
| 6 | #include "data/ContactStore.h" | ||
| 7 | #include "data/VCardCodec.h" | ||
| 8 | #include "util/MailboxText.h" | ||
| 9 | |||
| 10 | #include <QMetaObject> | ||
| 11 | #include <QSet> | ||
| 12 | #include <QSettings> | ||
| 13 | #include <algorithm> | ||
| 14 | |||
| 15 | namespace { | ||
| 16 | |||
| 17 | 1866 | QString initialsOf(const QString &displayName) { | |
| 18 |
1/1✓ Branch 5 → 6 taken 1866 times.
|
1866 | const QStringList words = displayName.split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| 19 | 1866 | QString result; | |
| 20 |
5/9✓ Branch 6 → 7 taken 1866 times.
✓ Branch 8 → 9 taken 1857 times.
✓ Branch 8 → 11 taken 9 times.
✓ Branch 24 → 14 taken 3732 times.
✓ Branch 24 → 25 taken 1866 times.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 44 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
|
9330 | for (const QString &word : {words.value(0), words.size() > 1 ? words.last() : QString()}) |
| 21 |
2/2✓ Branch 22 → 16 taken 3723 times.
✓ Branch 22 → 23 taken 9 times.
|
3732 | for (const QChar c : word) |
| 22 |
1/2✓ Branch 17 → 18 taken 3723 times.
✗ Branch 17 → 21 not taken.
|
3723 | if (c.isLetterOrNumber()) { |
| 23 |
1/1✓ Branch 19 → 20 taken 3723 times.
|
3723 | result += c.toUpper(); |
| 24 | 3723 | break; | |
| 25 | 5598 | } | |
| 26 |
1/1✓ Branch 31 → 32 taken 1866 times.
|
3732 | return result.left(2); |
| 27 | 1866 | } | |
| 28 | |||
| 29 | 863 | ContactQueries::View viewFromMap(const QVariantMap &map, bool byFamily) { | |
| 30 | 863 | ContactQueries::View view; | |
| 31 |
2/2✓ Branch 6 → 7 taken 863 times.
✓ Branch 7 → 8 taken 863 times.
|
1726 | const QString kind = map.value(QStringLiteral("kind")).toString(); |
| 32 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 863 times.
|
863 | if (kind == QLatin1String("frequent")) |
| 33 | ✗ | view.kind = ContactQueries::ViewKind::Frequent; | |
| 34 |
2/2✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 20 taken 860 times.
|
863 | else if (kind == QLatin1String("collected")) |
| 35 | 3 | view.kind = ContactQueries::ViewKind::Collected; | |
| 36 |
2/2✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 859 times.
|
860 | else if (kind == QLatin1String("book")) |
| 37 | 1 | view.kind = ContactQueries::ViewKind::Book; | |
| 38 |
2/2✓ Branch 26 → 27 taken 2 times.
✓ Branch 26 → 28 taken 857 times.
|
859 | else if (kind == QLatin1String("group")) |
| 39 | 2 | view.kind = ContactQueries::ViewKind::Group; | |
| 40 |
2/2✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 32 taken 856 times.
|
857 | else if (kind == QLatin1String("duplicates")) |
| 41 | 1 | view.kind = ContactQueries::ViewKind::Duplicates; | |
| 42 |
2/2✓ Branch 34 → 35 taken 1 time.
✓ Branch 34 → 36 taken 855 times.
|
856 | else if (kind == QLatin1String("ungrouped")) |
| 43 | 1 | view.kind = ContactQueries::ViewKind::Ungrouped; | |
| 44 |
2/2✓ Branch 40 → 41 taken 863 times.
✓ Branch 41 → 42 taken 863 times.
|
1726 | view.bookId = map.value(QStringLiteral("bookId")).toLongLong(); |
| 45 |
2/2✓ Branch 50 → 51 taken 863 times.
✓ Branch 51 → 52 taken 863 times.
|
1726 | view.group = map.value(QStringLiteral("group")).toString(); |
| 46 | 863 | view.byFamilyName = byFamily; | |
| 47 | 863 | return view; | |
| 48 | 863 | } | |
| 49 | |||
| 50 | // S106-310: the in-memory order is the SQL order (ContactQueries::sortKeyLess). | ||
| 51 | 101 | bool before(const ContactQueries::Row &a, const ContactQueries::Row &b) { | |
| 52 |
2/2✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 97 times.
|
101 | return a.sortKey == b.sortKey ? a.cardId < b.cardId : ContactQueries::sortKeyLess(a.sortKey, b.sortKey); |
| 53 | } | ||
| 54 | |||
| 55 | } // namespace | ||
| 56 | |||
| 57 | 854 | QuickContactModel::QuickContactModel(QString databasePath, QObject *parent) | |
| 58 |
2/2✓ Branch 10 → 11 taken 854 times.
✓ Branch 11 → 12 taken 854 times.
|
854 | : QAbstractListModel(parent), m_databasePath(std::move(databasePath)) { |
| 59 |
1/1✓ Branch 14 → 15 taken 854 times.
|
854 | m_pool.setMaxThreadCount(1); |
| 60 |
1/1✓ Branch 15 → 16 taken 854 times.
|
854 | m_completionPool.setMaxThreadCount(1); |
| 61 | // S97.3.7: the last view and sort order survive a restart. | ||
| 62 |
1/1✓ Branch 16 → 17 taken 854 times.
|
854 | const QSettings settings; |
| 63 |
3/3✓ Branch 28 → 29 taken 854 times.
✓ Branch 29 → 30 taken 854 times.
✓ Branch 30 → 31 taken 854 times.
|
1708 | m_view = viewFromMap(settings.value(QStringLiteral("contacts/view")).toMap(), |
| 64 |
2/2✓ Branch 22 → 23 taken 854 times.
✓ Branch 23 → 24 taken 854 times.
|
3416 | settings.value(QStringLiteral("contacts/sortByFamilyName"), false).toBool()); |
| 65 | // F100-10/F100-13: the chosen columns and the pane width. | ||
| 66 |
3/3✓ Branch 45 → 46 taken 854 times.
✓ Branch 48 → 49 taken 1 time.
✓ Branch 48 → 61 taken 853 times.
|
854 | if (settings.contains(QStringLiteral("contacts/columns"))) |
| 67 |
2/2✓ Branch 53 → 54 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
|
1 | m_columns = settings.value(QStringLiteral("contacts/columns")).toStringList(); |
| 68 | else | ||
| 69 |
2/4✓ Branch 72 → 73 taken 2559 times.
✓ Branch 72 → 74 taken 853 times.
✗ Branch 141 → 142 not taken.
✗ Branch 141 → 143 not taken.
|
3412 | m_columns = {QStringLiteral("email"), QStringLiteral("organization"), QStringLiteral("book")}; |
| 70 |
2/2✓ Branch 2 → 3 taken 2561 times.
✓ Branch 78 → 79 taken 854 times.
|
3415 | m_columns.removeIf([](const QString &id) { return !availableColumns().contains(id); }); |
| 71 |
1/1✓ Branch 79 → 80 taken 854 times.
|
854 | m_columns.removeDuplicates(); |
| 72 |
3/3✓ Branch 85 → 86 taken 854 times.
✓ Branch 86 → 87 taken 854 times.
✓ Branch 87 → 88 taken 854 times.
|
1708 | m_paneWidth = qBound(320, settings.value(QStringLiteral("contacts/paneWidth"), 440).toInt(), 760); |
| 73 |
1/1✓ Branch 92 → 93 taken 854 times.
|
854 | loadPage(); |
| 74 | 4266 | } | |
| 75 | |||
| 76 | 889 | QuickContactModel::~QuickContactModel() { | |
| 77 | // F4: an explicit join makes the worker lifetime deterministic. | ||
| 78 | 854 | m_pool.waitForDone(); | |
| 79 | 854 | m_completionPool.waitForDone(); | |
| 80 | 889 | } | |
| 81 | |||
| 82 | 170 | QHash<int, QByteArray> QuickContactModel::roleNames() const { | |
| 83 | ✗ | return {{CardKey, "cardKey"}, {DisplayName, "displayName"}, {PrimaryAddress, "primaryAddress"}, | |
| 84 | ✗ | {AddressCount, "addressCount"}, {Organization, "organization"}, {BookName, "bookName"}, | |
| 85 | ✗ | {BookReadOnly, "bookReadOnly"}, {LocalBook, "localBook"}, {Section, "section"}, | |
| 86 | ✗ | {Initials, "initials"}, {AvatarColor, "avatarColor"}, {HasPhoto, "hasPhoto"}, | |
| 87 | ✗ | {IsGroup, "isGroup"}, {SyncState, "syncState"}, {Collected, "collected"}, | |
| 88 | ✗ | {Writable, "writable"}, {BookId, "bookId"}, {Uid, "uid"}, | |
| 89 | ✗ | {PhotoTag, "photoTag"}, {Phone, "phone"}, {JobTitle, "jobTitle"}, | |
| 90 |
2/4✓ Branch 28 → 29 taken 4080 times.
✓ Branch 28 → 30 taken 170 times.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
|
4250 | {Locality, "locality"}, {Birthday, "birthday"}, {Groups, "groups"}}; |
| 91 | 170 | } | |
| 92 | |||
| 93 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 69652 times.
|
69652 | int QuickContactModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : int(m_rows.size()); } |
| 94 | |||
| 95 | 44183 | QVariant QuickContactModel::rowData(const ContactQueries::Row &row, int role) const { | |
| 96 |
20/25✓ Branch 2 → 3 taken 1894 times.
✓ Branch 2 → 4 taken 1878 times.
✓ Branch 2 → 5 taken 1855 times.
✓ Branch 2 → 6 taken 5 times.
✓ Branch 2 → 7 taken 1854 times.
✓ Branch 2 → 8 taken 1857 times.
✗ Branch 2 → 9 not taken.
✓ Branch 2 → 10 taken 1852 times.
✓ Branch 2 → 11 taken 10759 times.
✓ Branch 2 → 12 taken 1853 times.
✓ Branch 2 → 16 taken 1852 times.
✓ Branch 2 → 21 taken 1852 times.
✓ Branch 2 → 22 taken 1852 times.
✓ Branch 2 → 23 taken 1852 times.
✓ Branch 2 → 27 taken 1852 times.
✓ Branch 2 → 28 taken 1853 times.
✗ Branch 2 → 29 not taken.
✗ Branch 2 → 30 not taken.
✗ Branch 2 → 31 not taken.
✓ Branch 2 → 32 taken 1853 times.
✓ Branch 2 → 33 taken 1853 times.
✓ Branch 2 → 34 taken 1853 times.
✓ Branch 2 → 35 taken 1852 times.
✓ Branch 2 → 36 taken 1852 times.
✗ Branch 2 → 37 not taken.
|
44183 | switch (role) { |
| 97 | 1894 | case CardKey: return row.key; | |
| 98 | 1878 | case DisplayName: return row.displayName; | |
| 99 | 1855 | case PrimaryAddress: return row.primaryAddress; | |
| 100 | 5 | case AddressCount: return row.addressCount; | |
| 101 | 1854 | case Organization: return row.organization; | |
| 102 | 1857 | case BookName: return row.bookName; | |
| 103 | ✗ | case BookReadOnly: return row.bookReadOnly; | |
| 104 | 1852 | case LocalBook: return row.localBook; | |
| 105 | 10759 | case Section: return row.section; | |
| 106 |
1/1✓ Branch 12 → 13 taken 1853 times.
|
1853 | case Initials: return initialsOf(row.displayName); |
| 107 |
1/2✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1852 times.
|
1852 | case AvatarColor: return ContactIndex::avatarColorIndex(row.collected ? row.primaryAddress : row.uid); |
| 108 | 1852 | case HasPhoto: return row.hasPhoto; | |
| 109 | 1852 | case PhotoTag: return row.photoTag; | |
| 110 | 1852 | case IsGroup: return row.kind == QLatin1String("group"); | |
| 111 | 1852 | case SyncState: return row.syncState; | |
| 112 | 1853 | case Collected: return row.collected; | |
| 113 | ✗ | case Writable: return row.writable; | |
| 114 | ✗ | case BookId: return row.bookId; | |
| 115 | ✗ | case Uid: return row.uid; | |
| 116 | 1853 | case Phone: return row.phone; | |
| 117 | 1853 | case JobTitle: return row.title; | |
| 118 | 1853 | case Locality: return row.locality; | |
| 119 | 1852 | case Birthday: return row.birthday; | |
| 120 | 1852 | case Groups: return row.groups; | |
| 121 | ✗ | default: return {}; | |
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | 44183 | QVariant QuickContactModel::data(const QModelIndex &index, int role) const { | |
| 126 |
3/6✓ Branch 3 → 4 taken 44183 times.
✗ Branch 3 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 44183 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 44183 times.
|
44183 | if (index.row() < 0 || index.row() >= m_rows.size()) |
| 127 | ✗ | return {}; | |
| 128 | 44183 | return rowData(m_rows.at(index.row()), role); | |
| 129 | } | ||
| 130 | |||
| 131 | 217 | bool QuickContactModel::canFetchMore(const QModelIndex &parent) const { | |
| 132 |
5/6✓ Branch 3 → 4 taken 217 times.
✗ Branch 3 → 7 not taken.
✓ Branch 4 → 5 taken 30 times.
✓ Branch 4 → 7 taken 187 times.
✓ Branch 5 → 6 taken 28 times.
✓ Branch 5 → 7 taken 2 times.
|
217 | return !parent.isValid() && m_hasMore && !m_loading; |
| 133 | } | ||
| 134 | |||
| 135 | 18 | void QuickContactModel::fetchMore(const QModelIndex &parent) { | |
| 136 |
2/2✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 5 taken 5 times.
|
18 | if (canFetchMore(parent)) |
| 137 | 13 | loadPage(); | |
| 138 | 18 | } | |
| 139 | |||
| 140 | 55 | void QuickContactModel::setFilter(const QString &filter) { | |
| 141 |
2/2✓ Branch 3 → 4 taken 14 times.
✓ Branch 3 → 5 taken 41 times.
|
55 | if (m_filter == filter) |
| 142 | 14 | return; | |
| 143 | 41 | ++m_generation; // invalidates a page in flight | |
| 144 | 41 | m_filter = filter; | |
| 145 | 41 | emit filterChanged(); | |
| 146 | 41 | restartProjection(); | |
| 147 | } | ||
| 148 | |||
| 149 | 1040 | QVariantMap QuickContactModel::view() const { | |
| 150 | static const char *kinds[] = {"all", "frequent", "collected", "book", "group", "duplicates", "ungrouped"}; | ||
| 151 |
1/1✓ Branch 6 → 7 taken 1040 times.
|
2080 | return {{QStringLiteral("kind"), QString::fromLatin1(kinds[int(m_view.kind)])}, |
| 152 | 2080 | {QStringLiteral("bookId"), m_view.bookId}, | |
| 153 |
2/4✓ Branch 18 → 19 taken 3120 times.
✓ Branch 18 → 20 taken 1040 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
|
6240 | {QStringLiteral("group"), m_view.group}}; |
| 154 | 4160 | } | |
| 155 | |||
| 156 | 9 | void QuickContactModel::setView(const QVariantMap &map) { | |
| 157 |
1/1✓ Branch 2 → 3 taken 9 times.
|
9 | const ContactQueries::View next = viewFromMap(map, m_view.byFamilyName); |
| 158 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 9 times.
|
9 | if (next == m_view) |
| 159 | ✗ | return; | |
| 160 | 9 | ++m_generation; | |
| 161 | 9 | m_view = next; | |
| 162 |
3/3✓ Branch 7 → 8 taken 9 times.
✓ Branch 8 → 9 taken 9 times.
✓ Branch 14 → 15 taken 9 times.
|
18 | QSettings().setValue(QStringLiteral("contacts/view"), view()); |
| 163 |
1/1✓ Branch 20 → 21 taken 9 times.
|
9 | emit viewChanged(); |
| 164 |
1/1✓ Branch 21 → 22 taken 9 times.
|
9 | restartProjection(); |
| 165 | 9 | } | |
| 166 | |||
| 167 | 2 | void QuickContactModel::setSortByFamilyName(bool byFamily) { | |
| 168 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
|
2 | if (m_view.byFamilyName == byFamily) |
| 169 | ✗ | return; | |
| 170 | 2 | ++m_generation; | |
| 171 | 2 | m_view.byFamilyName = byFamily; | |
| 172 |
2/2✓ Branch 4 → 5 taken 2 times.
✓ Branch 10 → 11 taken 2 times.
|
4 | QSettings().setValue(QStringLiteral("contacts/sortByFamilyName"), byFamily); |
| 173 | 2 | emit viewChanged(); | |
| 174 | 2 | restartProjection(); | |
| 175 | } | ||
| 176 | |||
| 177 | 7 | void QuickContactModel::reload() { restartProjection(); } | |
| 178 | |||
| 179 | 2662 | QStringList QuickContactModel::availableColumns() { | |
| 180 | 2662 | return {QStringLiteral("email"), QStringLiteral("phone"), QStringLiteral("organization"), QStringLiteral("title"), | |
| 181 |
2/4✓ Branch 28 → 29 taken 21296 times.
✓ Branch 28 → 30 taken 2662 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
26620 | QStringLiteral("city"), QStringLiteral("birthday"), QStringLiteral("groups"), QStringLiteral("book")}; |
| 182 | 23958 | } | |
| 183 | |||
| 184 | 6 | void QuickContactModel::setColumns(const QStringList &columns) { | |
| 185 | 6 | QStringList valid; | |
| 186 |
2/2✓ Branch 18 → 4 taken 22 times.
✓ Branch 18 → 19 taken 6 times.
|
28 | for (const QString &id : columns) |
| 187 |
9/12✓ Branch 5 → 6 taken 22 times.
✓ Branch 7 → 8 taken 21 times.
✓ Branch 7 → 11 taken 1 time.
✓ Branch 9 → 10 taken 20 times.
✓ Branch 9 → 11 taken 1 time.
✓ Branch 12 → 13 taken 22 times.
✗ Branch 12 → 14 not taken.
✓ Branch 14 → 15 taken 20 times.
✓ Branch 14 → 16 taken 2 times.
✓ Branch 15 → 16 taken 20 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
|
22 | if (availableColumns().contains(id) && !valid.contains(id)) valid.append(id); |
| 188 |
2/3✓ Branch 19 → 20 taken 6 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 6 times.
|
6 | if (valid == m_columns) |
| 189 | ✗ | return; | |
| 190 | 6 | m_columns = valid; | |
| 191 |
2/2✓ Branch 23 → 24 taken 6 times.
✓ Branch 29 → 30 taken 6 times.
|
12 | QSettings().setValue(QStringLiteral("contacts/columns"), m_columns); |
| 192 |
1/1✓ Branch 34 → 35 taken 6 times.
|
6 | emit columnsChanged(); |
| 193 | 6 | } | |
| 194 | |||
| 195 | 7 | void QuickContactModel::setPaneWidth(int width) { | |
| 196 |
1/1✓ Branch 2 → 3 taken 7 times.
|
7 | width = qBound(320, width, 760); |
| 197 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 7 times.
|
7 | if (width == m_paneWidth) |
| 198 | ✗ | return; | |
| 199 | 7 | m_paneWidth = width; | |
| 200 |
2/2✓ Branch 5 → 6 taken 7 times.
✓ Branch 11 → 12 taken 7 times.
|
14 | QSettings().setValue(QStringLiteral("contacts/paneWidth"), m_paneWidth); |
| 201 | 7 | emit paneWidthChanged(); | |
| 202 | } | ||
| 203 | |||
| 204 | 422 | int QuickContactModel::indexOfKey(const QString &key) const { | |
| 205 |
2/2✓ Branch 9 → 3 taken 10260 times.
✓ Branch 9 → 10 taken 113 times.
|
10373 | for (int i = 0; i < m_rows.size(); ++i) |
| 206 |
2/2✓ Branch 5 → 6 taken 309 times.
✓ Branch 5 → 7 taken 9951 times.
|
10260 | if (m_rows.at(i).key == key) |
| 207 | 309 | return i; | |
| 208 | 113 | return -1; | |
| 209 | } | ||
| 210 | |||
| 211 | 153 | QString QuickContactModel::keyAt(int row) const { | |
| 212 |
4/4✓ Branch 2 → 3 taken 146 times.
✓ Branch 2 → 7 taken 7 times.
✓ Branch 4 → 5 taken 142 times.
✓ Branch 4 → 7 taken 4 times.
|
153 | return row >= 0 && row < m_rows.size() ? m_rows.at(row).key : QString(); |
| 213 | } | ||
| 214 | |||
| 215 | 857 | bool QuickContactModel::ensureReader() const { | |
| 216 |
5/6✓ Branch 3 → 4 taken 774 times.
✓ Branch 3 → 8 taken 83 times.
✓ Branch 6 → 7 taken 774 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 774 times.
✓ Branch 9 → 11 taken 83 times.
|
857 | if (m_reader && m_reader->isOpen()) |
| 217 | 774 | return true; | |
| 218 |
1/1✓ Branch 11 → 12 taken 83 times.
|
83 | m_reader = std::make_unique<ContactStore>(); |
| 219 |
3/6✓ Branch 15 → 16 taken 83 times.
✗ Branch 15 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 83 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 24 taken 83 times.
|
83 | if (m_databasePath.isEmpty() || !m_reader->open(m_databasePath)) { |
| 220 | ✗ | m_reader.reset(); | |
| 221 | ✗ | return false; | |
| 222 | } | ||
| 223 | 83 | return true; | |
| 224 | } | ||
| 225 | |||
| 226 | 773 | QVariantMap QuickContactModel::card(const QString &key) const { | |
| 227 |
2/3✓ Branch 2 → 3 taken 773 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 773 times.
|
773 | if (!ensureReader()) |
| 228 | ✗ | return {}; | |
| 229 |
3/3✓ Branch 6 → 7 taken 773 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 88 taken 772 times.
|
773 | if (key.startsWith(QLatin1String("collected:"))) { |
| 230 |
1/1✓ Branch 8 → 9 taken 1 time.
|
1 | const QString address = key.mid(10); |
| 231 |
2/2✓ Branch 10 → 11 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
|
1 | const ContactQueries::Lookup found = ContactQueries::lookup(m_reader->database(), address); |
| 232 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
|
1 | const QString name = found.displayName.isEmpty() ? address : found.displayName; |
| 233 | 2 | return {{QStringLiteral("key"), key}, | |
| 234 | 2 | {QStringLiteral("collected"), true}, | |
| 235 | 2 | {QStringLiteral("displayName"), name}, | |
| 236 |
1/1✓ Branch 33 → 34 taken 1 time.
|
2 | {QStringLiteral("initials"), initialsOf(name)}, |
| 237 |
1/1✓ Branch 38 → 39 taken 1 time.
|
2 | {QStringLiteral("avatarColor"), ContactIndex::avatarColorIndex(address)}, |
| 238 |
4/8✓ Branch 63 → 64 taken 1 time.
✓ Branch 63 → 65 taken 1 time.
✓ Branch 67 → 68 taken 1 time.
✓ Branch 67 → 69 taken 1 time.
✗ Branch 359 → 360 not taken.
✗ Branch 359 → 361 not taken.
✗ Branch 365 → 366 not taken.
✗ Branch 365 → 367 not taken.
|
5 | {QStringLiteral("emails"), QVariantList{QVariantMap{{QStringLiteral("value"), address}}}}, |
| 239 |
2/4✓ Branch 57 → 58 taken 7 times.
✓ Branch 57 → 59 taken 1 time.
✗ Branch 346 → 347 not taken.
✗ Branch 346 → 348 not taken.
|
10 | {QStringLiteral("writable"), false}}; |
| 240 | 1 | } | |
| 241 | 772 | qint64 bookId = 0; | |
| 242 | 772 | QString uid; | |
| 243 |
3/3✓ Branch 88 → 89 taken 772 times.
✓ Branch 89 → 90 taken 1 time.
✓ Branch 89 → 91 taken 771 times.
|
772 | if (!ContactQueries::splitKey(key, &bookId, &uid)) |
| 244 | 1 | return {}; | |
| 245 |
1/1✓ Branch 92 → 93 taken 771 times.
|
771 | const auto stored = m_reader->card(bookId, uid); |
| 246 |
1/1✓ Branch 94 → 95 taken 771 times.
|
771 | const auto book = m_reader->book(bookId); |
| 247 |
5/6✓ Branch 96 → 97 taken 750 times.
✓ Branch 96 → 99 taken 21 times.
✗ Branch 98 → 99 not taken.
✓ Branch 98 → 100 taken 750 times.
✓ Branch 101 → 102 taken 21 times.
✓ Branch 101 → 103 taken 750 times.
|
771 | if (!stored || !book) |
| 248 | 21 | return {}; | |
| 249 |
1/1✓ Branch 103 → 104 taken 750 times.
|
750 | ContactCard parsed; |
| 250 | 750 | bool writable = true; | |
| 251 |
2/3✓ Branch 105 → 106 taken 750 times.
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 108 taken 750 times.
|
750 | if (!VCardCodec::parse(stored->raw, &parsed, nullptr, &writable)) |
| 252 | ✗ | writable = false; | |
| 253 |
1/1✓ Branch 108 → 109 taken 750 times.
|
750 | QVariantMap map = ContactEditorFields::toMap(parsed); |
| 254 |
3/3✓ Branch 109 → 110 taken 750 times.
✓ Branch 110 → 111 taken 750 times.
✓ Branch 115 → 116 taken 750 times.
|
1500 | map.insert(QStringLiteral("birthdayText"), ContactEditorFields::formatPartialDate(parsed.birthday)); |
| 255 |
3/3✓ Branch 121 → 122 taken 750 times.
✓ Branch 122 → 123 taken 750 times.
✓ Branch 127 → 128 taken 750 times.
|
1500 | map.insert(QStringLiteral("anniversaryText"), ContactEditorFields::formatPartialDate(parsed.anniversary)); |
| 256 |
1/1✓ Branch 133 → 134 taken 750 times.
|
750 | const QString name = ContactIndex::displayName(parsed); |
| 257 |
1/1✓ Branch 138 → 139 taken 750 times.
|
1500 | map.insert(QStringLiteral("key"), key); |
| 258 |
1/1✓ Branch 146 → 147 taken 750 times.
|
1500 | map.insert(QStringLiteral("bookId"), bookId); |
| 259 |
1/1✓ Branch 155 → 156 taken 750 times.
|
1500 | map.insert(QStringLiteral("bookName"), book->displayName); |
| 260 |
1/1✓ Branch 164 → 165 taken 750 times.
|
1500 | map.insert(QStringLiteral("accountId"), book->accountId); |
| 261 |
1/1✓ Branch 174 → 175 taken 750 times.
|
1500 | map.insert(QStringLiteral("localBook"), book->isLocal()); |
| 262 |
1/1✓ Branch 183 → 184 taken 750 times.
|
1500 | map.insert(QStringLiteral("bookReadOnly"), book->readOnly); |
| 263 |
1/1✓ Branch 191 → 192 taken 750 times.
|
1500 | map.insert(QStringLiteral("displayName"), name); |
| 264 |
2/2✓ Branch 195 → 196 taken 750 times.
✓ Branch 200 → 201 taken 750 times.
|
1500 | map.insert(QStringLiteral("initials"), ContactIndex::initials(parsed)); |
| 265 |
2/2✓ Branch 205 → 206 taken 750 times.
✓ Branch 210 → 211 taken 750 times.
|
1500 | map.insert(QStringLiteral("avatarColor"), ContactIndex::avatarColorIndex(uid)); |
| 266 |
1/1✓ Branch 219 → 220 taken 750 times.
|
1500 | map.insert(QStringLiteral("syncState"), stored->syncState); |
| 267 |
3/3✓ Branch 232 → 233 taken 750 times.
✓ Branch 233 → 234 taken 750 times.
✓ Branch 238 → 239 taken 750 times.
|
1500 | map.insert(QStringLiteral("people"), ContactPeopleView::build(m_reader->database(), stored->id, parsed, name, |
| 268 |
2/2✓ Branch 228 → 229 taken 750 times.
✓ Branch 229 → 230 taken 750 times.
|
1500 | QSettings().value(QStringLiteral("contacts/meCard")).toString(), |
| 269 |
1/1✓ Branch 223 → 224 taken 750 times.
|
750 | m_eventTitle)); |
| 270 | // The avatar URL changes with the photo (inline data or a fetched URI). | ||
| 271 |
1/1✓ Branch 262 → 263 taken 750 times.
|
1500 | map.insert(QStringLiteral("photoTag"), |
| 272 |
3/3✓ Branch 249 → 250 taken 110 times.
✓ Branch 249 → 251 taken 640 times.
✓ Branch 250 → 258 taken 110 times.
|
2140 | parsed.photo.kind == ContactPhoto::Kind::Inline ? QString::number(qHash(parsed.photo.data), 16) |
| 273 |
4/7✓ Branch 253 → 254 taken 1 time.
✓ Branch 255 → 256 taken 1 time.
✗ Branch 255 → 257 not taken.
✓ Branch 267 → 268 taken 1 time.
✓ Branch 267 → 269 taken 749 times.
✗ Branch 606 → 607 not taken.
✗ Branch 606 → 608 not taken.
|
751 | : parsed.photo.kind == ContactPhoto::Kind::Uri && !m_reader->fetchedPhoto(bookId, uid).isEmpty() |
| 274 |
2/2✓ Branch 251 → 252 taken 1 time.
✓ Branch 251 → 257 taken 639 times.
|
640 | ? parsed.photo.uri |
| 275 | : QString()); | ||
| 276 |
1/1✓ Branch 284 → 285 taken 750 times.
|
1500 | map.insert(QStringLiteral("writable"), |
| 277 |
4/8✓ Branch 269 → 270 taken 750 times.
✗ Branch 269 → 279 not taken.
✓ Branch 271 → 272 taken 750 times.
✗ Branch 271 → 279 not taken.
✓ Branch 273 → 274 taken 750 times.
✗ Branch 273 → 279 not taken.
✓ Branch 277 → 278 taken 750 times.
✗ Branch 277 → 279 not taken.
|
750 | writable && stored->writable && !book->readOnly && stored->syncState != QLatin1String("legacy")); |
| 278 |
3/3✓ Branch 289 → 290 taken 750 times.
✓ Branch 291 → 292 taken 126 times.
✓ Branch 291 → 331 taken 624 times.
|
750 | if (const auto entry = m_reader->outboxEntry(bookId, uid)) { |
| 279 |
1/1✓ Branch 299 → 300 taken 126 times.
|
252 | map.insert(QStringLiteral("conflict"), entry->state == QLatin1String("conflict")); |
| 280 |
1/1✓ Branch 308 → 309 taken 126 times.
|
252 | map.insert(QStringLiteral("conflictFields"), entry->conflictFields); |
| 281 |
1/1✓ Branch 317 → 318 taken 126 times.
|
252 | map.insert(QStringLiteral("pendingAttempts"), entry->attempts); |
| 282 | // Technical detail only behind "Details" (G16). | ||
| 283 |
1/1✓ Branch 326 → 327 taken 126 times.
|
252 | map.insert(QStringLiteral("lastError"), entry->lastError); |
| 284 | 750 | } | |
| 285 | 750 | return map; | |
| 286 | 783 | } | |
| 287 | |||
| 288 | 19 | int QuickContactModel::insertPosition(const ContactQueries::Row &row) const { | |
| 289 |
1/1✓ Branch 4 → 5 taken 19 times.
|
19 | const auto it = std::lower_bound(m_rows.cbegin(), m_rows.cend(), row, before); |
| 290 | 38 | return int(it - m_rows.cbegin()); | |
| 291 | } | ||
| 292 | |||
| 293 | 42 | void QuickContactModel::refreshCount() { | |
| 294 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 42 times.
|
42 | if (!ensureReader()) |
| 295 | ✗ | return; | |
| 296 |
2/2✓ Branch 6 → 7 taken 42 times.
✓ Branch 7 → 8 taken 42 times.
|
42 | const int count = ContactQueries::count(m_reader->database(), m_view, m_filter); |
| 297 |
2/2✓ Branch 9 → 10 taken 16 times.
✓ Branch 9 → 11 taken 26 times.
|
42 | if (count != m_totalCount) { |
| 298 | 16 | m_totalCount = count; | |
| 299 | 16 | emit totalCountChanged(); | |
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | 47 | void QuickContactModel::applyCardChanges(const QStringList &keys) { | |
| 304 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 47 times.
|
47 | if (keys.isEmpty()) |
| 305 | ✗ | return; | |
| 306 | // Smart lists over usage and collected addresses are small: reload them. | ||
| 307 | // A changed card can make an unchanged one a duplicate: reload that too. | ||
| 308 | 141 | const bool cardView = m_view.kind != ContactQueries::ViewKind::Collected && | |
| 309 |
2/4✓ Branch 5 → 6 taken 47 times.
✗ Branch 5 → 9 not taken.
✓ Branch 6 → 7 taken 47 times.
✗ Branch 6 → 9 not taken.
|
94 | m_view.kind != ContactQueries::ViewKind::Frequent && |
| 310 |
1/2✓ Branch 7 → 8 taken 47 times.
✗ Branch 7 → 9 not taken.
|
47 | m_view.kind != ContactQueries::ViewKind::Duplicates; |
| 311 |
7/9✓ Branch 10 → 11 taken 47 times.
✗ Branch 10 → 17 not taken.
✓ Branch 14 → 15 taken 42 times.
✓ Branch 14 → 17 taken 5 times.
✓ Branch 15 → 16 taken 42 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 42 times.
✓ Branch 19 → 20 taken 5 times.
✓ Branch 19 → 22 taken 42 times.
|
47 | if (!cardView || keys.size() * 2 > qMax(int(m_rows.size()), 1) || !ensureReader()) { |
| 312 | 5 | restartProjection(); | |
| 313 | 5 | return; | |
| 314 | } | ||
| 315 |
5/5✓ Branch 24 → 25 taken 42 times.
✓ Branch 25 → 26 taken 42 times.
✓ Branch 26 → 27 taken 42 times.
✓ Branch 109 → 28 taken 45 times.
✓ Branch 109 → 110 taken 42 times.
|
87 | for (const QString &key : QSet<QString>(keys.cbegin(), keys.cend())) { |
| 316 | 45 | qint64 bookId = 0; | |
| 317 | 45 | QString uid; | |
| 318 |
2/3✓ Branch 29 → 30 taken 45 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 45 times.
|
45 | if (!ContactQueries::splitKey(key, &bookId, &uid)) |
| 319 | ✗ | continue; | |
| 320 | 45 | QList<ContactQueries::Row> fresh; | |
| 321 |
3/3✓ Branch 33 → 34 taken 45 times.
✓ Branch 35 → 36 taken 36 times.
✓ Branch 35 → 46 taken 9 times.
|
45 | if (const auto stored = m_reader->card(bookId, uid)) |
| 322 |
3/3✓ Branch 37 → 38 taken 36 times.
✓ Branch 39 → 40 taken 36 times.
✓ Branch 40 → 41 taken 36 times.
|
45 | fresh = ContactQueries::rowsForCards(m_reader->database(), m_view, m_filter, {stored->id}); |
| 323 | 45 | const int existing = indexOfKey(key); | |
| 324 |
2/2✓ Branch 49 → 50 taken 9 times.
✓ Branch 49 → 56 taken 36 times.
|
45 | if (fresh.isEmpty()) { |
| 325 |
1/2✓ Branch 50 → 51 taken 9 times.
✗ Branch 50 → 55 not taken.
|
9 | if (existing >= 0) { |
| 326 |
1/1✓ Branch 52 → 53 taken 9 times.
|
9 | beginRemoveRows({}, existing, existing); |
| 327 |
1/1✓ Branch 53 → 54 taken 9 times.
|
9 | m_rows.removeAt(existing); |
| 328 |
1/1✓ Branch 54 → 55 taken 9 times.
|
9 | endRemoveRows(); |
| 329 | } | ||
| 330 | 9 | continue; | |
| 331 | } | ||
| 332 |
1/1✓ Branch 56 → 57 taken 36 times.
|
36 | const ContactQueries::Row row = fresh.first(); |
| 333 |
6/6✓ Branch 58 → 59 taken 21 times.
✓ Branch 58 → 63 taken 15 times.
✓ Branch 61 → 62 taken 17 times.
✓ Branch 61 → 63 taken 4 times.
✓ Branch 64 → 65 taken 17 times.
✓ Branch 64 → 75 taken 19 times.
|
36 | if (existing >= 0 && m_rows.at(existing).sortKey == row.sortKey) { |
| 334 |
1/1✓ Branch 65 → 66 taken 17 times.
|
17 | m_rows[existing] = row; |
| 335 |
3/3✓ Branch 69 → 70 taken 17 times.
✓ Branch 71 → 72 taken 17 times.
✓ Branch 72 → 73 taken 17 times.
|
17 | emit dataChanged(index(existing), index(existing)); |
| 336 | 17 | continue; | |
| 337 | } | ||
| 338 |
2/2✓ Branch 75 → 76 taken 4 times.
✓ Branch 75 → 80 taken 15 times.
|
19 | if (existing >= 0) { |
| 339 |
1/1✓ Branch 77 → 78 taken 4 times.
|
4 | beginRemoveRows({}, existing, existing); |
| 340 |
1/1✓ Branch 78 → 79 taken 4 times.
|
4 | m_rows.removeAt(existing); |
| 341 |
1/1✓ Branch 79 → 80 taken 4 times.
|
4 | endRemoveRows(); |
| 342 | } | ||
| 343 |
1/1✓ Branch 80 → 81 taken 19 times.
|
19 | const int position = insertPosition(row); |
| 344 | // Rows beyond the loaded range arrive with the next page. | ||
| 345 |
6/6✓ Branch 82 → 83 taken 3 times.
✓ Branch 82 → 84 taken 16 times.
✓ Branch 83 → 84 taken 1 time.
✓ Branch 83 → 85 taken 2 times.
✓ Branch 86 → 87 taken 17 times.
✓ Branch 86 → 93 taken 2 times.
|
19 | if (position < m_rows.size() || !m_hasMore) { |
| 346 |
1/1✓ Branch 88 → 89 taken 17 times.
|
17 | beginInsertRows({}, position, position); |
| 347 |
1/1✓ Branch 89 → 90 taken 17 times.
|
17 | m_rows.insert(position, row); |
| 348 |
1/1✓ Branch 90 → 91 taken 17 times.
|
17 | endInsertRows(); |
| 349 |
2/2✓ Branch 91 → 92 taken 4 times.
✓ Branch 91 → 93 taken 13 times.
|
17 | if (existing >= 0) |
| 350 |
1/1✓ Branch 92 → 93 taken 4 times.
|
4 | emit cardMoved(key, position); |
| 351 | } | ||
| 352 | 130 | } | |
| 353 | 42 | refreshCount(); | |
| 354 | } | ||
| 355 | |||
| 356 | 64 | void QuickContactModel::restartProjection() { | |
| 357 | // A restart returns to the first keyset page; writes also invalidate any | ||
| 358 | // visible completion answer. | ||
| 359 | 64 | beginResetModel(); | |
| 360 | 64 | m_rows.clear(); | |
| 361 | 64 | m_totalCount = 0; | |
| 362 | 64 | m_hasMore = false; | |
| 363 | 64 | endResetModel(); | |
| 364 | 64 | emit totalCountChanged(); | |
| 365 | 64 | ++m_completionGeneration; | |
| 366 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 64 times.
|
64 | if (!m_completions.isEmpty()) { |
| 367 | ✗ | m_completions.clear(); | |
| 368 | ✗ | emit completionsChanged(); | |
| 369 | } | ||
| 370 | 64 | m_loading = false; | |
| 371 | 64 | loadPage(); | |
| 372 | 64 | } | |
| 373 | |||
| 374 | 931 | void QuickContactModel::loadPage() { | |
| 375 |
3/6✓ Branch 3 → 4 taken 931 times.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 931 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 931 times.
|
931 | if (m_databasePath.isEmpty() || m_loading) |
| 376 | ✗ | return; | |
| 377 | 931 | const quint64 generation = ++m_generation; | |
| 378 | 931 | const QString filter = m_filter; | |
| 379 | 931 | const QString databasePath = m_databasePath; | |
| 380 | 931 | const ContactQueries::View view = m_view; | |
| 381 | 931 | const bool first = m_rows.isEmpty(); | |
| 382 |
3/3✓ Branch 13 → 14 taken 918 times.
✓ Branch 13 → 15 taken 13 times.
✓ Branch 15 → 16 taken 13 times.
|
931 | const QString afterKey = first ? QString() : m_rows.last().sortKey; |
| 383 |
3/3✓ Branch 17 → 18 taken 918 times.
✓ Branch 17 → 19 taken 13 times.
✓ Branch 19 → 20 taken 13 times.
|
931 | const qint64 afterId = first ? 0 : m_rows.last().cardId; |
| 384 | // F-61: equal-name collected rows resume by their stable key. | ||
| 385 |
3/3✓ Branch 21 → 22 taken 918 times.
✓ Branch 21 → 23 taken 13 times.
✓ Branch 23 → 24 taken 13 times.
|
931 | const QString afterRowKey = first ? QString() : m_rows.last().key; |
| 386 | 931 | m_loading = true; | |
| 387 |
1/1✓ Branch 25 → 26 taken 931 times.
|
931 | emit loadingChanged(); |
| 388 |
1/9✓ Branch 31 → 32 taken 931 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 47 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 50 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 53 not taken.
|
931 | m_pool.start([this, generation, filter, databasePath, view, first, afterKey, afterId, afterRowKey] { |
| 389 | 931 | QList<ContactQueries::Row> page; | |
| 390 | 931 | int total = -1; | |
| 391 |
3/4✓ Branch 2 → 3 taken 931 times.
✓ Branch 3 → 4 taken 931 times.
✓ Branch 4 → 5 taken 931 times.
✗ Branch 4 → 21 not taken.
|
931 | if (ContactStore store; store.open(databasePath)) { |
| 392 |
2/2✓ Branch 5 → 6 taken 931 times.
✓ Branch 6 → 7 taken 931 times.
|
931 | page = ContactQueries::page(store.database(), view, filter, PageSize, afterKey, afterId, afterRowKey); |
| 393 | // A first page that is not full is the whole result: no COUNT scan. | ||
| 394 |
2/2✓ Branch 10 → 11 taken 918 times.
✓ Branch 10 → 21 taken 13 times.
|
931 | if (first) |
| 395 |
6/8✓ Branch 12 → 13 taken 892 times.
✓ Branch 12 → 15 taken 26 times.
✓ Branch 15 → 16 taken 26 times.
✓ Branch 16 → 17 taken 26 times.
✓ Branch 18 → 19 taken 26 times.
✓ Branch 18 → 20 taken 892 times.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
|
918 | total = page.size() < PageSize ? int(page.size()) : ContactQueries::count(store.database(), view, filter); |
| 396 | 931 | } | |
| 397 | 931 | QMetaObject::invokeMethod( | |
| 398 | this, | ||
| 399 |
1/3✓ Branch 24 → 25 taken 931 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
931 | [this, generation, page = std::move(page), total]() mutable { |
| 400 | // A newer request (view/filter change, restart) owns the | ||
| 401 | // projection; its own answer arrives later. | ||
| 402 |
2/2✓ Branch 2 → 3 taken 7 times.
✓ Branch 2 → 4 taken 798 times.
|
805 | if (generation != m_generation) |
| 403 | 7 | return; | |
| 404 | 798 | m_loading = false; | |
| 405 |
2/2✓ Branch 5 → 6 taken 245 times.
✓ Branch 5 → 12 taken 553 times.
|
798 | if (!page.isEmpty()) { |
| 406 | 245 | const int start = int(m_rows.size()); | |
| 407 |
1/1✓ Branch 9 → 10 taken 245 times.
|
245 | beginInsertRows({}, start, start + int(page.size()) - 1); |
| 408 | 245 | m_rows.append(page); | |
| 409 | 245 | endInsertRows(); | |
| 410 | } | ||
| 411 |
2/2✓ Branch 12 → 13 taken 785 times.
✓ Branch 12 → 14 taken 13 times.
|
798 | if (total >= 0) |
| 412 | 785 | m_totalCount = total; | |
| 413 | 798 | m_hasMore = page.size() == PageSize; | |
| 414 | 798 | emit loadingChanged(); | |
| 415 | 798 | emit totalCountChanged(); | |
| 416 | }, | ||
| 417 | Qt::QueuedConnection); | ||
| 418 | 931 | }); | |
| 419 | 931 | } | |
| 420 | |||
| 421 | 114 | void QuickContactModel::requestCompletions(const QString &fragment) { | |
| 422 | 114 | const quint64 generation = ++m_completionGeneration; | |
| 423 |
2/2✓ Branch 2 → 3 taken 114 times.
✓ Branch 3 → 4 taken 114 times.
|
114 | const QString trimmed = fragment.left(64).trimmed(); |
| 424 |
5/6✓ Branch 6 → 7 taken 114 times.
✗ Branch 6 → 9 not taken.
✓ Branch 8 → 9 taken 91 times.
✓ Branch 8 → 10 taken 23 times.
✓ Branch 11 → 12 taken 91 times.
✓ Branch 11 → 17 taken 23 times.
|
114 | if (m_databasePath.isEmpty() || trimmed.isEmpty()) { |
| 425 |
2/2✓ Branch 13 → 14 taken 10 times.
✓ Branch 13 → 16 taken 81 times.
|
91 | if (!m_completions.isEmpty()) { |
| 426 |
1/1✓ Branch 14 → 15 taken 10 times.
|
10 | m_completions.clear(); |
| 427 |
1/1✓ Branch 15 → 16 taken 10 times.
|
10 | emit completionsChanged(); |
| 428 | } | ||
| 429 | 91 | return; | |
| 430 | } | ||
| 431 | 23 | const QString databasePath = m_databasePath; | |
| 432 | // P90.13: latest-first — a queued completion for an older fragment is | ||
| 433 | // dropped instead of opening the store again. | ||
| 434 |
1/1✓ Branch 18 → 19 taken 23 times.
|
23 | m_completionPool.clear(); |
| 435 |
1/3✓ Branch 21 → 22 taken 23 times.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
|
23 | m_completionPool.start([this, generation, trimmed, databasePath] { |
| 436 | 21 | QVariantList results; | |
| 437 |
3/4✓ Branch 2 → 3 taken 21 times.
✓ Branch 3 → 4 taken 21 times.
✓ Branch 4 → 5 taken 21 times.
✗ Branch 4 → 226 not taken.
|
21 | if (ContactStore store; store.open(databasePath)) { |
| 438 |
6/6✓ Branch 5 → 6 taken 21 times.
✓ Branch 6 → 7 taken 21 times.
✓ Branch 8 → 9 taken 21 times.
✓ Branch 9 → 10 taken 21 times.
✓ Branch 223 → 11 taken 19 times.
✓ Branch 223 → 224 taken 21 times.
|
40 | for (const ContactQueries::Completion &item : ContactQueries::completions(store.database(), trimmed, 8)) { |
| 439 |
2/2✓ Branch 12 → 13 taken 7 times.
✓ Branch 12 → 116 taken 12 times.
|
19 | if (item.group) { |
| 440 | // S97.5.4: a group expands into its members on accept. | ||
| 441 | 7 | const int count = int(item.members.size()); | |
| 442 |
1/1✓ Branch 76 → 77 taken 7 times.
|
7 | results.append(QVariantMap{ |
| 443 | 14 | {QStringLiteral("key"), item.key}, | |
| 444 | 14 | {QStringLiteral("name"), item.name}, | |
| 445 | 14 | {QStringLiteral("email"), QString()}, | |
| 446 |
1/1✓ Branch 33 → 34 taken 7 times.
|
21 | {QStringLiteral("insert"), item.members.join(QStringLiteral(", "))}, |
| 447 |
4/6✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 42 taken 6 times.
✓ Branch 39 → 40 taken 1 time.
✓ Branch 41 → 45 taken 1 time.
✗ Branch 295 → 296 not taken.
✗ Branch 295 → 297 not taken.
|
20 | {QStringLiteral("label"), count == 1 ? tr("%1 (1 person)").arg(item.name) |
| 448 |
6/8✓ Branch 42 → 43 taken 6 times.
✓ Branch 44 → 45 taken 6 times.
✓ Branch 97 → 98 taken 6 times.
✓ Branch 97 → 99 taken 1 time.
✓ Branch 99 → 100 taken 1 time.
✓ Branch 99 → 101 taken 6 times.
✗ Branch 290 → 291 not taken.
✗ Branch 290 → 292 not taken.
|
19 | : tr("%1 (%n people)", "", count).arg(item.name)}, |
| 449 |
4/4✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 51 taken 6 times.
✓ Branch 50 → 52 taken 1 time.
✓ Branch 51 → 52 taken 6 times.
|
14 | {QStringLiteral("detail"), count == 1 ? tr("1 person") : tr("%n people", "", count)}, |
| 450 | 14 | {QStringLiteral("book"), item.bookName}, | |
| 451 | 14 | {QStringLiteral("collected"), false}, | |
| 452 | 14 | {QStringLiteral("group"), true}, | |
| 453 | 14 | {QStringLiteral("initials"), QString()}, | |
| 454 |
2/4✓ Branch 80 → 81 taken 77 times.
✓ Branch 80 → 82 taken 7 times.
✗ Branch 240 → 241 not taken.
✗ Branch 240 → 242 not taken.
|
91 | {QStringLiteral("avatarColor"), item.avatarColor}}); |
| 455 | 7 | continue; | |
| 456 | 7 | } | |
| 457 |
2/4✓ Branch 117 → 118 taken 12 times.
✗ Branch 117 → 121 not taken.
✓ Branch 119 → 120 taken 12 times.
✗ Branch 119 → 121 not taken.
|
12 | const bool named = !item.name.isEmpty() && item.name != item.address; |
| 458 |
1/1✓ Branch 184 → 185 taken 12 times.
|
12 | results.append(QVariantMap{ |
| 459 | 24 | {QStringLiteral("key"), item.key}, | |
| 460 | 24 | {QStringLiteral("name"), item.name}, | |
| 461 | 24 | {QStringLiteral("email"), item.address}, | |
| 462 |
2/3✓ Branch 137 → 138 taken 12 times.
✗ Branch 137 → 139 not taken.
✓ Branch 138 → 140 taken 12 times.
|
24 | {QStringLiteral("insert"), named ? MailboxText::mailbox(item.name, item.address) : item.address}, |
| 463 |
4/11✓ Branch 144 → 145 taken 12 times.
✗ Branch 144 → 149 not taken.
✓ Branch 148 → 150 taken 12 times.
✓ Branch 205 → 206 taken 12 times.
✗ Branch 205 → 207 not taken.
✓ Branch 207 → 208 taken 12 times.
✗ Branch 207 → 209 not taken.
✗ Branch 403 → 404 not taken.
✗ Branch 403 → 405 not taken.
✗ Branch 407 → 408 not taken.
✗ Branch 407 → 409 not taken.
|
36 | {QStringLiteral("label"), named ? QStringLiteral("%1 · %2").arg(item.name, item.address) : item.address}, |
| 464 | 24 | {QStringLiteral("book"), item.bookName}, | |
| 465 | 24 | {QStringLiteral("collected"), item.collected}, | |
| 466 | 24 | {QStringLiteral("group"), false}, | |
| 467 |
3/3✓ Branch 166 → 167 taken 3 times.
✓ Branch 166 → 168 taken 9 times.
✓ Branch 167 → 169 taken 3 times.
|
24 | {QStringLiteral("detail"), item.collected ? tr("Collected") : item.bookName}, |
| 468 |
2/3✓ Branch 173 → 174 taken 12 times.
✗ Branch 173 → 175 not taken.
✓ Branch 176 → 177 taken 12 times.
|
24 | {QStringLiteral("initials"), initialsOf(named ? item.name : item.address)}, |
| 469 |
2/4✓ Branch 188 → 189 taken 132 times.
✓ Branch 188 → 190 taken 12 times.
✗ Branch 355 → 356 not taken.
✗ Branch 355 → 357 not taken.
|
168 | {QStringLiteral("avatarColor"), item.avatarColor}}); |
| 470 | 21 | } | |
| 471 | 21 | } | |
| 472 |
1/1✓ Branch 228 → 229 taken 21 times.
|
21 | QMetaObject::invokeMethod( |
| 473 | this, | ||
| 474 | 42 | [this, generation, results]() { | |
| 475 |
2/2✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 17 times.
|
21 | if (generation != m_completionGeneration) |
| 476 | 4 | return; // stale answer | |
| 477 | 17 | m_completions = results; | |
| 478 | 17 | emit completionsChanged(); | |
| 479 | }, | ||
| 480 | Qt::QueuedConnection); | ||
| 481 |
2/10✓ Branch 74 → 75 taken 7 times.
✓ Branch 182 → 183 taken 12 times.
✗ Branch 342 → 343 not taken.
✗ Branch 342 → 346 not taken.
✗ Branch 344 → 345 not taken.
✗ Branch 344 → 346 not taken.
✗ Branch 445 → 446 not taken.
✗ Branch 445 → 449 not taken.
✗ Branch 447 → 448 not taken.
✗ Branch 447 → 449 not taken.
|
275 | }); |
| 482 | 114 | } | |
| 483 |