presentation/FolderPresentationModel.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "FolderPresentationModel.h" | ||
| 2 | #include "service/ImapResponseParser.h" | ||
| 3 | #include <algorithm> | ||
| 4 | |||
| 5 | 35151 | FolderPresentationModel::Node *FolderPresentationModel::node(const QModelIndex &index) const { | |
| 6 |
3/4✓ Branch 3 → 4 taken 35112 times.
✓ Branch 3 → 7 taken 39 times.
✓ Branch 5 → 6 taken 35112 times.
✗ Branch 5 → 7 not taken.
|
35151 | return index.isValid() && index.model() == this ? static_cast<Node *>(index.internalPointer()) : nullptr; |
| 7 | } | ||
| 8 | |||
| 9 | 18022 | QModelIndex FolderPresentationModel::index(int row, int column, const QModelIndex &parent) const { | |
| 10 |
6/10✓ Branch 2 → 3 taken 18022 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 18022 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 287 times.
✓ Branch 5 → 9 taken 17735 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 287 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 18022 times.
|
18022 | if (column != 0 || row < 0 || (parent.isValid() && parent.column() != 0)) return {}; |
| 11 |
2/2✓ Branch 13 → 14 taken 287 times.
✓ Branch 13 → 15 taken 17735 times.
|
18022 | const auto *owner = parent.isValid() ? node(parent) : &m_root; |
| 12 |
5/6✓ Branch 16 → 17 taken 18022 times.
✗ Branch 16 → 19 not taken.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 18021 times.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 23 taken 18021 times.
|
18022 | if (!owner || row >= owner->children.size()) return {}; |
| 13 | 18021 | return createIndex(row, column, owner->children[row]); | |
| 14 | } | ||
| 15 | |||
| 16 | 20624 | QModelIndex FolderPresentationModel::parent(const QModelIndex &index) const { | |
| 17 | 20624 | const auto *child = node(index); | |
| 18 |
5/6✓ Branch 3 → 4 taken 20598 times.
✓ Branch 3 → 6 taken 26 times.
✓ Branch 4 → 5 taken 897 times.
✓ Branch 4 → 6 taken 19701 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 897 times.
|
20624 | if (!child || child->parent == &m_root || !child->parent) return {}; |
| 19 | 897 | return createIndex(child->parent->row, 0, child->parent); | |
| 20 | } | ||
| 21 | |||
| 22 | 4990 | int FolderPresentationModel::rowCount(const QModelIndex &parent) const { | |
| 23 |
4/6✓ Branch 3 → 4 taken 2417 times.
✓ Branch 3 → 7 taken 2573 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2417 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 4990 times.
|
4990 | if (parent.isValid() && parent.column() != 0) return 0; |
| 24 |
2/2✓ Branch 11 → 12 taken 2417 times.
✓ Branch 11 → 13 taken 2573 times.
|
4990 | const auto *owner = parent.isValid() ? node(parent) : &m_root; |
| 25 |
1/2✓ Branch 14 → 15 taken 4990 times.
✗ Branch 14 → 17 not taken.
|
4990 | return owner ? owner->children.size() : 0; |
| 26 | } | ||
| 27 | |||
| 28 | 24109 | int FolderPresentationModel::columnCount(const QModelIndex &) const { return 1; } | |
| 29 | |||
| 30 | 44 | Qt::ItemFlags FolderPresentationModel::flags(const QModelIndex &index) const { | |
| 31 | 44 | const auto *item = node(index); | |
| 32 |
2/2✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 7 taken 31 times.
|
44 | if (!item) return Qt::NoItemFlags; |
| 33 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 24 times.
|
24 | return Qt::ItemIsEnabled | ((!item->synthetic && !item->folder.isNoselect()) |
| 34 |
2/2✓ Branch 7 → 8 taken 24 times.
✓ Branch 7 → 11 taken 7 times.
|
55 | ? Qt::ItemIsSelectable : Qt::NoItemFlags); |
| 35 | } | ||
| 36 | |||
| 37 | 11779 | QVariant FolderPresentationModel::data(const QModelIndex &index, int role) const { | |
| 38 | 11779 | const auto *item = node(index); | |
| 39 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 11779 times.
|
11779 | if (!item) return {}; |
| 40 |
8/9✓ Branch 5 → 6 taken 1875 times.
✓ Branch 5 → 7 taken 1864 times.
✓ Branch 5 → 8 taken 1852 times.
✓ Branch 5 → 14 taken 1937 times.
✓ Branch 5 → 15 taken 1 time.
✗ Branch 5 → 22 not taken.
✓ Branch 5 → 23 taken 2078 times.
✓ Branch 5 → 34 taken 2076 times.
✓ Branch 5 → 38 taken 96 times.
|
11779 | switch (role) { |
| 41 | 1875 | case PathRole: return item->folder.path; | |
| 42 | 1864 | case Qt::DisplayRole: | |
| 43 | 1864 | case NameRole: return item->folder.name; | |
| 44 |
4/4✓ Branch 8 → 9 taken 1837 times.
✓ Branch 8 → 12 taken 15 times.
✓ Branch 10 → 11 taken 1801 times.
✓ Branch 10 → 12 taken 36 times.
|
1852 | case SelectableRole: return !item->synthetic && !item->folder.isNoselect(); |
| 45 | 1937 | case UnreadRole: return item->unread; | |
| 46 | 2 | case KindRole: return QStringLiteral("mailbox"); | |
| 47 | ✗ | case ResultCountRole: return -1; | |
| 48 | 2078 | case IconRole: { | |
| 49 | 2078 | const auto it = m_appearance.constFind(item->folder.path); | |
| 50 |
4/4✓ Branch 26 → 27 taken 2058 times.
✓ Branch 26 → 31 taken 20 times.
✓ Branch 28 → 29 taken 2057 times.
✓ Branch 28 → 31 taken 1 time.
|
2078 | return it != m_appearance.constEnd() && it->glyph > 0 ? it->glyph : m_fallbackGlyph; |
| 51 | } | ||
| 52 | 2076 | case ColorRole: return m_appearance.value(item->folder.path).color; | |
| 53 | 96 | default: return {}; | |
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | 722 | QHash<int, QByteArray> FolderPresentationModel::roleNames() const { | |
| 58 | ✗ | return {{PathRole, "folderPath"}, {NameRole, "folderName"}, | |
| 59 | ✗ | {SelectableRole, "selectable"}, {UnreadRole, "unreadCount"}, | |
| 60 | ✗ | {KindRole, "nodeKind"}, {ResultCountRole, "resultCount"}, | |
| 61 |
2/4✓ Branch 12 → 13 taken 5776 times.
✓ Branch 12 → 14 taken 722 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
|
6498 | {IconRole, "folderGlyph"}, {ColorRole, "folderColor"}}; |
| 62 | 722 | } | |
| 63 | |||
| 64 | 7366 | FolderPresentationModel::Node *FolderPresentationModel::ensureNode(const QString &path, | |
| 65 | const QString &delimiter) { | ||
| 66 | 7366 | QStringList missing; | |
| 67 | 7366 | auto currentPath = path; | |
| 68 | // Iterative construction handles deep namespaces without recursive stack growth. | ||
| 69 |
6/6✓ Branch 17 → 18 taken 12579 times.
✓ Branch 17 → 21 taken 2266 times.
✓ Branch 19 → 20 taken 7479 times.
✓ Branch 19 → 21 taken 5100 times.
✓ Branch 22 → 4 taken 7479 times.
✓ Branch 22 → 23 taken 7366 times.
|
14845 | while (!currentPath.isEmpty() && !m_paths.contains(currentPath)) { |
| 70 |
1/1✓ Branch 4 → 5 taken 7479 times.
|
7479 | missing.prepend(currentPath); |
| 71 |
3/3✓ Branch 6 → 7 taken 1832 times.
✓ Branch 6 → 8 taken 5647 times.
✓ Branch 8 → 9 taken 5647 times.
|
7479 | const int split = delimiter.isEmpty() ? -1 : currentPath.lastIndexOf(delimiter); |
| 72 |
3/3✓ Branch 10 → 11 taken 5213 times.
✓ Branch 10 → 12 taken 2266 times.
✓ Branch 11 → 13 taken 5213 times.
|
7479 | currentPath = split > 0 ? currentPath.left(split) : QString{}; |
| 73 | } | ||
| 74 | 7366 | auto *owner = m_paths.value(currentPath, &m_root); | |
| 75 |
4/4✓ Branch 24 → 25 taken 7366 times.
✓ Branch 25 → 26 taken 7366 times.
✓ Branch 52 → 27 taken 7479 times.
✓ Branch 52 → 53 taken 7366 times.
|
14845 | for (const auto &missingPath : missing) { |
| 76 |
1/1✓ Branch 28 → 29 taken 7479 times.
|
7479 | auto created = std::make_unique<Node>(); |
| 77 | 7479 | created->folder.path = missingPath; | |
| 78 | 7479 | created->folder.delimiter = delimiter; | |
| 79 |
3/3✓ Branch 34 → 35 taken 1832 times.
✓ Branch 34 → 36 taken 5647 times.
✓ Branch 37 → 38 taken 5647 times.
|
13126 | const auto leaf = delimiter.isEmpty() ? missingPath : missingPath.section(delimiter, -1); |
| 80 |
1/1✓ Branch 38 → 39 taken 7479 times.
|
7479 | created->folder.name = ImapResponseParser::decodeMailboxName(leaf); |
| 81 | 7479 | created->parent = owner; | |
| 82 | 7479 | auto *item = created.get(); | |
| 83 |
1/1✓ Branch 44 → 45 taken 7479 times.
|
7479 | owner->children.append(item); |
| 84 |
1/1✓ Branch 45 → 46 taken 7479 times.
|
7479 | m_paths.insert(missingPath, item); |
| 85 |
1/1✓ Branch 47 → 48 taken 7479 times.
|
7479 | m_nodes.push_back(std::move(created)); |
| 86 | 7479 | owner = item; | |
| 87 | 7479 | } | |
| 88 | 7366 | return owner; | |
| 89 | 7366 | } | |
| 90 | |||
| 91 | 834 | void FolderPresentationModel::setFolders(const QList<FolderInfo> &folders, | |
| 92 | const QStringList &hidden) { | ||
| 93 |
1/1✓ Branch 2 → 3 taken 834 times.
|
834 | beginResetModel(); |
| 94 |
1/1✓ Branch 3 → 4 taken 834 times.
|
834 | m_root.children.clear(); |
| 95 | 834 | m_paths.clear(); | |
| 96 | 834 | m_nodes.clear(); | |
| 97 |
1/1✓ Branch 6 → 7 taken 834 times.
|
834 | m_selectablePaths.clear(); |
| 98 |
1/1✓ Branch 7 → 8 taken 834 times.
|
834 | m_completionIndex.clear(); |
| 99 | 834 | m_completionIndexValid = false; | |
| 100 |
2/2✓ Branch 44 → 10 taken 7371 times.
✓ Branch 44 → 45 taken 834 times.
|
8205 | for (const auto &folder : folders) { |
| 101 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 7371 times.
|
7376 | if (folder.path.isEmpty()) continue; |
| 102 | 7371 | auto *existing = m_paths.value(folder.path); | |
| 103 |
4/4✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 18 taken 7368 times.
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 18 taken 1 time.
|
7371 | if (existing && !existing->synthetic) continue; |
| 104 |
1/1✓ Branch 20 → 21 taken 7369 times.
|
7369 | const bool hide = std::any_of(hidden.begin(), hidden.end(), [&](const QString &path) { |
| 105 |
4/6✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 11 taken 1 time.
✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 12 not taken.
✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 12 not taken.
|
15 | return folder.path == path || (!path.isEmpty() && !folder.delimiter.isEmpty() && |
| 106 |
6/8✓ Branch 8 → 9 taken 7 times.
✓ Branch 9 → 10 taken 7 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 5 times.
✓ Branch 13 → 14 taken 7 times.
✓ Branch 13 → 15 taken 1 time.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
|
15 | folder.path.startsWith(path + folder.delimiter)); |
| 107 | }); | ||
| 108 |
2/2✓ Branch 21 → 22 taken 3 times.
✓ Branch 21 → 23 taken 7366 times.
|
7369 | if (hide) continue; |
| 109 |
1/1✓ Branch 23 → 24 taken 7366 times.
|
7366 | auto *item = ensureNode(folder.path, folder.delimiter); |
| 110 | 7366 | const auto fallbackName = item->folder.name; | |
| 111 | 7366 | item->folder = folder; | |
| 112 |
1/2✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 7366 times.
|
20266 | item->folder.name = folder.name.isEmpty() ? fallbackName : folder.delimiter.isEmpty() |
| 113 |
3/3✓ Branch 30 → 31 taken 1832 times.
✓ Branch 30 → 32 taken 5534 times.
✓ Branch 33 → 34 taken 5534 times.
|
12900 | ? folder.name : folder.name.section(folder.delimiter, -1); |
| 114 | 7366 | item->synthetic = false; | |
| 115 |
4/4✓ Branch 36 → 37 taken 7366 times.
✓ Branch 37 → 38 taken 7352 times.
✓ Branch 37 → 39 taken 14 times.
✓ Branch 38 → 39 taken 7352 times.
|
7366 | if (!folder.isNoselect()) m_selectablePaths.append(folder.path); |
| 116 | 7366 | } | |
| 117 | 8313 | auto sortChildren = [](Node *owner) { | |
| 118 | 8313 | std::sort(owner->children.begin(), owner->children.end(), [](const Node *left, const Node *right) { | |
| 119 |
2/2✓ Branch 4 → 5 taken 1164 times.
✓ Branch 4 → 7 taken 43495 times.
|
44659 | if ((left->folder.path == "INBOX") != (right->folder.path == "INBOX")) return left->folder.path == "INBOX"; |
| 120 | 43495 | const int order = QString::compare(left->folder.name, right->folder.name, Qt::CaseInsensitive); | |
| 121 |
1/2✓ Branch 8 → 9 taken 43495 times.
✗ Branch 8 → 10 not taken.
|
43495 | return order != 0 ? order < 0 : left->folder.path < right->folder.path; |
| 122 | }); | ||
| 123 |
2/2✓ Branch 9 → 6 taken 7479 times.
✓ Branch 9 → 10 taken 8313 times.
|
15792 | for (int row = 0; row < owner->children.size(); ++row) owner->children[row]->row = row; |
| 124 | 8313 | }; | |
| 125 |
1/1✓ Branch 45 → 46 taken 834 times.
|
834 | sortChildren(&m_root); |
| 126 |
3/3✓ Branch 50 → 51 taken 7479 times.
✓ Branch 53 → 48 taken 7479 times.
✓ Branch 53 → 54 taken 834 times.
|
8313 | for (const auto &item : m_nodes) sortChildren(item.get()); |
| 127 |
1/1✓ Branch 54 → 55 taken 834 times.
|
834 | endResetModel(); |
| 128 | 834 | } | |
| 129 | |||
| 130 | 34 | QStringList FolderPresentationModel::branchPaths() const { | |
| 131 | 34 | QStringList result; | |
| 132 |
5/5✓ Branch 7 → 8 taken 77 times.
✓ Branch 7 → 10 taken 215 times.
✓ Branch 9 → 10 taken 77 times.
✓ Branch 12 → 4 taken 292 times.
✓ Branch 12 → 13 taken 34 times.
|
326 | for (const auto &item : m_nodes) if (!item->children.isEmpty()) result.append(item->folder.path); |
| 133 | 34 | return result; | |
| 134 | ✗ | } | |
| 135 | |||
| 136 | 1324 | QModelIndex FolderPresentationModel::indexForPath(const QString &path) const { | |
| 137 | 1324 | const auto *item = m_paths.value(path); | |
| 138 |
2/2✓ Branch 3 → 4 taken 1162 times.
✓ Branch 3 → 5 taken 162 times.
|
1324 | return item ? createIndex(item->row, 0, item) : QModelIndex{}; |
| 139 | } | ||
| 140 | |||
| 141 | 123 | void FolderPresentationModel::setUnread(const QString &path, int unread) { | |
| 142 | 123 | auto *item = m_paths.value(path); | |
| 143 | 123 | const int count = std::max(0, unread); | |
| 144 |
6/6✓ Branch 4 → 5 taken 115 times.
✓ Branch 4 → 7 taken 8 times.
✓ Branch 5 → 6 taken 114 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 6 → 7 taken 16 times.
✓ Branch 6 → 8 taken 98 times.
|
123 | if (!item || item->synthetic || item->unread == count) return; |
| 145 | 98 | item->unread = count; | |
| 146 | 98 | const auto changed = indexForPath(path); | |
| 147 |
2/2✓ Branch 9 → 10 taken 98 times.
✓ Branch 10 → 11 taken 98 times.
|
98 | emit dataChanged(changed, changed, {UnreadRole}); |
| 148 | } | ||
| 149 | |||
| 150 | 13066 | bool FolderPresentationModel::isSelectable(const QString &path) const { | |
| 151 | 13066 | const auto *item = m_paths.value(path); | |
| 152 |
6/6✓ Branch 3 → 4 taken 7915 times.
✓ Branch 3 → 8 taken 5151 times.
✓ Branch 4 → 5 taken 7914 times.
✓ Branch 4 → 8 taken 1 time.
✓ Branch 6 → 7 taken 7906 times.
✓ Branch 6 → 8 taken 8 times.
|
13066 | return item && !item->synthetic && !item->folder.isNoselect(); |
| 153 | } | ||
| 154 | |||
| 155 | 516 | QList<FolderPresentationModel::TreeRow> FolderPresentationModel::treeRows() const { | |
| 156 | 516 | QList<TreeRow> rows; | |
| 157 | 516 | QList<QPair<const Node *, int>> stack; | |
| 158 |
6/6✓ Branch 3 → 4 taken 1534 times.
✓ Branch 5 → 6 taken 1534 times.
✓ Branch 6 → 7 taken 1534 times.
✓ Branch 8 → 9 taken 2050 times.
✓ Branch 9 → 3 taken 1534 times.
✓ Branch 9 → 10 taken 516 times.
|
2050 | for (auto it = m_root.children.crbegin(); it != m_root.children.crend(); ++it) stack.append({*it, 0}); |
| 159 |
2/2✓ Branch 28 → 11 taken 1558 times.
✓ Branch 28 → 29 taken 516 times.
|
2074 | while (!stack.isEmpty()) { |
| 160 |
1/1✓ Branch 11 → 12 taken 1558 times.
|
1558 | const auto [node, depth] = stack.takeLast(); |
| 161 |
6/6✓ Branch 15 → 16 taken 24 times.
✓ Branch 17 → 18 taken 24 times.
✓ Branch 18 → 19 taken 24 times.
✓ Branch 20 → 21 taken 1582 times.
✓ Branch 21 → 15 taken 24 times.
✓ Branch 21 → 22 taken 1558 times.
|
1582 | for (auto it = node->children.crbegin(); it != node->children.crend(); ++it) stack.append({*it, depth + 1}); |
| 162 | 1558 | rows.append({node->folder.path, node->folder.name, depth}); | |
| 163 | } | ||
| 164 | 516 | return rows; | |
| 165 | 2074 | } | |
| 166 | |||
| 167 | 11 | QStringList FolderPresentationModel::matchingPaths(const QString &prefix, int limit) const { | |
| 168 | 11 | QStringList result; | |
| 169 |
2/2✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 10 times.
|
11 | if (limit <= 0) return result; |
| 170 |
2/2✓ Branch 21 → 6 taken 20 times.
✓ Branch 21 → 22 taken 8 times.
|
28 | for (const auto &path : m_selectablePaths) { |
| 171 |
5/5✓ Branch 7 → 8 taken 20 times.
✓ Branch 8 → 9 taken 10 times.
✓ Branch 8 → 12 taken 10 times.
✓ Branch 14 → 15 taken 11 times.
✓ Branch 14 → 19 taken 9 times.
|
30 | if (path.contains(prefix, Qt::CaseInsensitive) || |
| 172 |
3/3✓ Branch 10 → 11 taken 10 times.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 9 times.
|
10 | m_paths.value(path)->folder.name.contains(prefix, Qt::CaseInsensitive)) { |
| 173 |
1/1✓ Branch 15 → 16 taken 11 times.
|
11 | result.append(path); |
| 174 |
2/2✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 19 taken 9 times.
|
11 | if (result.size() >= limit) break; |
| 175 | } | ||
| 176 | } | ||
| 177 | 10 | return result; | |
| 178 | ✗ | } | |
| 179 | |||
| 180 | namespace { | ||
| 181 | // Localized names of the special folders (D-20): the words a user types for | ||
| 182 | // them, matched as the fourth class. | ||
| 183 | 5266 | QString specialNames(const FolderInfo &folder) { | |
| 184 |
1/1✓ Branch 2 → 3 taken 5266 times.
|
5266 | const QString path = folder.path.toLower(); |
| 185 |
2/2✓ Branch 5 → 6 taken 40 times.
✓ Branch 5 → 11 taken 5226 times.
|
5306 | if (folder.path.compare(QLatin1String("INBOX"), Qt::CaseInsensitive) == 0) return QStringLiteral("posteingang inbox"); |
| 186 |
7/8✓ Branch 11 → 12 taken 5226 times.
✓ Branch 12 → 13 taken 5223 times.
✓ Branch 12 → 16 taken 3 times.
✓ Branch 14 → 15 taken 5223 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 5223 times.
✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 24 taken 5223 times.
|
5229 | if (folder.isSent() || path.endsWith(QLatin1String("sent"))) return QStringLiteral("gesendet gesendete sent"); |
| 187 |
7/8✓ Branch 24 → 25 taken 5223 times.
✓ Branch 25 → 26 taken 5220 times.
✓ Branch 25 → 29 taken 3 times.
✓ Branch 27 → 28 taken 5220 times.
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 5220 times.
✓ Branch 31 → 32 taken 3 times.
✓ Branch 31 → 37 taken 5220 times.
|
5226 | if (folder.isDrafts() || path.endsWith(QLatin1String("drafts"))) return QStringLiteral("entwürfe drafts"); |
| 188 |
7/8✓ Branch 37 → 38 taken 5220 times.
✓ Branch 38 → 39 taken 5209 times.
✓ Branch 38 → 42 taken 11 times.
✓ Branch 40 → 41 taken 5209 times.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 5209 times.
✓ Branch 44 → 45 taken 11 times.
✓ Branch 44 → 50 taken 5209 times.
|
5231 | if (folder.isTrash() || path.endsWith(QLatin1String("trash"))) return QStringLiteral("papierkorb gelöscht trash"); |
| 189 |
9/11✓ Branch 50 → 51 taken 5209 times.
✓ Branch 51 → 52 taken 5198 times.
✓ Branch 51 → 58 taken 11 times.
✓ Branch 53 → 54 taken 5198 times.
✓ Branch 54 → 55 taken 5198 times.
✗ Branch 54 → 58 not taken.
✓ Branch 56 → 57 taken 5198 times.
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 59 taken 5198 times.
✓ Branch 60 → 61 taken 11 times.
✓ Branch 60 → 66 taken 5198 times.
|
5209 | if (folder.isJunk() || path.endsWith(QLatin1String("junk")) || path.endsWith(QLatin1String("spam"))) |
| 190 | 11 | return QStringLiteral("spam junk werbung"); | |
| 191 |
8/8✓ Branch 66 → 67 taken 5198 times.
✓ Branch 67 → 68 taken 5196 times.
✓ Branch 67 → 71 taken 2 times.
✓ Branch 69 → 70 taken 5196 times.
✓ Branch 70 → 71 taken 19 times.
✓ Branch 70 → 72 taken 5177 times.
✓ Branch 73 → 74 taken 21 times.
✓ Branch 73 → 79 taken 5177 times.
|
5219 | if (folder.isArchive() || path.endsWith(QLatin1String("archive"))) return QStringLiteral("archiv archive"); |
| 192 | 5177 | return {}; | |
| 193 | 5266 | } | |
| 194 | } // namespace | ||
| 195 | |||
| 196 | 42 | void FolderPresentationModel::buildCompletionIndex() const { | |
| 197 |
1/1✓ Branch 2 → 3 taken 42 times.
|
42 | m_completionIndex.clear(); |
| 198 | // Tree order: depth first from the root, the order the folder tree shows. | ||
| 199 | 42 | QList<const Node *> stack; | |
| 200 |
6/6✓ Branch 4 → 5 taken 213 times.
✓ Branch 5 → 6 taken 213 times.
✓ Branch 6 → 7 taken 213 times.
✓ Branch 8 → 9 taken 255 times.
✓ Branch 9 → 4 taken 213 times.
✓ Branch 9 → 10 taken 42 times.
|
255 | for (auto it = m_root.children.crbegin(); it != m_root.children.crend(); ++it) stack.append(*it); |
| 201 |
2/2✓ Branch 70 → 11 taken 5369 times.
✓ Branch 70 → 71 taken 42 times.
|
5411 | while (!stack.isEmpty()) { |
| 202 |
1/1✓ Branch 11 → 12 taken 5369 times.
|
5369 | const Node *node = stack.takeLast(); |
| 203 |
6/6✓ Branch 13 → 14 taken 5156 times.
✓ Branch 14 → 15 taken 5156 times.
✓ Branch 15 → 16 taken 5156 times.
✓ Branch 17 → 18 taken 10525 times.
✓ Branch 18 → 13 taken 5156 times.
✓ Branch 18 → 19 taken 5369 times.
|
10525 | for (auto it = node->children.crbegin(); it != node->children.crend(); ++it) stack.append(*it); |
| 204 |
6/7✓ Branch 19 → 20 taken 5266 times.
✓ Branch 19 → 22 taken 103 times.
✓ Branch 20 → 21 taken 5266 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 5266 times.
✓ Branch 24 → 25 taken 103 times.
✓ Branch 24 → 26 taken 5266 times.
|
5369 | if (node->synthetic || node->folder.isNoselect()) continue; |
| 205 | 5266 | QStringList segments; | |
| 206 |
4/5✓ Branch 27 → 28 taken 10056 times.
✓ Branch 29 → 30 taken 15322 times.
✗ Branch 29 → 31 not taken.
✓ Branch 30 → 27 taken 10056 times.
✓ Branch 30 → 31 taken 5266 times.
|
15322 | for (const Node *item = node->parent; item && item != &m_root; item = item->parent) segments.prepend(item->folder.name); |
| 207 | 5266 | CompletionIndexEntry entry; | |
| 208 | 5266 | entry.node = node; | |
| 209 |
1/1✓ Branch 33 → 34 taken 5266 times.
|
5266 | entry.parent = segments.join(QLatin1Char('/')); |
| 210 |
6/8✓ Branch 37 → 38 taken 210 times.
✓ Branch 37 → 39 taken 5056 times.
✓ Branch 41 → 42 taken 5056 times.
✓ Branch 42 → 43 taken 5056 times.
✓ Branch 45 → 46 taken 5056 times.
✓ Branch 45 → 47 taken 210 times.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
|
5266 | entry.display = entry.parent.isEmpty() ? node->folder.name : entry.parent + QLatin1Char('/') + node->folder.name; |
| 211 |
1/1✓ Branch 47 → 48 taken 5266 times.
|
5266 | entry.leafLower = node->folder.name.toLower(); |
| 212 |
1/1✓ Branch 50 → 51 taken 5266 times.
|
5266 | entry.displayLower = entry.display.toLower(); |
| 213 |
1/1✓ Branch 53 → 54 taken 5266 times.
|
5266 | entry.pathLower = node->folder.path.toLower(); |
| 214 |
2/2✓ Branch 56 → 57 taken 5266 times.
✓ Branch 60 → 61 taken 5266 times.
|
5266 | entry.special = specialNames(node->folder).split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| 215 |
1/1✓ Branch 64 → 65 taken 5266 times.
|
5266 | m_completionIndex.append(entry); |
| 216 | 5266 | } | |
| 217 | 42 | m_completionIndexValid = true; | |
| 218 | 42 | } | |
| 219 | |||
| 220 | 145 | QList<FolderPresentationModel::Completion> FolderPresentationModel::completionCandidates( | |
| 221 | const QString &text, const QStringList &preferred, const QStringList &recent, int limit) const { | ||
| 222 |
3/3✓ Branch 2 → 3 taken 42 times.
✓ Branch 2 → 4 taken 103 times.
✓ Branch 3 → 4 taken 42 times.
|
145 | if (!m_completionIndexValid) buildCompletionIndex(); |
| 223 |
2/2✓ Branch 4 → 5 taken 145 times.
✓ Branch 5 → 6 taken 145 times.
|
145 | const QString needle = text.trimmed().toLower(); |
| 224 |
1/1✓ Branch 9 → 10 taken 145 times.
|
145 | const QString segment = QLatin1Char('/') + needle; |
| 225 | struct Ranked { int index; int match; int priority; }; | ||
| 226 | 145 | QList<Ranked> ranked; | |
| 227 |
2/2✓ Branch 74 → 11 taken 200616 times.
✓ Branch 74 → 75 taken 145 times.
|
200761 | for (int index = 0; index < m_completionIndex.size(); ++index) { |
| 228 | 200616 | const CompletionIndexEntry &entry = m_completionIndex.at(index); | |
| 229 | 200616 | int match = 0; | |
| 230 |
2/2✓ Branch 13 → 14 taken 200433 times.
✓ Branch 13 → 58 taken 183 times.
|
200616 | if (!needle.isEmpty()) { |
| 231 | // Most folders do not contain the text at all: one test rejects them. | ||
| 232 |
1/1✓ Branch 14 → 15 taken 200433 times.
|
200433 | const bool inDisplay = entry.displayLower.contains(needle); |
| 233 |
8/9✓ Branch 15 → 16 taken 180377 times.
✓ Branch 15 → 21 taken 20056 times.
✓ Branch 17 → 18 taken 180229 times.
✓ Branch 17 → 21 taken 148 times.
✓ Branch 18 → 19 taken 180229 times.
✓ Branch 19 → 20 taken 180229 times.
✗ Branch 19 → 21 not taken.
✓ Branch 22 → 23 taken 180229 times.
✓ Branch 22 → 24 taken 20204 times.
|
200433 | if (!inDisplay && entry.special.isEmpty() && !entry.pathLower.contains(needle)) continue; |
| 234 |
2/2✓ Branch 24 → 25 taken 148 times.
✓ Branch 24 → 26 taken 20056 times.
|
20204 | if (!inDisplay) match = 4; |
| 235 |
5/6✓ Branch 27 → 28 taken 16176 times.
✓ Branch 27 → 30 taken 4028 times.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 16176 times.
✓ Branch 32 → 33 taken 4028 times.
✓ Branch 32 → 34 taken 16176 times.
|
20204 | if (entry.leafLower == needle || entry.displayLower == needle) match = 0; |
| 236 |
8/8✓ Branch 34 → 35 taken 16176 times.
✓ Branch 35 → 36 taken 155 times.
✓ Branch 35 → 38 taken 16021 times.
✓ Branch 36 → 37 taken 155 times.
✓ Branch 37 → 38 taken 5 times.
✓ Branch 37 → 39 taken 150 times.
✓ Branch 40 → 41 taken 16026 times.
✓ Branch 40 → 42 taken 150 times.
|
16176 | else if (entry.leafLower.startsWith(needle) || entry.displayLower.startsWith(needle)) match = 1; |
| 237 |
3/3✓ Branch 42 → 43 taken 150 times.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 45 taken 149 times.
|
150 | else if (entry.displayLower.contains(segment)) match = 2; |
| 238 |
3/3✓ Branch 47 → 48 taken 149 times.
✓ Branch 48 → 49 taken 4 times.
✓ Branch 48 → 50 taken 145 times.
|
149 | else if (std::any_of(entry.special.cbegin(), entry.special.cend(), |
| 239 | 352 | [&needle](const QString &word) { return word.startsWith(needle); })) match = 3; | |
| 240 |
6/7✓ Branch 50 → 51 taken 144 times.
✓ Branch 50 → 53 taken 1 time.
✓ Branch 51 → 52 taken 144 times.
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 144 times.
✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 57 taken 144 times.
|
145 | else if (inDisplay || entry.pathLower.contains(needle)) match = 4; |
| 241 | 144 | else continue; | |
| 242 | } | ||
| 243 | 20243 | const QString &path = entry.node->folder.path; | |
| 244 |
2/2✓ Branch 59 → 60 taken 20205 times.
✓ Branch 59 → 61 taken 38 times.
|
20243 | const int recentIndex = recent.isEmpty() ? -1 : int(recent.indexOf(path)); |
| 245 |
4/4✓ Branch 64 → 65 taken 5 times.
✓ Branch 64 → 66 taken 20238 times.
✓ Branch 66 → 67 taken 10 times.
✓ Branch 66 → 68 taken 20228 times.
|
20243 | const int priority = preferred.contains(path) ? 0 : recentIndex >= 0 ? 1 + recentIndex : 1000; |
| 246 |
1/1✓ Branch 70 → 71 taken 20243 times.
|
20243 | ranked.append({index, match, priority}); |
| 247 | } | ||
| 248 | // Index order is tree order, so a stable sort keeps it within a class. | ||
| 249 |
3/3✓ Branch 75 → 76 taken 145 times.
✓ Branch 76 → 77 taken 145 times.
✓ Branch 77 → 78 taken 145 times.
|
145 | std::stable_sort(ranked.begin(), ranked.end(), [](const Ranked &a, const Ranked &b) { |
| 250 |
2/2✓ Branch 2 → 3 taken 12515 times.
✓ Branch 2 → 4 taken 104504 times.
|
117019 | return a.match != b.match ? a.match < b.match : a.priority < b.priority; |
| 251 | }); | ||
| 252 | 145 | QList<Completion> result; | |
| 253 |
4/4✓ Branch 78 → 79 taken 145 times.
✓ Branch 79 → 80 taken 145 times.
✓ Branch 94 → 81 taken 2283 times.
✓ Branch 94 → 95 taken 105 times.
|
2388 | for (const Ranked &entry : ranked) { |
| 254 |
2/2✓ Branch 83 → 84 taken 40 times.
✓ Branch 83 → 85 taken 2243 times.
|
2283 | if (result.size() >= limit) break; |
| 255 | 2243 | const CompletionIndexEntry &item = m_completionIndex.at(entry.index); | |
| 256 | 2243 | result.append({item.node->folder.path, item.node->folder.name, item.parent, item.node->unread, | |
| 257 | 2243 | preferred.contains(item.node->folder.path)}); | |
| 258 | } | ||
| 259 | 145 | return result; | |
| 260 | 2388 | } | |
| 261 | |||
| 262 | 799 | QString FolderPresentationModel::firstSelectable() const { | |
| 263 |
7/9✓ Branch 2 → 3 taken 799 times.
✓ Branch 3 → 4 taken 799 times.
✓ Branch 4 → 5 taken 591 times.
✓ Branch 4 → 8 taken 208 times.
✓ Branch 8 → 9 taken 208 times.
✓ Branch 10 → 11 taken 591 times.
✓ Branch 10 → 12 taken 208 times.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
|
1390 | return isSelectable("INBOX") ? QStringLiteral("INBOX") : m_selectablePaths.value(0); |
| 264 | } | ||
| 265 | |||
| 266 | 831 | void FolderPresentationModel::setAppearance(const QHash<QString, Appearance> &byPath, | |
| 267 | int fallbackGlyph) { | ||
| 268 | 831 | m_appearance = byPath; | |
| 269 | 831 | m_fallbackGlyph = fallbackGlyph; | |
| 270 |
2/2✓ Branch 14 → 5 taken 2357 times.
✓ Branch 14 → 15 taken 831 times.
|
3188 | for (const auto &item : m_nodes) { |
| 271 | 2357 | const auto changed = createIndex(item->row, 0, item.get()); | |
| 272 |
2/2✓ Branch 9 → 10 taken 2357 times.
✓ Branch 10 → 11 taken 2357 times.
|
2357 | emit dataChanged(changed, changed, {IconRole, ColorRole}); |
| 273 | } | ||
| 274 | 831 | } | |
| 275 |