presentation/ContactMerge.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "ContactMerge.h" | ||
| 2 | |||
| 3 | #include <functional> | ||
| 4 | |||
| 5 | namespace { | ||
| 6 | |||
| 7 | const char *kScalarFields[] = {"organization", "department", "title", "nickname", "birthday"}; | ||
| 8 | const char *kNameFields[] = {"given", "family", "prefix", "additional", "suffix", "formattedName"}; | ||
| 9 | |||
| 10 | 644 | QString text(const QVariantMap &card, const char *field) { | |
| 11 |
4/4✓ Branch 4 → 5 taken 644 times.
✓ Branch 5 → 6 taken 644 times.
✓ Branch 6 → 7 taken 644 times.
✓ Branch 7 → 8 taken 644 times.
|
644 | return card.value(QLatin1String(field)).toString().trimmed(); |
| 12 | } | ||
| 13 | |||
| 14 | 19 | QString nameOf(const QVariantMap &card) { | |
| 15 |
3/3✓ Branch 6 → 7 taken 19 times.
✓ Branch 7 → 8 taken 19 times.
✓ Branch 8 → 9 taken 19 times.
|
38 | const QString display = card.value(QStringLiteral("displayName")).toString().trimmed(); |
| 16 |
1/2✓ Branch 15 → 16 taken 19 times.
✗ Branch 15 → 18 not taken.
|
19 | if (!display.isEmpty()) return display; |
| 17 | ✗ | const QString formatted = text(card, "formattedName"); | |
| 18 | ✗ | if (!formatted.isEmpty()) return formatted; | |
| 19 | ✗ | return (text(card, "given") + QLatin1Char(' ') + text(card, "family")).trimmed(); | |
| 20 | 19 | } | |
| 21 | |||
| 22 | 56 | QString digits(const QString &number) { | |
| 23 | 56 | QString result; | |
| 24 |
2/2✓ Branch 8 → 4 taken 683 times.
✓ Branch 8 → 9 taken 56 times.
|
739 | for (const QChar ch : number) |
| 25 |
3/3✓ Branch 5 → 6 taken 585 times.
✓ Branch 5 → 7 taken 98 times.
✓ Branch 6 → 7 taken 585 times.
|
683 | if (ch.isDigit()) result.append(ch); |
| 26 |
4/4✓ Branch 10 → 11 taken 23 times.
✓ Branch 13 → 14 taken 79 times.
✓ Branch 14 → 10 taken 23 times.
✓ Branch 14 → 15 taken 56 times.
|
79 | while (result.startsWith(QLatin1Char('0'))) result.remove(0, 1); |
| 27 | 56 | return result; | |
| 28 | ✗ | } | |
| 29 | |||
| 30 | using SameValue = bool (*)(const QString &, const QString &); | ||
| 31 | |||
| 32 |
2/2✓ Branch 2 → 3 taken 56 times.
✓ Branch 3 → 4 taken 56 times.
|
56 | bool sameText(const QString &a, const QString &b) { return a.trimmed().compare(b.trimmed(), Qt::CaseInsensitive) == 0; } |
| 33 | |||
| 34 | // Values of `extra` not yet in `result` (compared on `field`) are appended | ||
| 35 | // as new values of the kept card. | ||
| 36 | 88 | void unite(QVariantList &result, const QVariantList &extra, const QString &field, SameValue same) { | |
| 37 |
2/2✓ Branch 65 → 4 taken 32 times.
✓ Branch 65 → 66 taken 88 times.
|
120 | for (const QVariant &value : extra) { |
| 38 |
1/1✓ Branch 5 → 6 taken 32 times.
|
32 | QVariantMap entry = value.toMap(); |
| 39 |
3/3✓ Branch 7 → 8 taken 32 times.
✓ Branch 8 → 9 taken 32 times.
✓ Branch 9 → 10 taken 32 times.
|
32 | const QString candidate = entry.value(field).toString().trimmed(); |
| 40 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 32 times.
|
32 | if (candidate.isEmpty()) continue; |
| 41 | 32 | bool known = false; | |
| 42 |
4/4✓ Branch 16 → 17 taken 32 times.
✓ Branch 17 → 18 taken 32 times.
✓ Branch 39 → 19 taken 51 times.
✓ Branch 39 → 40 taken 32 times.
|
83 | for (const QVariant &existing : result) |
| 43 |
16/24✓ Branch 20 → 21 taken 45 times.
✓ Branch 20 → 27 taken 6 times.
✓ Branch 21 → 22 taken 45 times.
✓ Branch 23 → 24 taken 45 times.
✓ Branch 24 → 25 taken 45 times.
✓ Branch 25 → 26 taken 45 times.
✓ Branch 26 → 27 taken 15 times.
✓ Branch 26 → 28 taken 30 times.
✓ Branch 29 → 30 taken 45 times.
✓ Branch 29 → 31 taken 6 times.
✓ Branch 31 → 32 taken 45 times.
✓ Branch 31 → 33 taken 6 times.
✓ Branch 33 → 34 taken 45 times.
✓ Branch 33 → 35 taken 6 times.
✓ Branch 35 → 36 taken 45 times.
✓ Branch 35 → 37 taken 6 times.
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 78 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 86 not taken.
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 90 not taken.
|
51 | known = known || same(existing.toMap().value(field).toString(), candidate); |
| 44 |
2/2✓ Branch 40 → 41 taken 15 times.
✓ Branch 40 → 42 taken 17 times.
|
32 | if (known) continue; |
| 45 |
1/1✓ Branch 46 → 47 taken 17 times.
|
34 | entry.insert(QStringLiteral("sourceIndex"), -1); |
| 46 |
1/1✓ Branch 51 → 52 taken 17 times.
|
17 | result.append(entry); |
| 47 | 47 | } | |
| 48 | 88 | } | |
| 49 | |||
| 50 | // The id of a list value: equal ids are one value (phone numbers by | ||
| 51 | // digits, the rest by text without case). | ||
| 52 | 87 | QString valueId(const QString &field, const QString &value) { | |
| 53 |
11/16✓ Branch 4 → 5 taken 14 times.
✓ Branch 4 → 10 taken 73 times.
✓ Branch 5 → 6 taken 14 times.
✓ Branch 7 → 8 taken 14 times.
✗ Branch 7 → 10 not taken.
✓ Branch 8 → 9 taken 14 times.
✓ Branch 10 → 11 taken 73 times.
✓ Branch 11 → 12 taken 73 times.
✓ Branch 12 → 13 taken 73 times.
✓ Branch 12 → 14 taken 14 times.
✓ Branch 14 → 15 taken 14 times.
✓ Branch 14 → 16 taken 73 times.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
|
101 | const QString key = field == QLatin1String("phones") && !digits(value).isEmpty() ? digits(value) : value.trimmed().toLower(); |
| 54 |
2/2✓ Branch 18 → 19 taken 87 times.
✓ Branch 19 → 20 taken 87 times.
|
174 | return field + QLatin1Char(':') + key; |
| 55 | 87 | } | |
| 56 | |||
| 57 | 73 | QString listKey(const QString &field) { | |
| 58 |
3/6✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 73 times.
✓ Branch 12 → 13 taken 73 times.
✗ Branch 12 → 14 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 73 times.
|
146 | return field == QLatin1String("addresses") ? QStringLiteral("oneLine") : QStringLiteral("value"); |
| 59 | } | ||
| 60 | |||
| 61 | // Removes the values whose id is excluded (Sprint 107 D-16). | ||
| 62 | 52 | QVariantList without(const QVariantList &values, const QString &field, const QStringList &excluded) { | |
| 63 | 52 | QVariantList kept; | |
| 64 |
2/2✓ Branch 22 → 4 taken 41 times.
✓ Branch 22 → 23 taken 52 times.
|
93 | for (const QVariant &value : values) |
| 65 |
8/8✓ Branch 5 → 6 taken 41 times.
✓ Branch 7 → 8 taken 41 times.
✓ Branch 8 → 9 taken 41 times.
✓ Branch 9 → 10 taken 41 times.
✓ Branch 10 → 11 taken 41 times.
✓ Branch 18 → 19 taken 39 times.
✓ Branch 18 → 20 taken 2 times.
✓ Branch 19 → 20 taken 39 times.
|
41 | if (!excluded.contains(valueId(field, value.toMap().value(listKey(field)).toString()))) kept.append(value); |
| 66 | 52 | return kept; | |
| 67 | ✗ | } | |
| 68 | |||
| 69 | 24 | int completeness(const QVariantMap &card) { | |
| 70 | 24 | int score = 0; | |
| 71 |
5/5✓ Branch 3 → 4 taken 120 times.
✓ Branch 5 → 6 taken 104 times.
✓ Branch 5 → 7 taken 16 times.
✓ Branch 10 → 3 taken 120 times.
✓ Branch 10 → 11 taken 24 times.
|
144 | for (const char *field : kScalarFields) score += text(card, field).isEmpty() ? 0 : 2; |
| 72 |
5/5✓ Branch 12 → 13 taken 144 times.
✓ Branch 14 → 15 taken 120 times.
✓ Branch 14 → 16 taken 24 times.
✓ Branch 19 → 12 taken 144 times.
✓ Branch 19 → 20 taken 24 times.
|
168 | for (const char *field : kNameFields) score += text(card, field).isEmpty() ? 0 : 1; |
| 73 |
5/5✓ Branch 24 → 25 taken 96 times.
✓ Branch 25 → 26 taken 96 times.
✓ Branch 26 → 27 taken 96 times.
✓ Branch 33 → 22 taken 96 times.
✓ Branch 33 → 34 taken 24 times.
|
120 | for (const char *list : {"emails", "phones", "addresses", "urls"}) score += 2 * int(card.value(QLatin1String(list)).toList().size()); |
| 74 |
2/2✓ Branch 38 → 39 taken 24 times.
✓ Branch 39 → 40 taken 24 times.
|
48 | score += int(card.value(QStringLiteral("categories")).toStringList().size()); |
| 75 |
3/3✓ Branch 46 → 47 taken 24 times.
✓ Branch 48 → 49 taken 21 times.
✓ Branch 48 → 50 taken 3 times.
|
24 | score += text(card, "note").isEmpty() ? 0 : 1; |
| 76 |
3/4✓ Branch 56 → 57 taken 24 times.
✓ Branch 57 → 58 taken 24 times.
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 24 times.
|
48 | score += card.value(QStringLiteral("hasPhoto")).toBool() ? 3 : 0; |
| 77 | 24 | return score; | |
| 78 | } | ||
| 79 | |||
| 80 | } // namespace | ||
| 81 | |||
| 82 | 12 | bool ContactMerge::samePhone(const QString &a, const QString &b) { | |
| 83 |
2/2✓ Branch 2 → 3 taken 12 times.
✓ Branch 3 → 4 taken 12 times.
|
12 | const QString left = digits(a), right = digits(b); |
| 84 |
3/7✓ Branch 5 → 6 taken 12 times.
✗ Branch 5 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 12 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 12 times.
✗ Branch 11 → 12 not taken.
|
12 | if (left.isEmpty() || right.isEmpty()) return sameText(a, b); |
| 85 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 12 times.
|
12 | if (left == right) return true; |
| 86 | // "+49 30 1234567" (49301234567) and "030 1234567" (301234567): one ends | ||
| 87 | // with the other and the difference is a country code (1–3 digits). | ||
| 88 |
2/2✓ Branch 18 → 19 taken 6 times.
✓ Branch 18 → 20 taken 6 times.
|
12 | const QString &longer = left.size() > right.size() ? left : right; |
| 89 |
2/2✓ Branch 23 → 24 taken 6 times.
✓ Branch 23 → 25 taken 6 times.
|
12 | const QString &shorter = left.size() > right.size() ? right : left; |
| 90 |
5/7✓ Branch 27 → 28 taken 12 times.
✗ Branch 27 → 34 not taken.
✓ Branch 28 → 29 taken 12 times.
✓ Branch 29 → 30 taken 11 times.
✓ Branch 29 → 34 taken 1 time.
✓ Branch 32 → 33 taken 11 times.
✗ Branch 32 → 34 not taken.
|
12 | return shorter.size() >= 6 && longer.endsWith(shorter) && longer.size() - shorter.size() <= 3; |
| 91 | 12 | } | |
| 92 | |||
| 93 | 7 | int ContactMerge::keeperIndex(const QList<QVariantMap> &cards) { | |
| 94 | 7 | int best = 0; | |
| 95 |
2/2✓ Branch 11 → 3 taken 12 times.
✓ Branch 11 → 12 taken 7 times.
|
19 | for (int i = 1; i < cards.size(); ++i) |
| 96 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 12 times.
|
12 | if (completeness(cards.at(i)) > completeness(cards.at(best))) best = i; |
| 97 | 7 | return best; | |
| 98 | } | ||
| 99 | |||
| 100 | 7 | QVariantList ContactMerge::conflicts(const QList<QVariantMap> &cards, int keeper) { | |
| 101 | 7 | QVariantList result; | |
| 102 | 42 | const auto add = [&](const QString &field, const QString &label, const std::function<QString(const QVariantMap &)> &value) { | |
| 103 | 42 | QVariantList options; | |
| 104 | 42 | QStringList seen; | |
| 105 | 42 | int chosen = -1; | |
| 106 |
2/2✓ Branch 76 → 3 taken 114 times.
✓ Branch 76 → 77 taken 42 times.
|
156 | for (int i = 0; i < cards.size(); ++i) { |
| 107 |
1/1✓ Branch 4 → 5 taken 114 times.
|
114 | const QString current = value(cards.at(i)); |
| 108 |
2/2✓ Branch 6 → 7 taken 82 times.
✓ Branch 6 → 8 taken 32 times.
|
114 | if (current.isEmpty()) continue; |
| 109 |
2/2✓ Branch 8 → 9 taken 12 times.
✓ Branch 8 → 11 taken 20 times.
|
32 | if (i == keeper) chosen = int(options.size()); |
| 110 | 32 | bool known = false; | |
| 111 |
8/9✓ Branch 11 → 12 taken 32 times.
✓ Branch 12 → 13 taken 32 times.
✓ Branch 15 → 16 taken 16 times.
✗ Branch 15 → 18 not taken.
✓ Branch 16 → 17 taken 16 times.
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 19 taken 11 times.
✓ Branch 22 → 14 taken 16 times.
✓ Branch 22 → 23 taken 32 times.
|
48 | for (const QString &other : seen) known = known || sameText(other, current); |
| 112 |
2/2✓ Branch 23 → 24 taken 5 times.
✓ Branch 23 → 47 taken 27 times.
|
32 | if (known) { |
| 113 |
2/2✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 46 taken 4 times.
|
5 | if (i == keeper) // the keeper's value is already listed under another card |
| 114 |
2/2✓ Branch 45 → 26 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
|
2 | for (int o = 0; o < options.size(); ++o) |
| 115 |
5/6✓ Branch 27 → 28 taken 1 time.
✓ Branch 32 → 33 taken 1 time.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 43 not taken.
|
2 | if (sameText(options.at(o).toMap().value(QStringLiteral("text")).toString(), current)) chosen = o; |
| 116 | 5 | continue; | |
| 117 | 5 | } | |
| 118 |
1/1✓ Branch 47 → 48 taken 27 times.
|
27 | seen.append(current); |
| 119 |
3/5✓ Branch 58 → 59 taken 27 times.
✓ Branch 62 → 63 taken 54 times.
✓ Branch 62 → 64 taken 27 times.
✗ Branch 161 → 162 not taken.
✗ Branch 161 → 163 not taken.
|
135 | options.append(QVariantMap{{QStringLiteral("text"), current}, {QStringLiteral("from"), i}}); |
| 120 | 114 | } | |
| 121 |
2/2✓ Branch 78 → 79 taken 33 times.
✓ Branch 78 → 80 taken 9 times.
|
42 | if (options.size() < 2) return; |
| 122 |
1/2✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 9 times.
|
9 | if (chosen < 0) chosen = 0; |
| 123 |
1/1✓ Branch 107 → 108 taken 9 times.
|
45 | result.append(QVariantMap{{QStringLiteral("field"), field}, {QStringLiteral("label"), label}, {QStringLiteral("options"), options}, |
| 124 |
4/6✓ Branch 98 → 99 taken 9 times.
✓ Branch 103 → 104 taken 9 times.
✓ Branch 111 → 112 taken 36 times.
✓ Branch 111 → 113 taken 9 times.
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 195 not taken.
|
63 | {QStringLiteral("chosen"), options.at(chosen).toMap().value(QStringLiteral("from"))}}); |
| 125 |
6/14✓ Branch 56 → 57 taken 27 times.
✓ Branch 105 → 106 taken 9 times.
✓ Branch 128 → 129 taken 9 times.
✓ Branch 128 → 130 taken 33 times.
✓ Branch 132 → 133 taken 9 times.
✓ Branch 132 → 135 taken 33 times.
✗ Branch 176 → 177 not taken.
✗ Branch 176 → 180 not taken.
✗ Branch 178 → 179 not taken.
✗ Branch 178 → 180 not taken.
✗ Branch 235 → 236 not taken.
✗ Branch 235 → 239 not taken.
✗ Branch 237 → 238 not taken.
✗ Branch 237 → 239 not taken.
|
201 | }; |
| 126 |
2/2✓ Branch 3 → 4 taken 7 times.
✓ Branch 7 → 8 taken 7 times.
|
33 | add(QStringLiteral("name"), tr("Name"), [](const QVariantMap &card) { return nameOf(card); }); |
| 127 |
2/2✓ Branch 13 → 14 taken 7 times.
✓ Branch 17 → 18 taken 7 times.
|
33 | add(QStringLiteral("organization"), tr("Organization"), [](const QVariantMap &card) { return text(card, "organization"); }); |
| 128 |
2/2✓ Branch 23 → 24 taken 7 times.
✓ Branch 27 → 28 taken 7 times.
|
33 | add(QStringLiteral("department"), tr("Department"), [](const QVariantMap &card) { return text(card, "department"); }); |
| 129 |
2/2✓ Branch 33 → 34 taken 7 times.
✓ Branch 37 → 38 taken 7 times.
|
33 | add(QStringLiteral("title"), tr("Job title"), [](const QVariantMap &card) { return text(card, "title"); }); |
| 130 |
2/2✓ Branch 43 → 44 taken 7 times.
✓ Branch 47 → 48 taken 7 times.
|
33 | add(QStringLiteral("nickname"), tr("Nickname"), [](const QVariantMap &card) { return text(card, "nickname"); }); |
| 131 |
2/2✓ Branch 53 → 54 taken 7 times.
✓ Branch 57 → 58 taken 7 times.
|
33 | add(QStringLiteral("birthday"), tr("Birthday"), [](const QVariantMap &card) { return text(card, "birthday"); }); |
| 132 | 7 | return result; | |
| 133 | ✗ | } | |
| 134 | |||
| 135 | 7 | QVariantList ContactMerge::setRows(const QList<QVariantMap> &cards, int keeper) { | |
| 136 | 7 | QVariantList rows; | |
| 137 |
1/1✓ Branch 5 → 6 taken 7 times.
|
14 | const QList<QPair<QString, QString>> lists{{QStringLiteral("emails"), tr("E-mail addresses")}, |
| 138 |
1/1✓ Branch 10 → 11 taken 7 times.
|
14 | {QStringLiteral("phones"), tr("Phone numbers")}, |
| 139 |
1/1✓ Branch 15 → 16 taken 7 times.
|
14 | {QStringLiteral("addresses"), tr("Postal addresses")}, |
| 140 |
1/1✓ Branch 20 → 21 taken 7 times.
|
14 | {QStringLiteral("urls"), tr("Links")}, |
| 141 |
3/5✓ Branch 25 → 26 taken 7 times.
✓ Branch 29 → 30 taken 35 times.
✓ Branch 29 → 31 taken 7 times.
✗ Branch 252 → 253 not taken.
✗ Branch 252 → 254 not taken.
|
49 | {QStringLiteral("categories"), tr("Groups")}}; |
| 142 |
2/2✓ Branch 247 → 48 taken 35 times.
✓ Branch 247 → 248 taken 7 times.
|
42 | for (const auto &[field, label] : lists) { |
| 143 | 35 | QVariantList values; | |
| 144 | 35 | QStringList ids; | |
| 145 | // The kept card first, so its values lead the row. | ||
| 146 |
1/1✓ Branch 51 → 52 taken 35 times.
|
35 | QList<int> order{keeper}; |
| 147 |
2/2✓ Branch 57 → 53 taken 95 times.
✓ Branch 57 → 58 taken 35 times.
|
130 | for (int i = 0; i < cards.size(); ++i) |
| 148 |
3/3✓ Branch 53 → 54 taken 60 times.
✓ Branch 53 → 55 taken 35 times.
✓ Branch 54 → 55 taken 60 times.
|
95 | if (i != keeper) order.append(i); |
| 149 |
4/4✓ Branch 58 → 59 taken 35 times.
✓ Branch 59 → 60 taken 35 times.
✓ Branch 212 → 61 taken 95 times.
✓ Branch 212 → 213 taken 35 times.
|
130 | for (const int index : order) { |
| 150 | 95 | QStringList texts; | |
| 151 |
2/2✓ Branch 64 → 65 taken 19 times.
✓ Branch 64 → 74 taken 76 times.
|
95 | if (field == QLatin1String("categories")) |
| 152 |
2/2✓ Branch 67 → 68 taken 19 times.
✓ Branch 68 → 69 taken 19 times.
|
19 | texts = cards.at(index).value(field).toStringList(); |
| 153 | else | ||
| 154 |
6/6✓ Branch 76 → 77 taken 76 times.
✓ Branch 77 → 78 taken 76 times.
✓ Branch 80 → 81 taken 76 times.
✓ Branch 81 → 82 taken 76 times.
✓ Branch 99 → 83 taken 32 times.
✓ Branch 99 → 100 taken 76 times.
|
108 | for (const QVariant &value : cards.at(index).value(field).toList()) |
| 155 |
6/6✓ Branch 84 → 85 taken 32 times.
✓ Branch 86 → 87 taken 32 times.
✓ Branch 87 → 88 taken 32 times.
✓ Branch 88 → 89 taken 32 times.
✓ Branch 89 → 90 taken 32 times.
✓ Branch 90 → 91 taken 32 times.
|
108 | texts.append(value.toMap().value(listKey(field)).toString().trimmed()); |
| 156 |
2/2✓ Branch 208 → 105 taken 37 times.
✓ Branch 208 → 209 taken 95 times.
|
132 | for (const QString &text : std::as_const(texts)) { |
| 157 |
1/2✗ Branch 107 → 108 not taken.
✓ Branch 107 → 109 taken 37 times.
|
46 | if (text.isEmpty()) continue; |
| 158 |
1/1✓ Branch 109 → 110 taken 37 times.
|
37 | QString id = valueId(field, text); |
| 159 |
2/2✓ Branch 112 → 113 taken 8 times.
✓ Branch 112 → 131 taken 29 times.
|
37 | if (field == QLatin1String("phones")) |
| 160 |
2/2✓ Branch 129 → 116 taken 4 times.
✓ Branch 129 → 130 taken 8 times.
|
12 | for (const QString &known : std::as_const(ids)) // "+49 30 …" and "030 …" are one number |
| 161 |
4/5✓ Branch 117 → 118 taken 4 times.
✓ Branch 121 → 122 taken 4 times.
✓ Branch 122 → 123 taken 4 times.
✓ Branch 125 → 126 taken 4 times.
✗ Branch 125 → 127 not taken.
|
4 | if (samePhone(known.mid(known.indexOf(QLatin1Char(':')) + 1), digits(text))) id = known; |
| 162 | 37 | const int existing = int(ids.indexOf(id)); | |
| 163 |
2/2✓ Branch 132 → 133 taken 9 times.
✓ Branch 132 → 167 taken 28 times.
|
37 | if (existing >= 0) { |
| 164 |
1/1✓ Branch 134 → 135 taken 9 times.
|
9 | QVariantMap entry = values.at(existing).toMap(); |
| 165 |
2/2✓ Branch 139 → 140 taken 9 times.
✓ Branch 140 → 141 taken 9 times.
|
18 | QVariantList from = entry.value(QStringLiteral("from")).toList(); |
| 166 |
2/3✓ Branch 146 → 147 taken 9 times.
✗ Branch 146 → 151 not taken.
✓ Branch 148 → 149 taken 9 times.
|
9 | if (!from.contains(index)) from.append(index); |
| 167 |
1/1✓ Branch 155 → 156 taken 9 times.
|
18 | entry.insert(QStringLiteral("from"), from); |
| 168 |
1/1✓ Branch 160 → 161 taken 9 times.
|
9 | values[existing] = entry; |
| 169 | 9 | continue; | |
| 170 | 9 | } | |
| 171 |
1/1✓ Branch 167 → 168 taken 28 times.
|
28 | ids.append(id); |
| 172 |
1/1✓ Branch 184 → 185 taken 28 times.
|
112 | values.append(QVariantMap{{QStringLiteral("id"), id}, {QStringLiteral("text"), text}, |
| 173 |
4/8✓ Branch 188 → 189 taken 84 times.
✓ Branch 188 → 190 taken 28 times.
✓ Branch 192 → 193 taken 28 times.
✓ Branch 192 → 194 taken 28 times.
✗ Branch 387 → 388 not taken.
✗ Branch 387 → 389 not taken.
✗ Branch 393 → 394 not taken.
✗ Branch 393 → 395 not taken.
|
168 | {QStringLiteral("from"), QVariantList{index}}}); |
| 174 | 37 | } | |
| 175 | 95 | } | |
| 176 |
2/2✓ Branch 214 → 215 taken 15 times.
✓ Branch 214 → 242 taken 20 times.
|
35 | if (!values.isEmpty()) |
| 177 |
3/5✓ Branch 229 → 230 taken 15 times.
✓ Branch 233 → 234 taken 45 times.
✓ Branch 233 → 235 taken 15 times.
✗ Branch 442 → 443 not taken.
✗ Branch 442 → 444 not taken.
|
105 | rows.append(QVariantMap{{QStringLiteral("field"), field}, {QStringLiteral("label"), label}, {QStringLiteral("values"), values}}); |
| 178 | 35 | } | |
| 179 | 7 | return rows; | |
| 180 | 221 | } | |
| 181 | |||
| 182 | 13 | QVariantMap ContactMerge::merged(const QList<QVariantMap> &cards, int keeper, const QMap<QString, int> &choices, | |
| 183 | const QStringList &excluded) { | ||
| 184 |
3/6✓ Branch 2 → 3 taken 13 times.
✗ Branch 2 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 13 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 13 times.
|
13 | if (keeper < 0 || keeper >= cards.size()) return {}; |
| 185 | 13 | const QVariantMap &keep = cards.at(keeper); | |
| 186 |
2/2✓ Branch 14 → 15 taken 13 times.
✓ Branch 15 → 16 taken 13 times.
|
26 | QVariantList emails = keep.value(QStringLiteral("emails")).toList(); |
| 187 |
2/2✓ Branch 24 → 25 taken 13 times.
✓ Branch 25 → 26 taken 13 times.
|
26 | QVariantList phones = keep.value(QStringLiteral("phones")).toList(); |
| 188 |
2/2✓ Branch 34 → 35 taken 13 times.
✓ Branch 35 → 36 taken 13 times.
|
26 | QVariantList urls = keep.value(QStringLiteral("urls")).toList(); |
| 189 |
2/2✓ Branch 44 → 45 taken 13 times.
✓ Branch 45 → 46 taken 13 times.
|
26 | QVariantList addresses = keep.value(QStringLiteral("addresses")).toList(); |
| 190 |
2/2✓ Branch 54 → 55 taken 13 times.
✓ Branch 55 → 56 taken 13 times.
|
26 | QStringList categories = keep.value(QStringLiteral("categories")).toStringList(); |
| 191 | 13 | QStringList notes; | |
| 192 |
5/5✓ Branch 60 → 61 taken 13 times.
✓ Branch 63 → 64 taken 2 times.
✓ Branch 63 → 68 taken 11 times.
✓ Branch 64 → 65 taken 2 times.
✓ Branch 65 → 66 taken 2 times.
|
13 | if (!text(keep, "note").isEmpty()) notes << text(keep, "note"); |
| 193 | 13 | QVariantMap fields; | |
| 194 |
2/2✓ Branch 206 → 69 taken 35 times.
✓ Branch 206 → 207 taken 13 times.
|
48 | for (int i = 0; i < cards.size(); ++i) { |
| 195 |
2/2✓ Branch 69 → 70 taken 13 times.
✓ Branch 69 → 71 taken 22 times.
|
35 | if (i == keeper) continue; |
| 196 | 22 | const QVariantMap &other = cards.at(i); | |
| 197 |
3/3✓ Branch 79 → 80 taken 22 times.
✓ Branch 80 → 81 taken 22 times.
✓ Branch 81 → 82 taken 22 times.
|
44 | unite(emails, other.value(QStringLiteral("emails")).toList(), QStringLiteral("value"), sameText); |
| 198 |
3/3✓ Branch 96 → 97 taken 22 times.
✓ Branch 97 → 98 taken 22 times.
✓ Branch 98 → 99 taken 22 times.
|
44 | unite(phones, other.value(QStringLiteral("phones")).toList(), QStringLiteral("value"), samePhone); |
| 199 |
3/3✓ Branch 113 → 114 taken 22 times.
✓ Branch 114 → 115 taken 22 times.
✓ Branch 115 → 116 taken 22 times.
|
44 | unite(urls, other.value(QStringLiteral("urls")).toList(), QStringLiteral("value"), sameText); |
| 200 |
3/3✓ Branch 130 → 131 taken 22 times.
✓ Branch 131 → 132 taken 22 times.
✓ Branch 132 → 133 taken 22 times.
|
44 | unite(addresses, other.value(QStringLiteral("addresses")).toList(), QStringLiteral("oneLine"), sameText); |
| 201 |
6/6✓ Branch 144 → 145 taken 22 times.
✓ Branch 145 → 146 taken 22 times.
✓ Branch 150 → 151 taken 22 times.
✓ Branch 151 → 152 taken 22 times.
✓ Branch 159 → 153 taken 4 times.
✓ Branch 159 → 160 taken 22 times.
|
48 | for (const QString &category : other.value(QStringLiteral("categories")).toStringList()) |
| 202 |
2/3✓ Branch 155 → 156 taken 4 times.
✗ Branch 155 → 157 not taken.
✓ Branch 156 → 157 taken 4 times.
|
26 | if (!categories.contains(category, Qt::CaseInsensitive)) categories.append(category); |
| 203 |
1/1✓ Branch 161 → 162 taken 22 times.
|
22 | const QString note = text(other, "note"); |
| 204 |
6/7✓ Branch 163 → 164 taken 4 times.
✓ Branch 163 → 167 taken 18 times.
✓ Branch 165 → 166 taken 4 times.
✗ Branch 165 → 167 not taken.
✓ Branch 168 → 169 taken 4 times.
✓ Branch 168 → 170 taken 18 times.
✓ Branch 169 → 170 taken 4 times.
|
22 | if (!note.isEmpty() && !notes.contains(note)) notes << note; |
| 205 | // Empty fields of the kept card are filled from the others. | ||
| 206 |
2/2✓ Branch 200 → 171 taken 110 times.
✓ Branch 200 → 201 taken 22 times.
|
132 | for (const char *field : kScalarFields) |
| 207 |
17/24✓ Branch 171 → 172 taken 110 times.
✓ Branch 173 → 174 taken 97 times.
✓ Branch 173 → 182 taken 13 times.
✓ Branch 175 → 176 taken 97 times.
✓ Branch 176 → 177 taken 97 times.
✓ Branch 177 → 178 taken 94 times.
✓ Branch 177 → 182 taken 3 times.
✓ Branch 178 → 179 taken 94 times.
✓ Branch 180 → 181 taken 8 times.
✓ Branch 180 → 182 taken 86 times.
✓ Branch 183 → 184 taken 94 times.
✓ Branch 183 → 185 taken 16 times.
✓ Branch 185 → 186 taken 97 times.
✓ Branch 185 → 187 taken 13 times.
✓ Branch 187 → 188 taken 110 times.
✗ Branch 187 → 189 not taken.
✓ Branch 189 → 190 taken 8 times.
✓ Branch 189 → 199 taken 102 times.
✗ Branch 551 → 552 not taken.
✗ Branch 551 → 553 not taken.
✗ Branch 555 → 556 not taken.
✗ Branch 555 → 557 not taken.
✗ Branch 560 → 561 not taken.
✗ Branch 560 → 562 not taken.
|
110 | if (text(keep, field).isEmpty() && !fields.contains(QLatin1String(field)) && !text(other, field).isEmpty()) |
| 208 |
3/3✓ Branch 190 → 191 taken 8 times.
✓ Branch 193 → 194 taken 8 times.
✓ Branch 194 → 195 taken 8 times.
|
8 | fields.insert(QLatin1String(field), text(other, field)); |
| 209 | 22 | } | |
| 210 |
2/2✓ Branch 210 → 211 taken 13 times.
✓ Branch 215 → 216 taken 13 times.
|
26 | fields.insert(QStringLiteral("emails"), without(emails, QStringLiteral("emails"), excluded)); |
| 211 |
2/2✓ Branch 225 → 226 taken 13 times.
✓ Branch 230 → 231 taken 13 times.
|
26 | fields.insert(QStringLiteral("phones"), without(phones, QStringLiteral("phones"), excluded)); |
| 212 |
2/2✓ Branch 240 → 241 taken 13 times.
✓ Branch 245 → 246 taken 13 times.
|
26 | fields.insert(QStringLiteral("urls"), without(urls, QStringLiteral("urls"), excluded)); |
| 213 |
2/2✓ Branch 255 → 256 taken 13 times.
✓ Branch 260 → 261 taken 13 times.
|
26 | fields.insert(QStringLiteral("addresses"), without(addresses, QStringLiteral("addresses"), excluded)); |
| 214 | 13 | QStringList keptCategories; | |
| 215 |
2/2✓ Branch 283 → 270 taken 9 times.
✓ Branch 283 → 284 taken 13 times.
|
22 | for (const QString &category : std::as_const(categories)) |
| 216 |
4/4✓ Branch 274 → 275 taken 9 times.
✓ Branch 279 → 280 taken 8 times.
✓ Branch 279 → 281 taken 1 time.
✓ Branch 280 → 281 taken 8 times.
|
9 | if (!excluded.contains(valueId(QStringLiteral("categories"), category))) keptCategories.append(category); |
| 217 |
1/1✓ Branch 288 → 289 taken 13 times.
|
26 | fields.insert(QStringLiteral("categories"), keptCategories); |
| 218 |
12/14✓ Branch 293 → 294 taken 12 times.
✓ Branch 293 → 300 taken 1 time.
✓ Branch 295 → 296 taken 4 times.
✓ Branch 295 → 301 taken 8 times.
✓ Branch 296 → 297 taken 4 times.
✓ Branch 297 → 298 taken 4 times.
✓ Branch 299 → 300 taken 3 times.
✓ Branch 299 → 301 taken 1 time.
✓ Branch 302 → 303 taken 4 times.
✓ Branch 302 → 304 taken 9 times.
✓ Branch 304 → 305 taken 4 times.
✓ Branch 304 → 321 taken 9 times.
✗ Branch 666 → 667 not taken.
✗ Branch 666 → 668 not taken.
|
13 | if (notes.size() > 1 || (notes.size() == 1 && notes.first() != text(keep, "note"))) |
| 219 |
2/2✓ Branch 308 → 309 taken 4 times.
✓ Branch 313 → 314 taken 4 times.
|
8 | fields.insert(QStringLiteral("note"), notes.join(QStringLiteral("\n\n"))); |
| 220 | // Conflicts: the chosen card's value. | ||
| 221 |
4/4✓ Branch 321 → 322 taken 13 times.
✓ Branch 374 → 375 taken 15 times.
✓ Branch 376 → 323 taken 2 times.
✓ Branch 376 → 377 taken 13 times.
|
15 | for (auto it = choices.begin(); it != choices.end(); ++it) { |
| 222 |
4/8✓ Branch 324 → 325 taken 2 times.
✗ Branch 324 → 330 not taken.
✓ Branch 327 → 328 taken 2 times.
✗ Branch 327 → 330 not taken.
✗ Branch 329 → 330 not taken.
✓ Branch 329 → 331 taken 2 times.
✗ Branch 332 → 333 not taken.
✓ Branch 332 → 334 taken 2 times.
|
2 | if (it.value() < 0 || it.value() >= cards.size() || it.value() == keeper) continue; |
| 223 | 2 | const QVariantMap &source = cards.at(it.value()); | |
| 224 |
2/2✓ Branch 339 → 340 taken 1 time.
✓ Branch 339 → 351 taken 1 time.
|
2 | if (it.key() == QLatin1String("name")) { |
| 225 |
5/5✓ Branch 341 → 342 taken 6 times.
✓ Branch 344 → 345 taken 6 times.
✓ Branch 345 → 346 taken 6 times.
✓ Branch 350 → 341 taken 6 times.
✓ Branch 350 → 373 taken 1 time.
|
7 | for (const char *field : kNameFields) fields.insert(QLatin1String(field), text(source, field)); |
| 226 | } else { | ||
| 227 |
2/2✓ Branch 372 → 352 taken 5 times.
✓ Branch 372 → 373 taken 1 time.
|
6 | for (const char *field : kScalarFields) |
| 228 |
10/13✓ Branch 355 → 356 taken 1 time.
✓ Branch 355 → 360 taken 4 times.
✓ Branch 356 → 357 taken 1 time.
✓ Branch 358 → 359 taken 1 time.
✗ Branch 358 → 360 not taken.
✓ Branch 361 → 362 taken 1 time.
✓ Branch 361 → 363 taken 4 times.
✓ Branch 363 → 364 taken 1 time.
✓ Branch 363 → 371 taken 4 times.
✓ Branch 364 → 365 taken 1 time.
✓ Branch 367 → 368 taken 1 time.
✗ Branch 698 → 699 not taken.
✗ Branch 698 → 700 not taken.
|
5 | if (it.key() == QLatin1String(field) && !text(source, field).isEmpty()) fields.insert(it.key(), text(source, field)); |
| 229 | } | ||
| 230 | } | ||
| 231 | 13 | return fields; | |
| 232 | 13 | } | |
| 233 |