presentation/WorkspaceState.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "WorkspaceState.h" | ||
| 2 | #include "SearchLog.h" | ||
| 3 | #include "ComposeLog.h" | ||
| 4 | #include <QUuid> | ||
| 5 | #include <QJsonArray> | ||
| 6 | #include <QSet> | ||
| 7 | #include <QSettings> | ||
| 8 | #include <algorithm> | ||
| 9 | #include <cmath> | ||
| 10 | |||
| 11 | 1837 | QString WorkspaceState::configuredReadingMode() { | |
| 12 |
3/3✓ Branch 2 → 3 taken 1837 times.
✓ Branch 11 → 12 taken 1837 times.
✓ Branch 12 → 13 taken 1837 times.
|
5511 | const QString mode = QSettings().value(QStringLiteral("view/defaultMode"), QStringLiteral("text")).toString(); |
| 13 |
5/6✓ Branch 22 → 23 taken 1824 times.
✓ Branch 22 → 26 taken 13 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 1824 times.
✓ Branch 28 → 29 taken 13 times.
✓ Branch 28 → 31 taken 1824 times.
|
1837 | if (mode == QLatin1String("light") || mode == QLatin1String("html")) return mode; |
| 14 | 1824 | return QStringLiteral("text"); | |
| 15 | 1837 | } | |
| 16 | |||
| 17 | 1797 | WorkspaceState::WorkspaceState(QObject *parent) | |
| 18 |
1/1✓ Branch 3 → 4 taken 1797 times.
|
5391 | : QAbstractListModel(parent), m_configuredMode(configuredReadingMode()) { |
| 19 |
1/3✓ Branch 20 → 21 taken 1797 times.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
|
5391 | Tab main{QStringLiteral("main"), tr("Inbox"), {}, m_configuredMode}; |
| 20 | 1797 | main.kind = QStringLiteral("main"); | |
| 21 |
1/1✓ Branch 33 → 34 taken 1797 times.
|
1797 | m_tabs.append(main); |
| 22 | 1797 | } | |
| 23 | |||
| 24 | 2 | void WorkspaceState::setConfiguredReadingMode(const QString &mode) { | |
| 25 |
2/4✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 2 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
|
2 | const QString canonical = mode == QLatin1String("html-light") ? QStringLiteral("light") : mode; |
| 26 |
3/6✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 20 taken 1 time.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 20 taken 1 time.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
|
2 | if (canonical == QLatin1String("text") || canonical == QLatin1String("light") || |
| 27 |
1/2✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 24 not taken.
|
2 | canonical == QLatin1String("html")) m_configuredMode = canonical; |
| 28 | 2 | } | |
| 29 | |||
| 30 | 24902 | int WorkspaceState::rowCount(const QModelIndex &parent) const { | |
| 31 |
2/2✓ Branch 3 → 4 taken 128 times.
✓ Branch 3 → 5 taken 24774 times.
|
24902 | return parent.isValid() ? 0 : m_tabs.size(); |
| 32 | } | ||
| 33 | |||
| 34 | 8694 | QVariant WorkspaceState::data(const QModelIndex &index, int role) const { | |
| 35 |
4/8✓ Branch 3 → 4 taken 8694 times.
✗ Branch 3 → 9 not taken.
✓ Branch 5 → 6 taken 8694 times.
✗ Branch 5 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 8694 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 8694 times.
|
8694 | if (!index.isValid() || index.row() < 0 || index.row() >= m_tabs.size()) return {}; |
| 36 | 8694 | const auto &tab = m_tabs.at(index.row()); | |
| 37 |
8/9✓ Branch 15 → 16 taken 10 times.
✓ Branch 15 → 17 taken 1512 times.
✓ Branch 15 → 18 taken 833 times.
✗ Branch 15 → 22 not taken.
✓ Branch 15 → 23 taken 1343 times.
✓ Branch 15 → 25 taken 1343 times.
✓ Branch 15 → 26 taken 1367 times.
✓ Branch 15 → 29 taken 1396 times.
✓ Branch 15 → 30 taken 890 times.
|
8694 | switch (role) { |
| 38 | 10 | case TabIdRole: return tab.id; | |
| 39 | 1512 | case TitleRole: return tab.title; | |
| 40 |
1/1✓ Branch 18 → 19 taken 833 times.
|
833 | case IdentityRole: return encode(tab.mailId); |
| 41 | ✗ | case ModeRole: return tab.mode; | |
| 42 | 1343 | case ClosableRole: return index.row() != 0; | |
| 43 | 1343 | case KindRole: return tab.kind; | |
| 44 | 1367 | case DormantRole: return tabDormant(index.row()); | |
| 45 | 1396 | case TooltipRole: return tab.tooltip; | |
| 46 | 890 | default: return {}; | |
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | 920 | QHash<int, QByteArray> WorkspaceState::roleNames() const { | |
| 51 | ✗ | return {{TabIdRole, "tabId"}, {TitleRole, "title"}, {IdentityRole, "identity"}, | |
| 52 | ✗ | {ModeRole, "readingMode"}, {ClosableRole, "closable"}, {KindRole, "kind"}, | |
| 53 |
2/4✓ Branch 12 → 13 taken 7360 times.
✓ Branch 12 → 14 taken 920 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
|
8280 | {DormantRole, "dormant"}, {TooltipRole, "tooltip"}}; |
| 54 | 920 | } | |
| 55 | |||
| 56 | 127880 | QVariantMap WorkspaceState::encode(const MailId &id) { | |
| 57 | ✗ | return {{"accountId", id.accountId}, {"folderId", QString::number(id.folderId)}, | |
| 58 |
2/4✓ Branch 9 → 10 taken 383640 times.
✓ Branch 9 → 11 taken 127880 times.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 18 not taken.
|
511520 | {"uid", QString::number(id.uid)}}; |
| 59 | 127880 | } | |
| 60 | |||
| 61 | 68906 | MailId WorkspaceState::decode(const QVariantMap &map) { | |
| 62 | // Accept strings only: JS numbers may already have lost precision. | ||
| 63 |
8/16✓ Branch 3 → 4 taken 68906 times.
✓ Branch 4 → 5 taken 68906 times.
✓ Branch 5 → 6 taken 68906 times.
✓ Branch 6 → 7 taken 68906 times.
✓ Branch 36 → 37 taken 68906 times.
✗ Branch 36 → 38 not taken.
✓ Branch 38 → 39 taken 68906 times.
✗ Branch 38 → 40 not taken.
✓ Branch 40 → 41 taken 5 times.
✓ Branch 40 → 42 taken 68901 times.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 106 not taken.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
|
137812 | if (map.value("accountId").metaType().id() != QMetaType::QString || |
| 64 |
12/20✓ Branch 7 → 8 taken 68903 times.
✓ Branch 7 → 20 taken 3 times.
✓ Branch 9 → 10 taken 68903 times.
✓ Branch 10 → 11 taken 68903 times.
✓ Branch 11 → 12 taken 68903 times.
✓ Branch 12 → 13 taken 68903 times.
✓ Branch 13 → 14 taken 68903 times.
✗ Branch 13 → 20 not taken.
✓ Branch 30 → 31 taken 68903 times.
✓ Branch 30 → 32 taken 3 times.
✓ Branch 32 → 33 taken 68903 times.
✓ Branch 32 → 34 taken 3 times.
✓ Branch 34 → 35 taken 68906 times.
✗ Branch 34 → 36 not taken.
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 93 not taken.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
|
275621 | map.value("folderId").metaType().id() != QMetaType::QString || |
| 65 |
14/20✓ Branch 15 → 16 taken 68903 times.
✓ Branch 16 → 17 taken 68903 times.
✓ Branch 17 → 18 taken 68903 times.
✓ Branch 18 → 19 taken 68903 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 21 taken 68901 times.
✓ Branch 22 → 23 taken 68903 times.
✓ Branch 22 → 24 taken 3 times.
✓ Branch 24 → 25 taken 68903 times.
✓ Branch 24 → 26 taken 3 times.
✓ Branch 26 → 27 taken 68903 times.
✓ Branch 26 → 28 taken 3 times.
✓ Branch 28 → 29 taken 68903 times.
✓ Branch 28 → 30 taken 3 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 88 not taken.
|
137814 | map.value("uid").metaType().id() != QMetaType::QString) return {}; |
| 66 | 68901 | bool folderOk = false, uidOk = false; | |
| 67 |
2/2✓ Branch 43 → 44 taken 68901 times.
✓ Branch 44 → 45 taken 68901 times.
|
137802 | MailId id{map.value("accountId").toString(), |
| 68 |
4/4✓ Branch 47 → 48 taken 68901 times.
✓ Branch 48 → 49 taken 68901 times.
✓ Branch 49 → 50 taken 68901 times.
✓ Branch 50 → 51 taken 68901 times.
|
137802 | map.value("folderId").toString().toLongLong(&folderOk), |
| 69 |
5/7✓ Branch 45 → 46 taken 68901 times.
✓ Branch 52 → 53 taken 68901 times.
✓ Branch 53 → 54 taken 68901 times.
✓ Branch 54 → 55 taken 68901 times.
✓ Branch 55 → 56 taken 68901 times.
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 142 not taken.
|
137802 | map.value("uid").toString().toLongLong(&uidOk)}; |
| 70 |
5/6✓ Branch 67 → 68 taken 68901 times.
✗ Branch 67 → 72 not taken.
✓ Branch 68 → 69 taken 68900 times.
✓ Branch 68 → 72 taken 1 time.
✓ Branch 70 → 71 taken 52323 times.
✓ Branch 70 → 72 taken 16577 times.
|
68901 | return folderOk && uidOk && id.isValid() ? id : MailId{}; |
| 71 | 68901 | } | |
| 72 | |||
| 73 | 15219 | QVariantMap WorkspaceState::selection() const { return encode(m_selection); } | |
| 74 | |||
| 75 | 2699 | void WorkspaceState::select(const MailId &id) { | |
| 76 |
2/2✓ Branch 3 → 4 taken 1336 times.
✓ Branch 3 → 5 taken 1363 times.
|
2699 | if (m_selection == id) return; |
| 77 | 1363 | const QString previousMode = readingMode(); | |
| 78 | 1363 | m_selection = id; | |
| 79 | 1363 | ++m_generation; | |
| 80 |
1/1✓ Branch 7 → 8 taken 1363 times.
|
1363 | m_tabs[m_activeTab].mailId = id; |
| 81 |
1/1✓ Branch 9 → 10 taken 1363 times.
|
1363 | m_tabs[m_activeTab].html = {}; |
| 82 | // The main list follows the configured default reading mode until the | ||
| 83 | // user explicitly chose a mode there this session. | ||
| 84 |
4/4✓ Branch 12 → 13 taken 1235 times.
✓ Branch 12 → 19 taken 128 times.
✓ Branch 13 → 14 taken 1230 times.
✓ Branch 13 → 19 taken 5 times.
|
1363 | if (m_activeTab == 0 && !m_mainModeTouched) { |
| 85 | 1230 | const QString &defaultMode = m_configuredMode; | |
| 86 |
2/4✓ Branch 14 → 15 taken 1230 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 1230 times.
✗ Branch 17 → 18 not taken.
|
1230 | if (m_tabs[0].mode != defaultMode) m_tabs[0].mode = defaultMode; |
| 87 | } | ||
| 88 | 1363 | const bool modeChanged = readingMode() != previousMode; | |
| 89 |
3/3✓ Branch 26 → 27 taken 1363 times.
✓ Branch 28 → 29 taken 1363 times.
✓ Branch 29 → 30 taken 1363 times.
|
1363 | emit dataChanged(index(m_activeTab), index(m_activeTab), |
| 90 |
2/4✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 1363 times.
✗ Branch 23 → 25 not taken.
✓ Branch 24 → 25 taken 1363 times.
|
2726 | modeChanged ? QList<int>{IdentityRole, ModeRole} : QList<int>{IdentityRole}); |
| 91 |
1/3✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 1363 times.
✗ Branch 32 → 33 not taken.
|
1363 | if (modeChanged) emit readingModeChanged(); |
| 92 |
1/1✓ Branch 33 → 34 taken 1363 times.
|
1363 | emit selectionChanged(); |
| 93 | 1363 | } | |
| 94 | |||
| 95 | 1010 | bool WorkspaceState::selectIdentity(const QVariantMap &identity) { | |
| 96 |
1/1✓ Branch 2 → 3 taken 1010 times.
|
1010 | const auto id = decode(identity); |
| 97 |
2/2✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1009 times.
|
1010 | if (!id.isValid()) return false; |
| 98 |
1/1✓ Branch 6 → 7 taken 1009 times.
|
1009 | select(id); |
| 99 | 1009 | return true; | |
| 100 | 1010 | } | |
| 101 | |||
| 102 | 10 | bool WorkspaceState::replaceActiveMail(const MailId &id, const QString &title) { | |
| 103 |
5/6✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 5 taken 1 time.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 9 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 9 times.
|
10 | if (m_activeTab == 0 || !id.isValid()) return false; |
| 104 | 9 | auto &tab = m_tabs[m_activeTab]; | |
| 105 |
1/1✓ Branch 10 → 11 taken 9 times.
|
9 | tab.title = title.left(1024); |
| 106 | // Keep the logical tab ID and reading mode; only this tab's mail changes. | ||
| 107 | 9 | const bool changed = m_selection != id; | |
| 108 |
1/2✓ Branch 14 → 15 taken 9 times.
✗ Branch 14 → 18 not taken.
|
9 | if (changed) tab.html = {}; |
| 109 | 9 | tab.mailId = id; | |
| 110 | 9 | m_selection = id; | |
| 111 |
1/2✓ Branch 20 → 21 taken 9 times.
✗ Branch 20 → 22 not taken.
|
9 | if (changed) ++m_generation; |
| 112 |
4/4✓ Branch 22 → 23 taken 9 times.
✓ Branch 24 → 25 taken 9 times.
✓ Branch 26 → 27 taken 9 times.
✓ Branch 27 → 28 taken 9 times.
|
9 | emit dataChanged(index(m_activeTab), index(m_activeTab), {TitleRole, IdentityRole}); |
| 113 |
1/2✓ Branch 29 → 30 taken 9 times.
✗ Branch 29 → 31 not taken.
|
9 | if (changed) emit selectionChanged(); |
| 114 | 9 | return true; | |
| 115 | } | ||
| 116 | |||
| 117 | 6 | bool WorkspaceState::accepts(const MailId &id, quint64 generation) const { | |
| 118 |
5/6✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 8 taken 2 times.
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 1 time.
|
6 | return id.isValid() && id == m_selection && generation == m_generation; |
| 119 | } | ||
| 120 | |||
| 121 | 1300 | void WorkspaceState::setLayout(const QString &layout) { | |
| 122 |
8/8✓ Branch 3 → 4 taken 291 times.
✓ Branch 3 → 6 taken 1009 times.
✓ Branch 5 → 6 taken 290 times.
✓ Branch 5 → 8 taken 1 time.
✓ Branch 7 → 8 taken 808 times.
✓ Branch 7 → 9 taken 491 times.
✓ Branch 10 → 11 taken 809 times.
✓ Branch 10 → 12 taken 491 times.
|
1300 | if ((layout != "classic" && layout != "wide") || layout == m_layout) return; |
| 123 | 491 | m_layout = layout; | |
| 124 | 491 | emit layoutChanged(); | |
| 125 | } | ||
| 126 | |||
| 127 | 224 | void WorkspaceState::setReaderFocused(bool focused) { | |
| 128 |
2/2✓ Branch 2 → 3 taken 77 times.
✓ Branch 2 → 4 taken 147 times.
|
224 | if (focused == m_readerFocused) return; |
| 129 | 147 | m_readerFocused = focused; | |
| 130 | 147 | emit readerFocusedChanged(); | |
| 131 | } | ||
| 132 | |||
| 133 | 935 | void WorkspaceState::setArea(const QString &area) { | |
| 134 | // F95-02: "rules" is the server-rule manager's own area; Sprint 100 | ||
| 135 | // (D-1): "settings" is the settings area. Neither is restored from a | ||
| 136 | // session (restoreSession keeps the four PIM areas). | ||
| 137 |
12/12✓ Branch 3 → 4 taken 680 times.
✓ Branch 3 → 16 taken 255 times.
✓ Branch 5 → 6 taken 506 times.
✓ Branch 5 → 17 taken 174 times.
✓ Branch 7 → 8 taken 365 times.
✓ Branch 7 → 17 taken 141 times.
✓ Branch 9 → 10 taken 275 times.
✓ Branch 9 → 17 taken 90 times.
✓ Branch 11 → 12 taken 187 times.
✓ Branch 11 → 17 taken 88 times.
✓ Branch 13 → 14 taken 159 times.
✓ Branch 13 → 17 taken 28 times.
|
1094 | if (area == m_area || (area != "mail" && area != "calendar" && area != "tasks" && area != "contacts" && area != "rules" |
| 138 |
3/4✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 159 times.
✓ Branch 18 → 19 taken 255 times.
✓ Branch 18 → 20 taken 680 times.
|
1094 | && area != "settings")) return; |
| 139 | 680 | m_area = area; | |
| 140 | 680 | emit areaChanged(); | |
| 141 | } | ||
| 142 | |||
| 143 | 323 | int WorkspaceState::openMail(const QVariantMap &identity, const QString &title) { | |
| 144 |
1/1✓ Branch 2 → 3 taken 323 times.
|
323 | auto id = decode(identity); |
| 145 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 323 times.
|
323 | if (!id.isValid()) return -1; |
| 146 |
2/2✓ Branch 21 → 7 taken 9185 times.
✓ Branch 21 → 22 taken 323 times.
|
9508 | for (int i = 1; i < m_tabs.size(); ++i) { |
| 147 |
6/9✓ Branch 8 → 9 taken 9185 times.
✓ Branch 10 → 11 taken 9182 times.
✓ Branch 10 → 15 taken 3 times.
✓ Branch 11 → 12 taken 9182 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 9182 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 9185 times.
✗ Branch 17 → 18 not taken.
|
9185 | if (m_tabs[i].kind == QLatin1String("mail") && m_tabs[i].mailId == id) { activateTab(i); return i; } |
| 148 | } | ||
| 149 |
2/2✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 25 taken 322 times.
|
323 | if (m_tabs.size() >= MaximumTabs) return -1; |
| 150 | 322 | const int row = m_tabs.size(); | |
| 151 |
1/1✓ Branch 27 → 28 taken 322 times.
|
322 | beginInsertRows({}, row, row); |
| 152 | 322 | m_tabs.append({QUuid::createUuid().toString(QUuid::WithoutBraces), title.left(1024), id, | |
| 153 | 322 | m_configuredMode}); | |
| 154 |
1/1✓ Branch 39 → 40 taken 322 times.
|
322 | endInsertRows(); |
| 155 |
1/1✓ Branch 40 → 41 taken 322 times.
|
322 | activateTab(row); |
| 156 | 322 | return row; | |
| 157 | 967 | } | |
| 158 | |||
| 159 | 738 | bool WorkspaceState::activateTab(int tab) { | |
| 160 |
5/6✓ Branch 2 → 3 taken 738 times.
✗ Branch 2 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 737 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 737 times.
|
738 | if (tab < 0 || tab >= m_tabs.size()) return false; |
| 161 |
1/1✓ Branch 9 → 10 taken 737 times.
|
737 | m_tabs[tab].used = ++m_useClock; |
| 162 |
2/2✓ Branch 10 → 11 taken 133 times.
✓ Branch 10 → 12 taken 604 times.
|
737 | if (tab == m_activeTab) return true; |
| 163 | 604 | const QString previousMode = readingMode(); | |
| 164 |
1/1✓ Branch 13 → 14 taken 604 times.
|
604 | m_previousTabId = m_tabs[m_activeTab].id; |
| 165 | 604 | m_activeTab = tab; | |
| 166 | // Even identical mail in a different tab invalidates callbacks for the old owner. | ||
| 167 |
1/1✓ Branch 15 → 16 taken 604 times.
|
604 | m_selection = m_tabs[tab].mailId; |
| 168 | 604 | ++m_generation; | |
| 169 |
1/1✓ Branch 17 → 18 taken 604 times.
|
604 | emit activeTabChanged(); |
| 170 |
3/3✓ Branch 21 → 22 taken 27 times.
✓ Branch 21 → 23 taken 577 times.
✓ Branch 22 → 23 taken 27 times.
|
604 | if (readingMode() != previousMode) emit readingModeChanged(); |
| 171 |
1/1✓ Branch 23 → 24 taken 604 times.
|
604 | emit selectionChanged(); |
| 172 | 604 | return true; | |
| 173 | 604 | } | |
| 174 | |||
| 175 | 93 | bool WorkspaceState::closeTab(int tab) { | |
| 176 |
5/6✓ Branch 2 → 3 taken 72 times.
✓ Branch 2 → 5 taken 21 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 72 times.
✓ Branch 7 → 8 taken 21 times.
✓ Branch 7 → 9 taken 72 times.
|
93 | if (tab <= 0 || tab >= m_tabs.size()) return false; |
| 177 | 72 | const QString previousMode = readingMode(); | |
| 178 | 72 | const bool closingActive = tab == m_activeTab; | |
| 179 | 72 | const Tab closed = m_tabs.at(tab); | |
| 180 |
1/1✓ Branch 13 → 14 taken 72 times.
|
72 | beginRemoveRows({}, tab, tab); |
| 181 |
1/1✓ Branch 14 → 15 taken 72 times.
|
72 | m_tabs.removeAt(tab); |
| 182 |
1/1✓ Branch 15 → 16 taken 72 times.
|
72 | endRemoveRows(); |
| 183 |
4/4✓ Branch 16 → 17 taken 14 times.
✓ Branch 16 → 18 taken 58 times.
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 52 taken 5 times.
|
72 | if (closingActive || m_activeTab > tab) { |
| 184 | // D-31: closing the active search tab returns to the tab used before it; | ||
| 185 | // so does closing a compose tab (S108.9.1: sending returns to the mail). | ||
| 186 |
5/6✓ Branch 20 → 21 taken 53 times.
✓ Branch 20 → 27 taken 14 times.
✓ Branch 23 → 24 taken 16 times.
✓ Branch 23 → 27 taken 37 times.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 16 times.
|
83 | const bool returns = closed.kind == QLatin1String("search") || closed.kind == QLatin1String("compose") || |
| 187 | 16 | closed.kind == QLatin1String("outbox"); | |
| 188 |
2/2✓ Branch 29 → 30 taken 51 times.
✓ Branch 29 → 31 taken 16 times.
|
67 | const int previous = returns ? rowForTabId(m_previousTabId) : -1; |
| 189 |
4/4✓ Branch 32 → 33 taken 58 times.
✓ Branch 32 → 39 taken 9 times.
✓ Branch 33 → 34 taken 16 times.
✓ Branch 33 → 37 taken 42 times.
|
67 | m_activeTab = closingActive ? (previous >= 0 ? previous : qMin(tab, int(m_tabs.size()) - 1)) : m_activeTab - 1; |
| 190 |
2/2✓ Branch 40 → 41 taken 58 times.
✓ Branch 40 → 44 taken 9 times.
|
67 | if (closingActive) { |
| 191 |
1/1✓ Branch 41 → 42 taken 58 times.
|
58 | m_selection = m_tabs[m_activeTab].mailId; |
| 192 | 58 | ++m_generation; | |
| 193 | } | ||
| 194 |
1/1✓ Branch 44 → 45 taken 67 times.
|
67 | emit activeTabChanged(); |
| 195 |
3/3✓ Branch 48 → 49 taken 2 times.
✓ Branch 48 → 50 taken 65 times.
✓ Branch 49 → 50 taken 2 times.
|
67 | if (readingMode() != previousMode) emit readingModeChanged(); |
| 196 |
3/3✓ Branch 50 → 51 taken 58 times.
✓ Branch 50 → 52 taken 9 times.
✓ Branch 51 → 52 taken 58 times.
|
67 | if (closingActive) emit selectionChanged(); |
| 197 | } | ||
| 198 |
1/1✓ Branch 52 → 53 taken 72 times.
|
72 | emit tabRemoved(closed.id, closed.kind); |
| 199 | 72 | return true; | |
| 200 | 72 | } | |
| 201 | |||
| 202 | 17 | void WorkspaceState::invalidateFolder(const QString &accountId, qint64 folderId) { | |
| 203 | 44 | const auto matches = [&](const Tab &tab) { | |
| 204 |
6/6✓ Branch 3 → 4 taken 34 times.
✓ Branch 3 → 8 taken 10 times.
✓ Branch 5 → 6 taken 30 times.
✓ Branch 5 → 8 taken 4 times.
✓ Branch 6 → 7 taken 21 times.
✓ Branch 6 → 8 taken 9 times.
|
44 | return tab.mailId.isValid() && tab.mailId.accountId == accountId && tab.mailId.folderId == folderId; |
| 205 | 17 | }; | |
| 206 |
3/3✓ Branch 4 → 5 taken 17 times.
✓ Branch 5 → 6 taken 9 times.
✓ Branch 5 → 7 taken 8 times.
|
17 | if (std::none_of(m_tabs.cbegin(), m_tabs.cend(), matches)) return; |
| 207 | 8 | const QString previousMode = readingMode(); | |
| 208 |
1/1✓ Branch 8 → 9 taken 8 times.
|
8 | const auto activeId = m_tabs[m_activeTab].id; |
| 209 | 8 | const int previousIndex = m_activeTab; | |
| 210 | 8 | const auto before = m_tabs; | |
| 211 |
1/1✓ Branch 11 → 12 taken 8 times.
|
8 | beginResetModel(); |
| 212 |
4/4✓ Branch 12 → 13 taken 8 times.
✓ Branch 13 → 14 taken 8 times.
✓ Branch 31 → 15 taken 20 times.
✓ Branch 31 → 32 taken 8 times.
|
28 | for (auto &tab : m_tabs) |
| 213 |
6/6✓ Branch 18 → 19 taken 9 times.
✓ Branch 18 → 22 taken 11 times.
✓ Branch 20 → 21 taken 6 times.
✓ Branch 20 → 22 taken 3 times.
✓ Branch 23 → 24 taken 6 times.
✓ Branch 23 → 29 taken 14 times.
|
20 | if (tab.kind != QLatin1String("mail") && matches(tab)) { tab.mailId = {}; tab.html = {}; } |
| 214 |
2/2✓ Branch 46 → 34 taken 12 times.
✓ Branch 46 → 47 taken 8 times.
|
20 | for (int row = int(m_tabs.size()) - 1; row > 0; --row) |
| 215 |
9/9✓ Branch 35 → 36 taken 12 times.
✓ Branch 37 → 38 taken 11 times.
✓ Branch 37 → 42 taken 1 time.
✓ Branch 38 → 39 taken 11 times.
✓ Branch 40 → 41 taken 7 times.
✓ Branch 40 → 42 taken 4 times.
✓ Branch 43 → 44 taken 7 times.
✓ Branch 43 → 45 taken 5 times.
✓ Branch 44 → 45 taken 7 times.
|
12 | if (m_tabs[row].kind == QLatin1String("mail") && matches(m_tabs[row])) m_tabs.removeAt(row); |
| 216 | 8 | m_activeTab = 0; | |
| 217 |
2/2✓ Branch 54 → 48 taken 13 times.
✓ Branch 54 → 55 taken 8 times.
|
21 | for (int row = 0; row < m_tabs.size(); ++row) |
| 218 |
3/3✓ Branch 48 → 49 taken 13 times.
✓ Branch 50 → 51 taken 6 times.
✓ Branch 50 → 52 taken 7 times.
|
13 | if (m_tabs[row].id == activeId) m_activeTab = row; |
| 219 |
5/6✓ Branch 55 → 56 taken 8 times.
✓ Branch 57 → 58 taken 2 times.
✓ Branch 57 → 61 taken 6 times.
✓ Branch 58 → 59 taken 2 times.
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 62 taken 2 times.
|
8 | const bool selectionChangedValue = m_selection != m_tabs[m_activeTab].mailId || m_tabs[m_activeTab].id != activeId; |
| 220 |
1/1✓ Branch 63 → 64 taken 8 times.
|
8 | m_selection = m_tabs[m_activeTab].mailId; |
| 221 |
2/2✓ Branch 65 → 66 taken 6 times.
✓ Branch 65 → 67 taken 2 times.
|
8 | if (selectionChangedValue) ++m_generation; |
| 222 |
1/1✓ Branch 67 → 68 taken 8 times.
|
8 | endResetModel(); |
| 223 |
7/8✓ Branch 68 → 69 taken 5 times.
✓ Branch 68 → 72 taken 3 times.
✓ Branch 69 → 70 taken 5 times.
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 5 times.
✓ Branch 74 → 75 taken 3 times.
✓ Branch 74 → 76 taken 5 times.
✓ Branch 75 → 76 taken 3 times.
|
8 | if (m_activeTab != previousIndex || m_tabs[m_activeTab].id != activeId) emit activeTabChanged(); |
| 224 |
1/3✗ Branch 79 → 80 not taken.
✓ Branch 79 → 81 taken 8 times.
✗ Branch 80 → 81 not taken.
|
8 | if (readingMode() != previousMode) emit readingModeChanged(); |
| 225 |
3/3✓ Branch 81 → 82 taken 6 times.
✓ Branch 81 → 83 taken 2 times.
✓ Branch 82 → 83 taken 6 times.
|
8 | if (selectionChangedValue) emit selectionChanged(); |
| 226 |
1/1✓ Branch 83 → 84 taken 8 times.
|
8 | emitRemoved(before); |
| 227 | 8 | } | |
| 228 | |||
| 229 | 1 | void WorkspaceState::cycleTabs(int offset) { | |
| 230 | 1 | activateTab(((m_activeTab + offset) % m_tabs.size() + m_tabs.size()) % m_tabs.size()); | |
| 231 | 1 | } | |
| 232 | |||
| 233 | 91 | bool WorkspaceState::setReadingMode(const QString &mode) { | |
| 234 |
4/4✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 7 taken 82 times.
✓ Branch 8 → 9 taken 9 times.
✓ Branch 8 → 10 taken 82 times.
|
100 | const QString canonical = mode == "html-light" ? QStringLiteral("light") : mode; |
| 235 |
6/8✓ Branch 11 → 12 taken 55 times.
✓ Branch 11 → 17 taken 36 times.
✓ Branch 13 → 14 taken 11 times.
✓ Branch 13 → 17 taken 44 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 11 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 91 times.
|
91 | if (canonical != "text" && canonical != "light" && canonical != "html") return false; |
| 236 |
3/3✓ Branch 20 → 21 taken 91 times.
✓ Branch 22 → 23 taken 25 times.
✓ Branch 22 → 24 taken 66 times.
|
91 | if (m_tabs[m_activeTab].mode == canonical) return true; |
| 237 |
2/2✓ Branch 24 → 25 taken 48 times.
✓ Branch 24 → 26 taken 18 times.
|
66 | if (m_activeTab == 0) m_mainModeTouched = true; |
| 238 |
1/1✓ Branch 26 → 27 taken 66 times.
|
66 | m_tabs[m_activeTab].mode = canonical; |
| 239 |
4/4✓ Branch 28 → 29 taken 66 times.
✓ Branch 30 → 31 taken 66 times.
✓ Branch 32 → 33 taken 66 times.
✓ Branch 33 → 34 taken 66 times.
|
66 | emit dataChanged(index(m_activeTab), index(m_activeTab), {ModeRole}); |
| 240 |
1/1✓ Branch 35 → 36 taken 66 times.
|
66 | emit readingModeChanged(); |
| 241 | 66 | return true; | |
| 242 | 91 | } | |
| 243 | |||
| 244 | 8 | static bool validReaderPosition(const QPointF &position) { | |
| 245 |
3/4✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 16 taken 1 time.
✓ Branch 10 → 11 taken 7 times.
✗ Branch 10 → 16 not taken.
|
23 | return std::isfinite(position.x()) && std::isfinite(position.y()) && |
| 246 |
5/6✓ Branch 4 → 5 taken 8 times.
✗ Branch 4 → 16 not taken.
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 16 taken 1 time.
✓ Branch 14 → 15 taken 5 times.
✓ Branch 14 → 16 taken 1 time.
|
23 | std::abs(position.x()) <= 1e9 && position.y() >= 0 && position.y() <= 1e9; |
| 247 | } | ||
| 248 | |||
| 249 | 26 | WorkspaceState::Tab *WorkspaceState::findTab(const QString &tabId, const MailId &id) { | |
| 250 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 26 times.
|
26 | if (!id.isValid()) return nullptr; |
| 251 |
10/10✓ Branch 5 → 6 taken 26 times.
✓ Branch 6 → 7 taken 26 times.
✓ Branch 10 → 11 taken 25 times.
✓ Branch 10 → 14 taken 9 times.
✓ Branch 12 → 13 taken 22 times.
✓ Branch 12 → 14 taken 3 times.
✓ Branch 15 → 16 taken 22 times.
✓ Branch 15 → 17 taken 12 times.
✓ Branch 19 → 8 taken 34 times.
✓ Branch 19 → 20 taken 4 times.
|
38 | for (auto &tab : m_tabs) if (tab.id == tabId && tab.mailId == id) return &tab; |
| 252 | 4 | return nullptr; | |
| 253 | } | ||
| 254 | |||
| 255 | 10 | WorkspaceState::HtmlReadingState WorkspaceState::bindHtmlDocument(const QString &tabId, const MailId &id, | |
| 256 | quint32 epoch, const QByteArray &digest) { | ||
| 257 |
1/1✓ Branch 2 → 3 taken 10 times.
|
10 | auto *tab = findTab(tabId, id); |
| 258 |
3/6✓ Branch 3 → 4 taken 10 times.
✗ Branch 3 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 10 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 10 times.
|
10 | if (!tab || digest.size() != 32) return {}; |
| 259 |
6/6✓ Branch 10 → 11 taken 6 times.
✓ Branch 10 → 14 taken 4 times.
✓ Branch 12 → 13 taken 5 times.
✓ Branch 12 → 14 taken 1 time.
✓ Branch 15 → 16 taken 5 times.
✓ Branch 15 → 17 taken 5 times.
|
10 | if (tab->html.uidValidity == epoch && tab->html.digest == digest) return tab->html; |
| 260 | 5 | tab->html = {epoch, digest, {}, false}; | |
| 261 | 5 | const auto state = tab->html; | |
| 262 |
1/1✓ Branch 21 → 22 taken 5 times.
|
5 | emit readerStateChanged(); |
| 263 | 5 | return state; | |
| 264 | 10 | } | |
| 265 | |||
| 266 | 9 | bool WorkspaceState::rememberHtmlScroll(const QString &tabId, const MailId &id, quint32 epoch, | |
| 267 | const QByteArray &digest, const QPointF &position) { | ||
| 268 | 9 | auto *tab = findTab(tabId, id); | |
| 269 |
8/10✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 11 taken 2 times.
✓ Branch 5 → 6 taken 7 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 11 not taken.
✓ Branch 8 → 9 taken 6 times.
✓ Branch 8 → 11 taken 1 time.
✓ Branch 13 → 14 taken 6 times.
✓ Branch 13 → 15 taken 3 times.
|
15 | if (!tab || digest.size() != 32 || tab->html.uidValidity != epoch || tab->html.digest != digest || |
| 270 |
2/2✓ Branch 10 → 11 taken 3 times.
✓ Branch 10 → 12 taken 3 times.
|
12 | !validReaderPosition(position)) return false; |
| 271 |
2/2✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 2 times.
|
3 | if (tab->html.scroll == position) return true; |
| 272 | 2 | tab->html.scroll = position; | |
| 273 | 2 | emit readerStateChanged(); | |
| 274 | 2 | return true; | |
| 275 | } | ||
| 276 | |||
| 277 | 7 | bool WorkspaceState::allowHtmlExternal(const QString &tabId, const MailId &id, quint32 epoch, const QByteArray &digest) { | |
| 278 | 7 | auto *tab = findTab(tabId, id); | |
| 279 |
8/10✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 9 taken 2 times.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 9 not taken.
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 9 taken 1 time.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 4 times.
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 13 taken 4 times.
|
7 | if (!tab || digest.size() != 32 || tab->html.uidValidity != epoch || tab->html.digest != digest) return false; |
| 280 | 4 | tab->html.allowExternal = true; | |
| 281 | 4 | return true; | |
| 282 | } | ||
| 283 | |||
| 284 | 801 | void WorkspaceState::clearHtmlConsent() { | |
| 285 |
4/4✓ Branch 2 → 3 taken 801 times.
✓ Branch 3 → 4 taken 801 times.
✓ Branch 8 → 5 taken 819 times.
✓ Branch 8 → 9 taken 801 times.
|
1620 | for (auto &tab : m_tabs) tab.html.allowExternal = false; |
| 286 | 801 | } | |
| 287 | |||
| 288 | 835 | void WorkspaceState::retainMailIdentities(const std::function<bool(const MailId &)> &acceptIdentity) { | |
| 289 | 835 | auto retained = m_tabs; | |
| 290 | 835 | bool changed = false; | |
| 291 | // Tab 0 and search tabs stay (D-15); only their selected mail is cleared. | ||
| 292 |
4/4✓ Branch 3 → 4 taken 835 times.
✓ Branch 4 → 5 taken 835 times.
✓ Branch 24 → 6 taken 854 times.
✓ Branch 24 → 25 taken 835 times.
|
1689 | for (auto &tab : retained) |
| 293 |
9/9✓ Branch 9 → 10 taken 846 times.
✓ Branch 9 → 15 taken 8 times.
✓ Branch 11 → 12 taken 17 times.
✓ Branch 11 → 15 taken 829 times.
✓ Branch 12 → 13 taken 17 times.
✓ Branch 13 → 14 taken 10 times.
✓ Branch 13 → 15 taken 7 times.
✓ Branch 16 → 17 taken 10 times.
✓ Branch 16 → 22 taken 844 times.
|
854 | if (tab.kind != QLatin1String("mail") && tab.mailId.isValid() && !acceptIdentity(tab.mailId)) { |
| 294 | 10 | tab.mailId = {}; tab.html = {}; changed = true; | |
| 295 | } | ||
| 296 |
2/2✓ Branch 40 → 27 taken 19 times.
✓ Branch 40 → 41 taken 835 times.
|
854 | for (int row = retained.size() - 1; row > 0; --row) |
| 297 |
9/9✓ Branch 28 → 29 taken 19 times.
✓ Branch 30 → 31 taken 8 times.
✓ Branch 30 → 35 taken 11 times.
✓ Branch 31 → 32 taken 8 times.
✓ Branch 32 → 33 taken 8 times.
✓ Branch 33 → 34 taken 7 times.
✓ Branch 33 → 35 taken 1 time.
✓ Branch 36 → 37 taken 7 times.
✓ Branch 36 → 39 taken 12 times.
|
19 | if (retained[row].kind == QLatin1String("mail") && !acceptIdentity(retained[row].mailId)) { |
| 298 |
1/1✓ Branch 37 → 38 taken 7 times.
|
7 | retained.removeAt(row); changed = true; |
| 299 | } | ||
| 300 |
2/2✓ Branch 41 → 42 taken 826 times.
✓ Branch 41 → 43 taken 9 times.
|
835 | if (!changed) return; |
| 301 | 9 | const QString previousMode = readingMode(); | |
| 302 | 9 | const auto oldTabId = activeTabId(); | |
| 303 | 9 | const int oldIndex = m_activeTab; | |
| 304 | 9 | int active = 0; | |
| 305 |
5/5✓ Branch 46 → 47 taken 13 times.
✓ Branch 48 → 49 taken 5 times.
✓ Branch 48 → 50 taken 8 times.
✓ Branch 52 → 46 taken 13 times.
✓ Branch 52 → 53 taken 9 times.
|
22 | for (int row = 0; row < retained.size(); ++row) if (retained[row].id == oldTabId) active = row; |
| 306 |
6/6✓ Branch 53 → 54 taken 9 times.
✓ Branch 55 → 56 taken 5 times.
✓ Branch 55 → 59 taken 4 times.
✓ Branch 56 → 57 taken 5 times.
✓ Branch 58 → 59 taken 4 times.
✓ Branch 58 → 60 taken 1 time.
|
9 | const bool ownerChanged = retained[active].id != oldTabId || retained[active].mailId != m_selection; |
| 307 | 9 | const auto before = m_tabs; | |
| 308 |
1/1✓ Branch 62 → 63 taken 9 times.
|
9 | beginResetModel(); |
| 309 | 9 | m_tabs = std::move(retained); | |
| 310 | 9 | m_activeTab = active; | |
| 311 |
1/1✓ Branch 65 → 66 taken 9 times.
|
9 | m_selection = m_tabs[active].mailId; |
| 312 |
2/2✓ Branch 67 → 68 taken 8 times.
✓ Branch 67 → 69 taken 1 time.
|
9 | if (ownerChanged) ++m_generation; |
| 313 |
1/1✓ Branch 69 → 70 taken 9 times.
|
9 | endResetModel(); |
| 314 |
5/5✓ Branch 70 → 71 taken 4 times.
✓ Branch 70 → 72 taken 5 times.
✓ Branch 71 → 72 taken 3 times.
✓ Branch 71 → 73 taken 1 time.
✓ Branch 72 → 73 taken 8 times.
|
9 | if (oldIndex != m_activeTab || ownerChanged) emit activeTabChanged(); |
| 315 |
1/3✗ Branch 76 → 77 not taken.
✓ Branch 76 → 78 taken 9 times.
✗ Branch 77 → 78 not taken.
|
9 | if (readingMode() != previousMode) emit readingModeChanged(); |
| 316 |
3/3✓ Branch 78 → 79 taken 8 times.
✓ Branch 78 → 80 taken 1 time.
✓ Branch 79 → 80 taken 8 times.
|
9 | if (ownerChanged) emit selectionChanged(); |
| 317 |
1/1✓ Branch 80 → 81 taken 9 times.
|
9 | emitRemoved(before); |
| 318 | 835 | } | |
| 319 | |||
| 320 | 1020 | static bool validFolderExpansion(const QMap<QString, QStringList> &accounts) { | |
| 321 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1019 times.
|
1020 | if (accounts.size() > 64) return false; |
| 322 | 1019 | qsizetype characters = 0, paths = 0; | |
| 323 |
4/4✓ Branch 5 → 6 taken 1019 times.
✓ Branch 47 → 48 taken 3148 times.
✓ Branch 49 → 7 taken 2130 times.
✓ Branch 49 → 50 taken 1018 times.
|
3148 | for (auto it = accounts.cbegin(); it != accounts.cend(); ++it) { |
| 324 |
4/8✓ Branch 9 → 10 taken 2130 times.
✗ Branch 9 → 16 not taken.
✓ Branch 12 → 13 taken 2130 times.
✗ Branch 12 → 16 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2130 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 2130 times.
|
2131 | if (it.key().isEmpty() || it.key().size() > 1024 || it.value().size() > 4096) return false; |
| 325 | 2130 | characters += it.key().size(); | |
| 326 | 2130 | paths += it.value().size(); | |
| 327 |
2/2✓ Branch 41 → 27 taken 2287 times.
✓ Branch 41 → 42 taken 2129 times.
|
4416 | for (const auto &path : it.value()) { |
| 328 |
3/6✓ Branch 29 → 30 taken 2287 times.
✗ Branch 29 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 2287 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 2287 times.
|
2288 | if (path.isEmpty() || path.size() > 4096) return false; |
| 329 | 2287 | characters += path.size(); | |
| 330 |
2/2✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 39 taken 2286 times.
|
2287 | if (characters > 65536) return false; |
| 331 | } | ||
| 332 |
2/4✓ Branch 42 → 44 taken 2129 times.
✗ Branch 42 → 45 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 2129 times.
|
2129 | if (paths > 4096 || characters > 65536) return false; |
| 333 | } | ||
| 334 | 1018 | return true; | |
| 335 | } | ||
| 336 | |||
| 337 | 111 | bool WorkspaceState::setFolderExpanded(const QString &account, const QString &path, bool expanded) { | |
| 338 |
8/10✓ Branch 3 → 4 taken 110 times.
✓ Branch 3 → 10 taken 1 time.
✓ Branch 5 → 6 taken 110 times.
✗ Branch 5 → 10 not taken.
✓ Branch 7 → 8 taken 110 times.
✗ Branch 7 → 10 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 109 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 109 times.
|
111 | if (account.isEmpty() || account.size() > 1024 || path.isEmpty() || path.size() > 4096) return false; |
| 339 | 109 | auto accounts = m_expandedFolders; | |
| 340 |
1/1✓ Branch 16 → 17 taken 109 times.
|
109 | auto paths = accounts.value(account); |
| 341 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 109 times.
|
109 | if (paths.contains(path) == expanded) return true; |
| 342 |
4/4✓ Branch 21 → 22 taken 101 times.
✓ Branch 21 → 24 taken 8 times.
✓ Branch 22 → 23 taken 101 times.
✓ Branch 23 → 25 taken 101 times.
|
109 | if (expanded) { paths.append(path); paths.sort(); } |
| 343 |
1/1✓ Branch 24 → 25 taken 8 times.
|
8 | else paths.removeAll(path); |
| 344 |
3/3✓ Branch 26 → 27 taken 6 times.
✓ Branch 26 → 28 taken 103 times.
✓ Branch 27 → 30 taken 6 times.
|
109 | if (paths.isEmpty()) accounts.remove(account); |
| 345 |
1/1✓ Branch 28 → 29 taken 103 times.
|
103 | else accounts[account] = paths; |
| 346 |
3/3✓ Branch 30 → 31 taken 109 times.
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 33 taken 107 times.
|
109 | if (!validFolderExpansion(accounts)) return false; |
| 347 | 107 | m_expandedFolders = std::move(accounts); | |
| 348 |
1/1✓ Branch 35 → 36 taken 107 times.
|
107 | emit folderExpansionChanged(); |
| 349 | 107 | return true; | |
| 350 | 109 | } | |
| 351 | |||
| 352 | 34 | void WorkspaceState::retainFolderBranches(const QString &account, const QStringList &paths) { | |
| 353 |
3/3✓ Branch 2 → 3 taken 34 times.
✓ Branch 3 → 4 taken 20 times.
✓ Branch 3 → 5 taken 14 times.
|
40 | if (!m_expandedFolders.contains(account)) return; |
| 354 |
1/1✓ Branch 7 → 8 taken 14 times.
|
14 | const QSet<QString> valid(paths.begin(), paths.end()); |
| 355 |
1/1✓ Branch 9 → 10 taken 14 times.
|
14 | auto retained = m_expandedFolders.value(account); |
| 356 |
1/1✓ Branch 11 → 12 taken 14 times.
|
29 | retained.removeIf([&](const QString &path) { return !valid.contains(path); }); |
| 357 |
4/4✓ Branch 13 → 14 taken 14 times.
✓ Branch 14 → 15 taken 14 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 19 taken 8 times.
|
14 | if (retained == m_expandedFolders.value(account)) return; |
| 358 |
2/3✓ Branch 20 → 21 taken 8 times.
✗ Branch 20 → 22 not taken.
✓ Branch 21 → 24 taken 8 times.
|
8 | if (retained.isEmpty()) m_expandedFolders.remove(account); |
| 359 | ✗ | else m_expandedFolders[account] = retained; | |
| 360 |
1/1✓ Branch 24 → 25 taken 8 times.
|
8 | emit folderExpansionChanged(); |
| 361 | 20 | } | |
| 362 | |||
| 363 | 771 | QJsonObject WorkspaceState::saveSession() const { | |
| 364 |
1/1✓ Branch 2 → 3 taken 771 times.
|
771 | QJsonArray tabs; |
| 365 |
2/2✓ Branch 82 → 5 taken 1544 times.
✓ Branch 82 → 83 taken 771 times.
|
2315 | for (const auto &tab : m_tabs) { |
| 366 | 4632 | QJsonObject entry{{"id", tab.id}, {"title", tab.title}, {"kind", tab.kind}, | |
| 367 |
3/5✓ Branch 10 → 11 taken 1544 times.
✓ Branch 15 → 16 taken 7720 times.
✓ Branch 15 → 17 taken 1544 times.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
|
10808 | {"identity", QJsonObject::fromVariantMap(encode(tab.mailId))}, {"readingMode", tab.mode}}; |
| 368 |
2/2✓ Branch 21 → 22 taken 60 times.
✓ Branch 21 → 42 taken 1484 times.
|
1544 | if (tab.kind == QLatin1String("search")) { |
| 369 | // D-16: the query and account; the zoom is the query's date part. | ||
| 370 |
3/3✓ Branch 22 → 23 taken 60 times.
✓ Branch 23 → 24 taken 60 times.
✓ Branch 24 → 25 taken 60 times.
|
60 | entry.insert("query", tab.query); |
| 371 |
3/3✓ Branch 27 → 28 taken 60 times.
✓ Branch 28 → 29 taken 60 times.
✓ Branch 29 → 30 taken 60 times.
|
60 | entry.insert("accountId", tab.accountId); |
| 372 |
4/4✓ Branch 32 → 33 taken 60 times.
✓ Branch 33 → 34 taken 60 times.
✓ Branch 35 → 36 taken 60 times.
✓ Branch 36 → 37 taken 60 times.
|
60 | entry.insert("anchor", QJsonObject::fromVariantMap(encode(tab.anchor))); |
| 373 | } | ||
| 374 |
5/5✓ Branch 44 → 45 taken 58 times.
✓ Branch 44 → 51 taken 1486 times.
✓ Branch 45 → 46 taken 58 times.
✓ Branch 46 → 47 taken 58 times.
✓ Branch 47 → 48 taken 58 times.
|
1544 | if (tab.kind == QLatin1String("compose")) entry.insert("sessionId", tab.sessionId); |
| 375 |
2/2✓ Branch 52 → 53 taken 10 times.
✓ Branch 52 → 76 taken 1534 times.
|
1544 | if (tab.html.digest.size() == 32) |
| 376 |
2/2✓ Branch 64 → 65 taken 10 times.
✓ Branch 65 → 66 taken 10 times.
|
10 | entry.insert("htmlReading", QJsonObject{{"epoch", QString::number(tab.html.uidValidity)}, |
| 377 |
1/1✓ Branch 56 → 57 taken 10 times.
|
20 | {"digest", QString::fromLatin1(tab.html.digest.toHex())}, |
| 378 |
2/4✓ Branch 70 → 71 taken 40 times.
✓ Branch 70 → 72 taken 10 times.
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 167 not taken.
|
60 | {"x", tab.html.scroll.x()}, {"y", tab.html.scroll.y()}}); |
| 379 |
2/2✓ Branch 76 → 77 taken 1544 times.
✓ Branch 77 → 78 taken 1544 times.
|
1544 | tabs.append(entry); |
| 380 | 1544 | } | |
| 381 | // Layout preferences belong to UiStateStore, not to the domain session. | ||
| 382 |
1/1✓ Branch 83 → 84 taken 771 times.
|
771 | QJsonObject expanded; |
| 383 |
4/4✓ Branch 84 → 85 taken 771 times.
✓ Branch 94 → 95 taken 980 times.
✓ Branch 96 → 86 taken 209 times.
✓ Branch 96 → 97 taken 771 times.
|
980 | for (auto it = m_expandedFolders.cbegin(); it != m_expandedFolders.cend(); ++it) |
| 384 |
2/2✓ Branch 87 → 88 taken 209 times.
✓ Branch 90 → 91 taken 209 times.
|
209 | expanded.insert(it.key(), QJsonArray::fromStringList(it.value())); |
| 385 | ✗ | return {{"schemaVersion", 2}, {"tabs", tabs}, {"activeTabId", m_tabs[m_activeTab].id}, | |
| 386 |
2/4✓ Branch 105 → 106 taken 3855 times.
✓ Branch 105 → 107 taken 771 times.
✗ Branch 203 → 204 not taken.
✗ Branch 203 → 205 not taken.
|
5397 | {"area", m_area}, {"expandedFolders", expanded}}; |
| 387 | 4650 | } | |
| 388 | |||
| 389 | 925 | bool WorkspaceState::restoreSession(const QJsonObject &session, QString *error, | |
| 390 | const std::function<bool(const MailId &)> &acceptIdentity) { | ||
| 391 | 925 | const QString previousMode = readingMode(); | |
| 392 |
2/2✓ Branch 2 → 3 taken 19 times.
✓ Branch 2 → 4 taken 10 times.
|
29 | auto fail = [&](const QString &message) { if (error) *error = message; return false; }; |
| 393 | // Sprint 101 S101.6.2: version 2 adds tab kinds; version 1 sessions hold | ||
| 394 | // the folder tab and mail tabs only. | ||
| 395 |
3/3✓ Branch 3 → 4 taken 925 times.
✓ Branch 4 → 5 taken 925 times.
✓ Branch 5 → 6 taken 925 times.
|
925 | const int version = session.value("schemaVersion").toInt(); |
| 396 |
23/38✓ Branch 8 → 9 taken 925 times.
✓ Branch 9 → 10 taken 925 times.
✓ Branch 10 → 11 taken 925 times.
✓ Branch 11 → 12 taken 925 times.
✓ Branch 12 → 13 taken 921 times.
✓ Branch 12 → 19 taken 4 times.
✓ Branch 13 → 14 taken 921 times.
✓ Branch 14 → 15 taken 921 times.
✓ Branch 15 → 16 taken 921 times.
✓ Branch 16 → 17 taken 921 times.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 920 times.
✓ Branch 20 → 21 taken 921 times.
✓ Branch 20 → 22 taken 4 times.
✓ Branch 22 → 23 taken 921 times.
✓ Branch 22 → 24 taken 4 times.
✓ Branch 24 → 25 taken 921 times.
✓ Branch 24 → 26 taken 4 times.
✓ Branch 26 → 27 taken 925 times.
✗ Branch 26 → 28 not taken.
✓ Branch 28 → 29 taken 925 times.
✗ Branch 28 → 30 not taken.
✓ Branch 30 → 31 taken 925 times.
✗ Branch 30 → 32 not taken.
✓ Branch 32 → 33 taken 1 time.
✓ Branch 32 → 40 taken 924 times.
✗ Branch 701 → 702 not taken.
✗ Branch 701 → 703 not taken.
✗ Branch 705 → 706 not taken.
✗ Branch 705 → 707 not taken.
✗ Branch 709 → 710 not taken.
✗ Branch 709 → 711 not taken.
✗ Branch 713 → 714 not taken.
✗ Branch 713 → 715 not taken.
✗ Branch 717 → 718 not taken.
✗ Branch 717 → 719 not taken.
✗ Branch 721 → 722 not taken.
✗ Branch 721 → 723 not taken.
|
925 | if (session.value("schemaVersion") != QJsonValue(1) && session.value("schemaVersion") != QJsonValue(2)) |
| 397 | 1 | return fail(QStringLiteral("Unsupported workspace session version")); | |
| 398 | 924 | QMap<QString, QStringList> expanded; | |
| 399 |
4/4✓ Branch 40 → 41 taken 924 times.
✓ Branch 41 → 42 taken 924 times.
✓ Branch 43 → 44 taken 917 times.
✓ Branch 43 → 184 taken 7 times.
|
924 | if (session.contains("expandedFolders")) { |
| 400 |
2/2✓ Branch 44 → 45 taken 917 times.
✓ Branch 45 → 46 taken 917 times.
|
917 | const auto value = session.value("expandedFolders"); |
| 401 |
9/13✓ Branch 47 → 48 taken 917 times.
✓ Branch 48 → 49 taken 917 times.
✗ Branch 48 → 52 not taken.
✓ Branch 49 → 50 taken 917 times.
✓ Branch 50 → 51 taken 917 times.
✓ Branch 51 → 52 taken 1 time.
✓ Branch 51 → 53 taken 916 times.
✓ Branch 54 → 55 taken 917 times.
✗ Branch 54 → 56 not taken.
✓ Branch 56 → 57 taken 1 time.
✓ Branch 56 → 64 taken 916 times.
✗ Branch 731 → 732 not taken.
✗ Branch 731 → 733 not taken.
|
917 | if (!value.isObject() || value.toObject().size() > 64) |
| 402 | 1 | return fail(QStringLiteral("Invalid expanded-folder accounts")); | |
| 403 |
1/1✓ Branch 64 → 65 taken 916 times.
|
916 | const auto accounts = value.toObject(); |
| 404 | 916 | qsizetype totalPaths = 0, characters = 0; | |
| 405 |
3/3✓ Branch 162 → 163 taken 926 times.
✓ Branch 164 → 66 taken 15 times.
✓ Branch 164 → 165 taken 911 times.
|
926 | for (auto it = accounts.begin(); it != accounts.end(); ++it) { |
| 406 |
8/18✓ Branch 66 → 67 taken 15 times.
✓ Branch 68 → 69 taken 15 times.
✗ Branch 68 → 75 not taken.
✓ Branch 69 → 70 taken 15 times.
✓ Branch 71 → 72 taken 15 times.
✗ Branch 71 → 75 not taken.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 76 taken 15 times.
✓ Branch 77 → 78 taken 15 times.
✗ Branch 77 → 79 not taken.
✓ Branch 79 → 80 taken 15 times.
✗ Branch 79 → 81 not taken.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 89 taken 15 times.
✗ Branch 736 → 737 not taken.
✗ Branch 736 → 738 not taken.
✗ Branch 740 → 741 not taken.
✗ Branch 740 → 742 not taken.
|
15 | if (it.key().isEmpty() || it.key().size() > 1024 || !it.value().isArray()) |
| 407 | ✗ | return fail(QStringLiteral("Invalid expanded-folder account")); | |
| 408 |
1/1✓ Branch 90 → 91 taken 15 times.
|
15 | const auto paths = it.value().toArray(); |
| 409 |
1/1✓ Branch 91 → 92 taken 15 times.
|
15 | totalPaths += paths.size(); |
| 410 |
1/1✓ Branch 92 → 93 taken 15 times.
|
15 | characters += it.key().size(); |
| 411 |
2/2✓ Branch 95 → 96 taken 1 time.
✓ Branch 95 → 103 taken 14 times.
|
16 | if (totalPaths > 4096) return fail(QStringLiteral("Too many expanded folders")); |
| 412 | 14 | QStringList decoded; | |
| 413 | 14 | QSet<QString> seen; | |
| 414 |
3/3✓ Branch 105 → 106 taken 14 times.
✓ Branch 140 → 107 taken 31 times.
✓ Branch 140 → 141 taken 10 times.
|
41 | for (const auto &path : paths) { |
| 415 |
1/1✓ Branch 109 → 110 taken 31 times.
|
31 | const auto text = path.toString(); |
| 416 | 31 | characters += text.size(); | |
| 417 |
5/6✓ Branch 115 → 116 taken 30 times.
✗ Branch 115 → 121 not taken.
✓ Branch 117 → 118 taken 29 times.
✓ Branch 117 → 121 taken 1 time.
✓ Branch 118 → 119 taken 28 times.
✓ Branch 118 → 121 taken 1 time.
|
61 | if (!path.isString() || text.isEmpty() || text.size() > 4096 || |
| 418 |
6/6✓ Branch 113 → 114 taken 30 times.
✓ Branch 113 → 121 taken 1 time.
✓ Branch 120 → 121 taken 1 time.
✓ Branch 120 → 122 taken 27 times.
✓ Branch 123 → 124 taken 4 times.
✓ Branch 123 → 131 taken 27 times.
|
61 | characters > 65536 || seen.contains(text)) |
| 419 | 4 | return fail(QStringLiteral("Invalid expanded-folder path")); | |
| 420 |
1/1✓ Branch 131 → 132 taken 27 times.
|
27 | seen.insert(text); |
| 421 |
1/1✓ Branch 132 → 133 taken 27 times.
|
27 | decoded.append(text); |
| 422 | 31 | } | |
| 423 |
1/1✓ Branch 141 → 142 taken 10 times.
|
10 | decoded.sort(); |
| 424 |
3/4✓ Branch 143 → 144 taken 10 times.
✗ Branch 143 → 148 not taken.
✓ Branch 144 → 145 taken 10 times.
✓ Branch 145 → 146 taken 10 times.
|
10 | if (!decoded.isEmpty()) expanded.insert(it.key(), decoded); |
| 425 | 23 | } | |
| 426 |
2/3✓ Branch 165 → 166 taken 911 times.
✗ Branch 166 → 167 not taken.
✓ Branch 166 → 174 taken 911 times.
|
911 | if (!validFolderExpansion(expanded)) return fail(QStringLiteral("Expanded folders exceed limits")); |
| 427 | 922 | } | |
| 428 |
5/5✓ Branch 184 → 185 taken 918 times.
✓ Branch 185 → 186 taken 918 times.
✓ Branch 186 → 187 taken 918 times.
✓ Branch 189 → 190 taken 4 times.
✓ Branch 189 → 197 taken 914 times.
|
922 | if (!session.value("tabs").isArray()) return fail(QStringLiteral("Missing workspace tabs")); |
| 429 |
3/3✓ Branch 197 → 198 taken 914 times.
✓ Branch 198 → 199 taken 914 times.
✓ Branch 199 → 200 taken 914 times.
|
914 | const auto entries = session.value("tabs").toArray(); |
| 430 |
8/8✓ Branch 202 → 203 taken 914 times.
✓ Branch 203 → 204 taken 911 times.
✓ Branch 203 → 206 taken 3 times.
✓ Branch 204 → 205 taken 911 times.
✓ Branch 205 → 206 taken 1 time.
✓ Branch 205 → 207 taken 910 times.
✓ Branch 208 → 209 taken 4 times.
✓ Branch 208 → 216 taken 910 times.
|
918 | if (entries.isEmpty() || entries.size() > 128) return fail(QStringLiteral("Invalid workspace tab count")); |
| 431 | 910 | QList<Tab> restored; | |
| 432 | 910 | QSet<QString> ids; | |
| 433 |
3/3✓ Branch 629 → 630 taken 2580 times.
✓ Branch 630 → 218 taken 1684 times.
✓ Branch 630 → 631 taken 896 times.
|
2580 | for (int i = 0; i < entries.size(); ++i) { |
| 434 |
3/4✓ Branch 218 → 219 taken 1684 times.
✓ Branch 219 → 220 taken 1684 times.
✗ Branch 221 → 222 not taken.
✓ Branch 221 → 229 taken 1684 times.
|
1684 | if (!entries[i].isObject()) return fail(QStringLiteral("Malformed workspace tab")); |
| 435 |
2/2✓ Branch 229 → 230 taken 1684 times.
✓ Branch 230 → 231 taken 1684 times.
|
1684 | const auto entry = entries[i].toObject(); |
| 436 |
1/1✓ Branch 232 → 233 taken 1684 times.
|
1684 | Tab tab; |
| 437 |
3/3✓ Branch 233 → 234 taken 1684 times.
✓ Branch 234 → 235 taken 1684 times.
✓ Branch 235 → 236 taken 1684 times.
|
1684 | tab.id = entry.value("id").toString(); |
| 438 |
3/3✓ Branch 240 → 241 taken 1684 times.
✓ Branch 241 → 242 taken 1684 times.
✓ Branch 242 → 243 taken 1684 times.
|
1684 | tab.title = entry.value("title").toString(); |
| 439 |
3/3✓ Branch 247 → 248 taken 1684 times.
✓ Branch 248 → 249 taken 1684 times.
✓ Branch 249 → 250 taken 1684 times.
|
1684 | const auto rawIdentity = entry.value("identity").toObject(); |
| 440 |
2/2✓ Branch 252 → 253 taken 1684 times.
✓ Branch 253 → 254 taken 1684 times.
|
1684 | tab.mailId = decode(rawIdentity.toVariantMap()); |
| 441 |
3/3✓ Branch 257 → 258 taken 1684 times.
✓ Branch 258 → 259 taken 1684 times.
✓ Branch 259 → 260 taken 1684 times.
|
1684 | tab.mode = entry.value("readingMode").toString(); |
| 442 |
4/4✓ Branch 264 → 265 taken 1684 times.
✓ Branch 265 → 266 taken 1684 times.
✓ Branch 267 → 268 taken 6 times.
✓ Branch 267 → 360 taken 1678 times.
|
1684 | if (entry.contains("htmlReading")) { |
| 443 |
4/5✓ Branch 268 → 269 taken 6 times.
✓ Branch 269 → 270 taken 6 times.
✓ Branch 270 → 271 taken 6 times.
✗ Branch 273 → 274 not taken.
✓ Branch 273 → 281 taken 6 times.
|
6 | if (!entry.value("htmlReading").isObject()) return fail(QStringLiteral("Invalid HTML reader state")); |
| 444 |
3/3✓ Branch 281 → 282 taken 6 times.
✓ Branch 282 → 283 taken 6 times.
✓ Branch 283 → 284 taken 6 times.
|
6 | const auto html = entry.value("htmlReading").toObject(); |
| 445 | 6 | bool epochOk = false; | |
| 446 |
4/4✓ Branch 286 → 287 taken 6 times.
✓ Branch 287 → 288 taken 6 times.
✓ Branch 288 → 289 taken 6 times.
✓ Branch 289 → 290 taken 6 times.
|
6 | tab.html.uidValidity = html.value("epoch").toString().toUInt(&epochOk); |
| 447 |
4/4✓ Branch 293 → 294 taken 6 times.
✓ Branch 294 → 295 taken 6 times.
✓ Branch 295 → 296 taken 6 times.
✓ Branch 296 → 297 taken 6 times.
|
6 | const auto hex = html.value("digest").toString().toLatin1(); |
| 448 |
1/1✓ Branch 300 → 301 taken 6 times.
|
6 | tab.html.digest = QByteArray::fromHex(hex); |
| 449 |
6/6✓ Branch 303 → 304 taken 6 times.
✓ Branch 304 → 305 taken 6 times.
✓ Branch 305 → 306 taken 6 times.
✓ Branch 306 → 307 taken 6 times.
✓ Branch 307 → 308 taken 6 times.
✓ Branch 308 → 309 taken 6 times.
|
6 | tab.html.scroll = {html.value("x").toDouble(), html.value("y").toDouble()}; |
| 450 |
6/9✓ Branch 316 → 317 taken 4 times.
✓ Branch 316 → 330 taken 1 time.
✓ Branch 317 → 318 taken 4 times.
✓ Branch 319 → 320 taken 4 times.
✗ Branch 319 → 330 not taken.
✓ Branch 342 → 343 taken 4 times.
✓ Branch 342 → 350 taken 2 times.
✗ Branch 883 → 884 not taken.
✗ Branch 883 → 885 not taken.
|
11 | if (!epochOk || hex.size() != 64 || tab.html.digest.toHex() != hex || |
| 451 |
23/32✓ Branch 314 → 315 taken 5 times.
✓ Branch 314 → 330 taken 1 time.
✓ Branch 320 → 321 taken 4 times.
✓ Branch 321 → 322 taken 4 times.
✓ Branch 322 → 323 taken 4 times.
✓ Branch 323 → 324 taken 3 times.
✓ Branch 323 → 330 taken 1 time.
✓ Branch 324 → 325 taken 3 times.
✓ Branch 325 → 326 taken 3 times.
✓ Branch 326 → 327 taken 3 times.
✓ Branch 327 → 328 taken 2 times.
✓ Branch 327 → 330 taken 1 time.
✗ Branch 329 → 330 not taken.
✓ Branch 329 → 331 taken 2 times.
✓ Branch 332 → 333 taken 3 times.
✓ Branch 332 → 334 taken 3 times.
✓ Branch 334 → 335 taken 3 times.
✓ Branch 334 → 336 taken 3 times.
✓ Branch 336 → 337 taken 4 times.
✓ Branch 336 → 338 taken 2 times.
✓ Branch 338 → 339 taken 4 times.
✓ Branch 338 → 340 taken 2 times.
✓ Branch 340 → 341 taken 4 times.
✓ Branch 340 → 342 taken 2 times.
✗ Branch 867 → 868 not taken.
✗ Branch 867 → 869 not taken.
✗ Branch 871 → 872 not taken.
✗ Branch 871 → 873 not taken.
✗ Branch 875 → 876 not taken.
✗ Branch 875 → 877 not taken.
✗ Branch 879 → 880 not taken.
✗ Branch 879 → 881 not taken.
|
11 | !html.value("x").isDouble() || !html.value("y").isDouble() || !validReaderPosition(tab.html.scroll)) |
| 452 | 4 | return fail(QStringLiteral("Invalid HTML reader snapshot or position")); | |
| 453 | 10 | } | |
| 454 |
15/23✓ Branch 360 → 361 taken 1678 times.
✓ Branch 360 → 364 taken 2 times.
✓ Branch 361 → 362 taken 1678 times.
✓ Branch 362 → 363 taken 1678 times.
✓ Branch 363 → 371 taken 1678 times.
✓ Branch 364 → 365 taken 1 time.
✓ Branch 364 → 368 taken 1 time.
✓ Branch 373 → 374 taken 1 time.
✓ Branch 373 → 375 taken 1679 times.
✓ Branch 375 → 376 taken 1 time.
✓ Branch 375 → 377 taken 1679 times.
✓ Branch 377 → 378 taken 1678 times.
✓ Branch 377 → 379 taken 2 times.
✓ Branch 379 → 380 taken 1678 times.
✓ Branch 379 → 381 taken 2 times.
✗ Branch 892 → 893 not taken.
✗ Branch 892 → 894 not taken.
✗ Branch 896 → 897 not taken.
✗ Branch 896 → 898 not taken.
✗ Branch 900 → 901 not taken.
✗ Branch 900 → 902 not taken.
✗ Branch 904 → 905 not taken.
✗ Branch 904 → 906 not taken.
|
1682 | tab.kind = version >= 2 ? entry.value("kind").toString() : (i == 0 ? QStringLiteral("main") : QStringLiteral("mail")); |
| 455 |
4/4✓ Branch 383 → 384 taken 1679 times.
✓ Branch 383 → 397 taken 1 time.
✓ Branch 384 → 385 taken 774 times.
✓ Branch 384 → 398 taken 905 times.
|
2454 | if ((i == 0) != (tab.kind == QLatin1String("main")) || |
| 456 |
4/4✓ Branch 387 → 388 taken 183 times.
✓ Branch 387 → 398 taken 591 times.
✓ Branch 390 → 391 taken 107 times.
✓ Branch 390 → 398 taken 76 times.
|
774 | (i != 0 && tab.kind != QLatin1String("mail") && tab.kind != QLatin1String("search") && |
| 457 |
6/6✓ Branch 393 → 394 taken 25 times.
✓ Branch 393 → 398 taken 82 times.
✓ Branch 396 → 397 taken 5 times.
✓ Branch 396 → 398 taken 20 times.
✓ Branch 399 → 400 taken 6 times.
✓ Branch 399 → 407 taken 1674 times.
|
1787 | tab.kind != QLatin1String("compose") && tab.kind != QLatin1String("outbox"))) |
| 458 | 6 | return fail(QStringLiteral("Invalid workspace tab kind")); | |
| 459 |
2/2✓ Branch 409 → 410 taken 20 times.
✓ Branch 409 → 432 taken 1654 times.
|
1674 | if (tab.kind == QLatin1String("outbox")) { |
| 460 | 20 | tab.mailId = {}; | |
| 461 | 20 | tab.mode = m_configuredMode; | |
| 462 |
1/1✓ Branch 415 → 416 taken 20 times.
|
20 | const bool duplicate = std::any_of(restored.cbegin(), restored.cend(), |
| 463 | 20 | [](const Tab &other) { return other.kind == QLatin1String("outbox"); }); | |
| 464 |
6/12✓ Branch 416 → 417 taken 20 times.
✗ Branch 416 → 425 not taken.
✓ Branch 418 → 419 taken 20 times.
✗ Branch 418 → 425 not taken.
✓ Branch 420 → 421 taken 20 times.
✗ Branch 420 → 425 not taken.
✓ Branch 422 → 423 taken 20 times.
✗ Branch 422 → 425 not taken.
✗ Branch 424 → 425 not taken.
✓ Branch 424 → 426 taken 20 times.
✗ Branch 427 → 428 not taken.
✓ Branch 427 → 429 taken 20 times.
|
20 | if (duplicate || tab.id.isEmpty() || tab.id.size() > 64 || ids.contains(tab.id) || tab.title.size() > 1024) continue; |
| 465 |
1/1✓ Branch 429 → 430 taken 20 times.
|
20 | ids.insert(tab.id); |
| 466 |
1/1✓ Branch 430 → 431 taken 20 times.
|
20 | restored.append(tab); |
| 467 | 20 | continue; | |
| 468 | 20 | } | |
| 469 |
2/2✓ Branch 434 → 435 taken 82 times.
✓ Branch 434 → 472 taken 1572 times.
|
1654 | if (tab.kind == QLatin1String("compose")) { |
| 470 | // The draft itself lives in the ComposeSessionStore; the tab only | ||
| 471 | // names it. A tab whose session id is malformed is dropped. | ||
| 472 |
3/3✓ Branch 435 → 436 taken 82 times.
✓ Branch 436 → 437 taken 82 times.
✓ Branch 437 → 438 taken 82 times.
|
82 | tab.sessionId = entry.value("sessionId").toString(); |
| 473 | 82 | tab.mailId = {}; | |
| 474 | 82 | tab.mode = m_configuredMode; | |
| 475 |
4/7✓ Branch 445 → 446 taken 82 times.
✓ Branch 448 → 449 taken 81 times.
✗ Branch 448 → 455 not taken.
✓ Branch 450 → 451 taken 81 times.
✗ Branch 450 → 455 not taken.
✓ Branch 452 → 453 taken 81 times.
✗ Branch 452 → 455 not taken.
|
244 | if (!validComposeSessionId(tab.sessionId) || tab.id.isEmpty() || tab.id.size() > 64 || |
| 476 |
5/6✓ Branch 446 → 447 taken 81 times.
✓ Branch 446 → 455 taken 1 time.
✗ Branch 454 → 455 not taken.
✓ Branch 454 → 456 taken 81 times.
✓ Branch 457 → 458 taken 1 time.
✓ Branch 457 → 469 taken 81 times.
|
244 | ids.contains(tab.id) || tab.title.size() > 1024) { |
| 477 |
5/5✓ Branch 458 → 459 taken 1 time.
✓ Branch 462 → 463 taken 1 time.
✓ Branch 463 → 464 taken 1 time.
✓ Branch 467 → 460 taken 1 time.
✓ Branch 467 → 468 taken 1 time.
|
2 | qCWarning(lcCompose) << "Dropped a compose tab with an invalid session payload"; |
| 478 | 1 | continue; | |
| 479 | 1 | } | |
| 480 |
1/1✓ Branch 469 → 470 taken 81 times.
|
81 | ids.insert(tab.id); |
| 481 |
1/1✓ Branch 470 → 471 taken 81 times.
|
81 | restored.append(tab); |
| 482 | 81 | continue; | |
| 483 | 81 | } | |
| 484 |
2/2✓ Branch 474 → 475 taken 76 times.
✓ Branch 474 → 515 taken 1496 times.
|
1572 | if (tab.kind == QLatin1String("search")) { |
| 485 | // A corrupted search tab is dropped; the other tabs are restored. | ||
| 486 |
3/3✓ Branch 475 → 476 taken 76 times.
✓ Branch 476 → 477 taken 6 times.
✓ Branch 476 → 488 taken 70 times.
|
76 | if (!restoreSearchPayload(entry, tab)) { |
| 487 |
5/5✓ Branch 477 → 478 taken 6 times.
✓ Branch 481 → 482 taken 6 times.
✓ Branch 482 → 483 taken 6 times.
✓ Branch 486 → 479 taken 6 times.
✓ Branch 486 → 487 taken 6 times.
|
12 | qCWarning(lcSearch) << "Dropped a search tab with an invalid session payload"; |
| 488 | 6 | continue; | |
| 489 | 6 | } | |
| 490 |
9/9✓ Branch 489 → 490 taken 52 times.
✓ Branch 489 → 495 taken 18 times.
✓ Branch 491 → 492 taken 2 times.
✓ Branch 491 → 495 taken 50 times.
✓ Branch 492 → 493 taken 2 times.
✓ Branch 493 → 494 taken 1 time.
✓ Branch 493 → 495 taken 1 time.
✓ Branch 496 → 497 taken 1 time.
✓ Branch 496 → 500 taken 69 times.
|
70 | if (tab.mailId.isValid() && acceptIdentity && !acceptIdentity(tab.mailId)) tab.mailId = {}; |
| 491 |
5/10✓ Branch 501 → 502 taken 70 times.
✗ Branch 501 → 508 not taken.
✓ Branch 503 → 504 taken 70 times.
✗ Branch 503 → 508 not taken.
✓ Branch 505 → 506 taken 70 times.
✗ Branch 505 → 508 not taken.
✗ Branch 507 → 508 not taken.
✓ Branch 507 → 509 taken 70 times.
✗ Branch 510 → 511 not taken.
✓ Branch 510 → 512 taken 70 times.
|
70 | if (tab.id.isEmpty() || tab.id.size() > 64 || ids.contains(tab.id) || tab.title.size() > 1024) continue; |
| 492 |
1/1✓ Branch 512 → 513 taken 70 times.
|
70 | ids.insert(tab.id); |
| 493 |
1/1✓ Branch 513 → 514 taken 70 times.
|
70 | restored.append(tab); |
| 494 | 70 | continue; | |
| 495 | 70 | } | |
| 496 |
1/2✗ Branch 516 → 517 not taken.
✓ Branch 516 → 524 taken 1496 times.
|
1496 | if (tab.mode == "html-light") tab.mode = QStringLiteral("light"); |
| 497 |
6/8✓ Branch 525 → 526 taken 322 times.
✓ Branch 525 → 531 taken 1174 times.
✓ Branch 527 → 528 taken 141 times.
✓ Branch 527 → 531 taken 181 times.
✗ Branch 529 → 530 not taken.
✓ Branch 529 → 531 taken 141 times.
✗ Branch 532 → 533 not taken.
✓ Branch 532 → 534 taken 1496 times.
|
1496 | if (tab.mode != "text" && tab.mode != "light" && tab.mode != "html") tab.mode = m_configuredMode; |
| 498 |
4/6✓ Branch 537 → 538 taken 1496 times.
✗ Branch 537 → 547 not taken.
✓ Branch 539 → 540 taken 1495 times.
✓ Branch 539 → 547 taken 1 time.
✓ Branch 541 → 542 taken 1495 times.
✗ Branch 541 → 547 not taken.
|
2991 | if (tab.id.isEmpty() || tab.id.size() > 64 || ids.contains(tab.id) || |
| 499 |
13/21✓ Branch 535 → 536 taken 1496 times.
✗ Branch 535 → 547 not taken.
✓ Branch 542 → 543 taken 1495 times.
✓ Branch 543 → 544 taken 1495 times.
✓ Branch 544 → 545 taken 1495 times.
✗ Branch 546 → 547 not taken.
✓ Branch 546 → 548 taken 1495 times.
✓ Branch 549 → 550 taken 1495 times.
✓ Branch 549 → 551 taken 1 time.
✓ Branch 551 → 552 taken 1495 times.
✓ Branch 551 → 553 taken 1 time.
✓ Branch 553 → 554 taken 1495 times.
✓ Branch 553 → 555 taken 1 time.
✓ Branch 555 → 556 taken 1 time.
✓ Branch 555 → 563 taken 1495 times.
✗ Branch 929 → 930 not taken.
✗ Branch 929 → 931 not taken.
✗ Branch 933 → 934 not taken.
✗ Branch 933 → 935 not taken.
✗ Branch 937 → 938 not taken.
✗ Branch 937 → 939 not taken.
|
4487 | tab.title.size() > 1024 || rawIdentity.value("accountId").toString().size() > 1024) |
| 500 | 1 | return fail(QStringLiteral("Invalid or duplicate workspace tab identity")); | |
| 501 |
1/2✗ Branch 564 → 565 not taken.
✓ Branch 564 → 572 taken 1495 times.
|
1495 | if ((i == 0) != (tab.id == "main")) return fail(QStringLiteral("Missing permanent main tab")); |
| 502 |
1/1✓ Branch 572 → 573 taken 1495 times.
|
1495 | ids.insert(tab.id); |
| 503 |
2/2✓ Branch 574 → 575 taken 350 times.
✓ Branch 574 → 596 taken 1145 times.
|
1495 | if (!tab.mailId.isValid()) { |
| 504 | // Only an explicitly empty main tab may omit a valid identity. | ||
| 505 |
14/21✓ Branch 575 → 576 taken 347 times.
✓ Branch 575 → 580 taken 3 times.
✓ Branch 576 → 577 taken 347 times.
✓ Branch 577 → 578 taken 347 times.
✓ Branch 578 → 579 taken 347 times.
✗ Branch 579 → 580 not taken.
✓ Branch 579 → 581 taken 347 times.
✓ Branch 582 → 583 taken 347 times.
✓ Branch 582 → 584 taken 3 times.
✓ Branch 584 → 585 taken 347 times.
✓ Branch 584 → 586 taken 3 times.
✓ Branch 586 → 587 taken 347 times.
✓ Branch 586 → 588 taken 3 times.
✓ Branch 588 → 589 taken 3 times.
✓ Branch 588 → 610 taken 347 times.
✗ Branch 942 → 943 not taken.
✗ Branch 942 → 944 not taken.
✗ Branch 946 → 947 not taken.
✗ Branch 946 → 948 not taken.
✗ Branch 950 → 951 not taken.
✗ Branch 950 → 952 not taken.
|
350 | if (i != 0 || rawIdentity != QJsonObject::fromVariantMap(encode(MailId{}))) |
| 506 | 3 | return fail(QStringLiteral("Invalid workspace mail identity")); | |
| 507 |
7/7✓ Branch 597 → 598 taken 12 times.
✓ Branch 597 → 601 taken 1133 times.
✓ Branch 598 → 599 taken 12 times.
✓ Branch 599 → 600 taken 6 times.
✓ Branch 599 → 601 taken 6 times.
✓ Branch 602 → 603 taken 6 times.
✓ Branch 602 → 610 taken 1139 times.
|
1145 | } else if (acceptIdentity && !acceptIdentity(tab.mailId)) { |
| 508 | // A removed account/folder must never resolve to another account's UID. | ||
| 509 |
2/2✓ Branch 603 → 604 taken 3 times.
✓ Branch 603 → 605 taken 3 times.
|
6 | if (i != 0) continue; |
| 510 | 3 | tab.mailId = {}; | |
| 511 | 3 | tab.html = {}; | |
| 512 | } | ||
| 513 |
1/1✓ Branch 610 → 611 taken 1489 times.
|
1489 | restored.append(tab); |
| 514 | 2074 | } | |
| 515 |
3/3✓ Branch 631 → 632 taken 896 times.
✓ Branch 632 → 633 taken 896 times.
✓ Branch 633 → 634 taken 896 times.
|
896 | const QString activeId = session.value("activeTabId").toString(); |
| 516 | 896 | int active = 0; | |
| 517 |
5/5✓ Branch 637 → 638 taken 1646 times.
✓ Branch 639 → 640 taken 887 times.
✓ Branch 639 → 641 taken 759 times.
✓ Branch 643 → 637 taken 1646 times.
✓ Branch 643 → 644 taken 896 times.
|
2542 | for (int i = 0; i < restored.size(); ++i) if (restored[i].id == activeId) active = i; |
| 518 |
3/3✓ Branch 644 → 645 taken 896 times.
✓ Branch 645 → 646 taken 896 times.
✓ Branch 646 → 647 taken 896 times.
|
896 | QString area = session.value("area").toString(); |
| 519 |
10/10✓ Branch 650 → 651 taken 413 times.
✓ Branch 650 → 658 taken 483 times.
✓ Branch 652 → 653 taken 229 times.
✓ Branch 652 → 658 taken 184 times.
✓ Branch 654 → 655 taken 174 times.
✓ Branch 654 → 658 taken 55 times.
✓ Branch 656 → 657 taken 109 times.
✓ Branch 656 → 658 taken 65 times.
✓ Branch 659 → 660 taken 109 times.
✓ Branch 659 → 667 taken 787 times.
|
1005 | if (area != "mail" && area != "calendar" && area != "tasks" && area != "contacts") area = QStringLiteral("mail"); |
| 520 |
1/1✓ Branch 667 → 668 taken 896 times.
|
896 | beginResetModel(); |
| 521 | 896 | m_tabs = restored; | |
| 522 | 896 | m_activeTab = active; | |
| 523 | 896 | m_area = area; | |
| 524 | 896 | m_expandedFolders = std::move(expanded); | |
| 525 |
1/1✓ Branch 672 → 673 taken 896 times.
|
896 | m_selection = m_tabs[active].mailId; |
| 526 | 896 | ++m_generation; | |
| 527 |
1/1✓ Branch 674 → 675 taken 896 times.
|
896 | endResetModel(); |
| 528 |
1/1✓ Branch 675 → 676 taken 896 times.
|
896 | emit activeTabChanged(); |
| 529 |
3/3✓ Branch 679 → 680 taken 58 times.
✓ Branch 679 → 681 taken 838 times.
✓ Branch 680 → 681 taken 58 times.
|
896 | if (readingMode() != previousMode) emit readingModeChanged(); |
| 530 |
1/1✓ Branch 681 → 682 taken 896 times.
|
896 | emit selectionChanged(); |
| 531 |
1/1✓ Branch 682 → 683 taken 896 times.
|
896 | emit areaChanged(); |
| 532 |
1/1✓ Branch 683 → 684 taken 896 times.
|
896 | emit folderExpansionChanged(); |
| 533 |
2/2✓ Branch 684 → 685 taken 867 times.
✓ Branch 684 → 686 taken 29 times.
|
896 | if (error) error->clear(); |
| 534 | 896 | return true; | |
| 535 | 925 | } | |
| 536 | |||
| 537 | // ── Sprint 101 S101.1.1: tab kinds and search tabs ────────────────────── | ||
| 538 | |||
| 539 | 76 | bool WorkspaceState::restoreSearchPayload(const QJsonObject &entry, Tab &tab) const { | |
| 540 |
17/28✓ Branch 2 → 3 taken 76 times.
✓ Branch 3 → 4 taken 76 times.
✓ Branch 4 → 5 taken 76 times.
✓ Branch 5 → 6 taken 75 times.
✓ Branch 5 → 10 taken 1 time.
✓ Branch 6 → 7 taken 75 times.
✓ Branch 7 → 8 taken 75 times.
✓ Branch 8 → 9 taken 75 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 75 times.
✓ Branch 12 → 13 taken 75 times.
✓ Branch 12 → 14 taken 1 time.
✓ Branch 14 → 15 taken 75 times.
✓ Branch 14 → 16 taken 1 time.
✓ Branch 16 → 17 taken 76 times.
✗ Branch 16 → 18 not taken.
✓ Branch 18 → 19 taken 76 times.
✗ Branch 18 → 20 not taken.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 22 taken 75 times.
✗ Branch 148 → 149 not taken.
✗ Branch 148 → 150 not taken.
✗ Branch 152 → 153 not taken.
✗ Branch 152 → 154 not taken.
✗ Branch 156 → 157 not taken.
✗ Branch 156 → 158 not taken.
✗ Branch 160 → 161 not taken.
✗ Branch 160 → 162 not taken.
|
76 | if (!entry.value("query").isString() || !entry.value("accountId").isString()) return false; |
| 541 |
3/3✓ Branch 22 → 23 taken 75 times.
✓ Branch 23 → 24 taken 75 times.
✓ Branch 24 → 25 taken 75 times.
|
75 | tab.query = entry.value("query").toString(); |
| 542 |
3/3✓ Branch 29 → 30 taken 75 times.
✓ Branch 30 → 31 taken 75 times.
✓ Branch 31 → 32 taken 75 times.
|
75 | tab.accountId = entry.value("accountId").toString(); |
| 543 |
7/8✓ Branch 37 → 38 taken 74 times.
✓ Branch 37 → 42 taken 1 time.
✓ Branch 39 → 40 taken 73 times.
✓ Branch 39 → 42 taken 1 time.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 73 times.
✓ Branch 44 → 45 taken 2 times.
✓ Branch 44 → 46 taken 73 times.
|
75 | if (tab.query.size() > MaximumQueryCharacters || tab.accountId.isEmpty() || tab.accountId.size() > 1024) |
| 544 | 2 | return false; | |
| 545 |
3/3✓ Branch 46 → 47 taken 73 times.
✓ Branch 47 → 48 taken 73 times.
✓ Branch 48 → 49 taken 73 times.
|
73 | const auto identity = entry.value("identity").toObject(); |
| 546 |
2/2✓ Branch 51 → 52 taken 73 times.
✓ Branch 52 → 53 taken 73 times.
|
73 | tab.mailId = decode(identity.toVariantMap()); |
| 547 |
13/21✓ Branch 57 → 58 taken 18 times.
✓ Branch 57 → 63 taken 55 times.
✓ Branch 58 → 59 taken 18 times.
✓ Branch 59 → 60 taken 18 times.
✓ Branch 60 → 61 taken 18 times.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 18 times.
✓ Branch 64 → 65 taken 18 times.
✓ Branch 64 → 66 taken 55 times.
✓ Branch 66 → 67 taken 18 times.
✓ Branch 66 → 68 taken 55 times.
✓ Branch 68 → 69 taken 18 times.
✓ Branch 68 → 70 taken 55 times.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 73 times.
✗ Branch 188 → 189 not taken.
✗ Branch 188 → 190 not taken.
✗ Branch 192 → 193 not taken.
✗ Branch 192 → 194 not taken.
✗ Branch 196 → 197 not taken.
✗ Branch 196 → 198 not taken.
|
73 | if (!tab.mailId.isValid() && identity != QJsonObject::fromVariantMap(encode(MailId{}))) return false; |
| 548 |
6/6✓ Branch 73 → 74 taken 55 times.
✓ Branch 73 → 77 taken 18 times.
✓ Branch 75 → 76 taken 1 time.
✓ Branch 75 → 77 taken 54 times.
✓ Branch 78 → 79 taken 1 time.
✓ Branch 78 → 80 taken 72 times.
|
73 | if (tab.mailId.isValid() && tab.mailId.accountId != tab.accountId) return false; |
| 549 |
3/3✓ Branch 80 → 81 taken 72 times.
✓ Branch 81 → 82 taken 72 times.
✓ Branch 82 → 83 taken 72 times.
|
72 | const auto anchor = entry.value("anchor").toObject(); |
| 550 |
2/2✓ Branch 85 → 86 taken 72 times.
✓ Branch 86 → 87 taken 72 times.
|
72 | tab.anchor = decode(anchor.toVariantMap()); |
| 551 |
17/24✓ Branch 91 → 92 taken 5 times.
✓ Branch 91 → 99 taken 67 times.
✓ Branch 92 → 93 taken 5 times.
✓ Branch 93 → 94 taken 5 times.
✗ Branch 93 → 99 not taken.
✓ Branch 94 → 95 taken 5 times.
✓ Branch 95 → 96 taken 5 times.
✓ Branch 96 → 97 taken 5 times.
✓ Branch 97 → 98 taken 1 time.
✓ Branch 97 → 99 taken 4 times.
✓ Branch 100 → 101 taken 5 times.
✓ Branch 100 → 102 taken 67 times.
✓ Branch 102 → 103 taken 5 times.
✓ Branch 102 → 104 taken 67 times.
✓ Branch 104 → 105 taken 5 times.
✓ Branch 104 → 106 taken 67 times.
✓ Branch 106 → 107 taken 1 time.
✓ Branch 106 → 108 taken 71 times.
✗ Branch 210 → 211 not taken.
✗ Branch 210 → 212 not taken.
✗ Branch 214 → 215 not taken.
✗ Branch 214 → 216 not taken.
✗ Branch 218 → 219 not taken.
✗ Branch 218 → 220 not taken.
|
72 | if (!tab.anchor.isValid() && !anchor.isEmpty() && anchor != QJsonObject::fromVariantMap(encode(MailId{}))) |
| 552 | 1 | return false; | |
| 553 | // S106-333: the anchor is fenced like the previewed mail. | ||
| 554 |
6/6✓ Branch 109 → 110 taken 67 times.
✓ Branch 109 → 113 taken 4 times.
✓ Branch 111 → 112 taken 1 time.
✓ Branch 111 → 113 taken 66 times.
✓ Branch 114 → 115 taken 1 time.
✓ Branch 114 → 116 taken 70 times.
|
71 | if (tab.anchor.isValid() && tab.anchor.accountId != tab.accountId) return false; |
| 555 |
3/3✓ Branch 116 → 117 taken 70 times.
✓ Branch 117 → 118 taken 70 times.
✓ Branch 118 → 119 taken 70 times.
|
70 | tab.mode = entry.value("readingMode").toString(); |
| 556 |
1/2✗ Branch 124 → 125 not taken.
✓ Branch 124 → 132 taken 70 times.
|
70 | if (tab.mode == "html-light") tab.mode = QStringLiteral("light"); |
| 557 |
2/8✗ Branch 133 → 134 not taken.
✓ Branch 133 → 139 taken 70 times.
✗ Branch 135 → 136 not taken.
✗ Branch 135 → 139 not taken.
✗ Branch 137 → 138 not taken.
✗ Branch 137 → 139 not taken.
✗ Branch 140 → 141 not taken.
✓ Branch 140 → 142 taken 70 times.
|
70 | if (tab.mode != "text" && tab.mode != "light" && tab.mode != "html") tab.mode = m_configuredMode; |
| 558 | 70 | tab.tooltip = tab.query; | |
| 559 | 70 | return true; | |
| 560 | 73 | } | |
| 561 | |||
| 562 | 17 | void WorkspaceState::emitRemoved(const QList<Tab> &before) { | |
| 563 |
2/2✓ Branch 10 → 4 taken 40 times.
✓ Branch 10 → 11 taken 17 times.
|
57 | for (const auto &tab : before) |
| 564 |
3/3✓ Branch 6 → 7 taken 14 times.
✓ Branch 6 → 8 taken 26 times.
✓ Branch 7 → 8 taken 14 times.
|
40 | if (rowForTabId(tab.id) < 0) emit tabRemoved(tab.id, tab.kind); |
| 565 | 17 | } | |
| 566 | |||
| 567 | 12 | QString WorkspaceState::tabKind(int index) const { | |
| 568 |
3/4✓ Branch 2 → 3 taken 12 times.
✗ Branch 2 → 7 not taken.
✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 7 taken 1 time.
|
12 | return index >= 0 && index < m_tabs.size() ? m_tabs.at(index).kind : QString(); |
| 569 | } | ||
| 570 | |||
| 571 | 873 | int WorkspaceState::rowForTabId(const QString &tabId) const { | |
| 572 |
2/2✓ Branch 9 → 3 taken 1813 times.
✓ Branch 9 → 10 taken 113 times.
|
1926 | for (int row = 0; row < m_tabs.size(); ++row) |
| 573 |
2/2✓ Branch 5 → 6 taken 760 times.
✓ Branch 5 → 7 taken 1053 times.
|
1813 | if (m_tabs.at(row).id == tabId) return row; |
| 574 | 113 | return -1; | |
| 575 | } | ||
| 576 | |||
| 577 | 113 | int WorkspaceState::openSearch(const QString &query, const QString &accountId, const QString &title, bool newTab) { | |
| 578 |
7/8✓ Branch 3 → 4 taken 112 times.
✓ Branch 3 → 8 taken 1 time.
✓ Branch 5 → 6 taken 111 times.
✓ Branch 5 → 8 taken 1 time.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 111 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 111 times.
|
113 | if (query.size() > MaximumQueryCharacters || accountId.isEmpty() || accountId.size() > 1024) return -1; |
| 579 | 111 | int reuse = -1; | |
| 580 |
2/2✓ Branch 36 → 13 taken 34 times.
✓ Branch 36 → 37 taken 110 times.
|
144 | for (int row = 1; row < m_tabs.size(); ++row) { |
| 581 | 34 | const auto &tab = m_tabs.at(row); | |
| 582 |
6/6✓ Branch 16 → 17 taken 25 times.
✓ Branch 16 → 19 taken 9 times.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 20 taken 23 times.
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 23 taken 23 times.
|
34 | if (tab.kind != QLatin1String("search") || tab.accountId != accountId) continue; |
| 583 |
3/3✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 22 times.
✓ Branch 25 → 26 taken 1 time.
|
23 | if (tab.query == query) { activateTab(row); return row; } // D-2: the same search exists |
| 584 |
6/6✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 30 taken 17 times.
✓ Branch 29 → 30 taken 4 times.
✓ Branch 29 → 31 taken 1 time.
✓ Branch 32 → 33 taken 21 times.
✓ Branch 32 → 34 taken 1 time.
|
22 | if (reuse < 0 || tab.used > m_tabs.at(reuse).used) reuse = row; |
| 585 | } | ||
| 586 |
4/4✓ Branch 37 → 38 taken 17 times.
✓ Branch 37 → 45 taken 93 times.
✓ Branch 38 → 39 taken 8 times.
✓ Branch 38 → 45 taken 9 times.
|
110 | if (reuse >= 0 && !newTab) { |
| 587 | 8 | const QString id = m_tabs.at(reuse).id; | |
| 588 |
1/1✓ Branch 41 → 42 taken 8 times.
|
8 | activateTab(reuse); |
| 589 |
1/1✓ Branch 42 → 43 taken 8 times.
|
8 | setSearchQuery(id, query, title, query); |
| 590 | 8 | return reuse; | |
| 591 | 8 | } | |
| 592 |
1/2✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 102 times.
|
102 | if (m_tabs.size() >= MaximumTabs) return -1; |
| 593 |
1/1✓ Branch 48 → 49 taken 102 times.
|
102 | Tab tab; |
| 594 |
2/2✓ Branch 49 → 50 taken 102 times.
✓ Branch 50 → 51 taken 102 times.
|
102 | tab.id = QUuid::createUuid().toString(QUuid::WithoutBraces); |
| 595 | 102 | tab.kind = QStringLiteral("search"); | |
| 596 |
1/1✓ Branch 59 → 60 taken 102 times.
|
102 | tab.title = title.left(1024); |
| 597 | 102 | tab.tooltip = query; | |
| 598 | 102 | tab.query = query; | |
| 599 | 102 | tab.accountId = accountId; | |
| 600 | 102 | tab.mode = m_configuredMode; | |
| 601 | 102 | const int row = m_tabs.size(); | |
| 602 |
1/1✓ Branch 68 → 69 taken 102 times.
|
102 | beginInsertRows({}, row, row); |
| 603 |
1/1✓ Branch 69 → 70 taken 102 times.
|
102 | m_tabs.append(tab); |
| 604 |
1/1✓ Branch 70 → 71 taken 102 times.
|
102 | endInsertRows(); |
| 605 |
1/1✓ Branch 71 → 72 taken 102 times.
|
102 | activateTab(row); |
| 606 | 102 | return row; | |
| 607 | 102 | } | |
| 608 | |||
| 609 | 148 | bool WorkspaceState::setSearchQuery(const QString &tabId, const QString &query, const QString &title, | |
| 610 | const QString &tooltip) { | ||
| 611 | 148 | const int row = rowForTabId(tabId); | |
| 612 |
4/8✓ Branch 3 → 4 taken 148 times.
✗ Branch 3 → 10 not taken.
✓ Branch 7 → 8 taken 148 times.
✗ Branch 7 → 10 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 148 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 148 times.
|
148 | if (row < 0 || m_tabs.at(row).kind != QLatin1String("search") || query.size() > MaximumQueryCharacters) return false; |
| 613 | 148 | auto &tab = m_tabs[row]; | |
| 614 |
9/13✓ Branch 16 → 17 taken 91 times.
✓ Branch 16 → 23 taken 57 times.
✓ Branch 17 → 18 taken 91 times.
✓ Branch 19 → 20 taken 91 times.
✗ Branch 19 → 23 not taken.
✓ Branch 21 → 22 taken 91 times.
✗ Branch 21 → 23 not taken.
✓ Branch 24 → 25 taken 91 times.
✓ Branch 24 → 26 taken 57 times.
✓ Branch 26 → 27 taken 91 times.
✓ Branch 26 → 28 taken 57 times.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
|
148 | if (tab.query == query && tab.title == title.left(1024) && tab.tooltip == tooltip) return true; |
| 615 | 57 | tab.query = query; | |
| 616 |
1/1✓ Branch 29 → 30 taken 57 times.
|
57 | tab.title = title.left(1024); |
| 617 |
1/1✓ Branch 32 → 33 taken 57 times.
|
57 | tab.tooltip = tooltip.left(MaximumQueryCharacters); |
| 618 |
4/4✓ Branch 35 → 36 taken 57 times.
✓ Branch 37 → 38 taken 57 times.
✓ Branch 39 → 40 taken 57 times.
✓ Branch 40 → 41 taken 57 times.
|
57 | emit dataChanged(index(row), index(row), {TitleRole, TooltipRole}); |
| 619 | 57 | return true; | |
| 620 | } | ||
| 621 | |||
| 622 | 103 | QString WorkspaceState::searchQuery(const QString &tabId) const { | |
| 623 | 103 | const int row = rowForTabId(tabId); | |
| 624 |
1/2✓ Branch 3 → 4 taken 103 times.
✗ Branch 3 → 6 not taken.
|
103 | return row >= 0 ? m_tabs.at(row).query : QString(); |
| 625 | } | ||
| 626 | |||
| 627 | 92 | QString WorkspaceState::searchAccount(const QString &tabId) const { | |
| 628 | 92 | const int row = rowForTabId(tabId); | |
| 629 |
1/2✓ Branch 3 → 4 taken 92 times.
✗ Branch 3 → 6 not taken.
|
92 | return row >= 0 ? m_tabs.at(row).accountId : QString(); |
| 630 | } | ||
| 631 | |||
| 632 | 110 | QStringList WorkspaceState::searchTabIds() const { | |
| 633 | 110 | QStringList ids; | |
| 634 |
2/2✓ Branch 11 → 4 taken 233 times.
✓ Branch 11 → 12 taken 110 times.
|
343 | for (const auto &tab : m_tabs) |
| 635 |
3/3✓ Branch 7 → 8 taken 120 times.
✓ Branch 7 → 9 taken 113 times.
✓ Branch 8 → 9 taken 120 times.
|
233 | if (tab.kind == QLatin1String("search")) ids.append(tab.id); |
| 636 | 110 | return ids; | |
| 637 | ✗ | } | |
| 638 | |||
| 639 | 120 | bool WorkspaceState::setSearchAnchor(const QString &tabId, const MailId &anchor) { | |
| 640 | 120 | const int row = rowForTabId(tabId); | |
| 641 |
3/6✓ Branch 3 → 4 taken 120 times.
✗ Branch 3 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 120 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 120 times.
|
120 | if (row < 0 || m_tabs.at(row).kind != QLatin1String("search")) return false; |
| 642 |
5/6✓ Branch 13 → 14 taken 120 times.
✗ Branch 13 → 18 not taken.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 119 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 119 times.
|
120 | if (anchor.isValid() && anchor.accountId != m_tabs.at(row).accountId) return false; // S106-333 |
| 643 | 119 | m_tabs[row].anchor = anchor; | |
| 644 | 119 | return true; | |
| 645 | } | ||
| 646 | |||
| 647 | 1 | MailId WorkspaceState::searchAnchor(const QString &tabId) const { | |
| 648 | 1 | const int row = rowForTabId(tabId); | |
| 649 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | return row >= 0 ? m_tabs.at(row).anchor : MailId{}; |
| 650 | } | ||
| 651 | |||
| 652 | 1590 | void WorkspaceState::setActiveAccount(const QString &accountId) { | |
| 653 |
2/2✓ Branch 3 → 4 taken 810 times.
✓ Branch 3 → 5 taken 780 times.
|
1590 | if (m_activeAccount == accountId) return; |
| 654 | 780 | m_activeAccount = accountId; | |
| 655 |
5/6✓ Branch 7 → 8 taken 780 times.
✗ Branch 7 → 17 not taken.
✓ Branch 8 → 9 taken 780 times.
✓ Branch 11 → 12 taken 780 times.
✓ Branch 13 → 14 taken 780 times.
✓ Branch 14 → 15 taken 780 times.
|
780 | if (!m_tabs.isEmpty()) emit dataChanged(index(0), index(int(m_tabs.size()) - 1), {DormantRole}); |
| 656 | } | ||
| 657 | |||
| 658 | 1589 | bool WorkspaceState::tabDormant(int row) const { | |
| 659 |
3/6✓ Branch 2 → 3 taken 1589 times.
✗ Branch 2 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1589 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1589 times.
|
1589 | if (row < 0 || row >= m_tabs.size()) return false; |
| 660 | 1589 | const auto &tab = m_tabs.at(row); | |
| 661 |
5/6✓ Branch 12 → 13 taken 318 times.
✓ Branch 12 → 18 taken 1271 times.
✓ Branch 14 → 15 taken 318 times.
✗ Branch 14 → 18 not taken.
✓ Branch 16 → 17 taken 18 times.
✓ Branch 16 → 18 taken 300 times.
|
1589 | return tab.kind == QLatin1String("search") && !m_activeAccount.isEmpty() && tab.accountId != m_activeAccount; |
| 662 | } | ||
| 663 | |||
| 664 | 2 | bool WorkspaceState::activatePreviousTab() { | |
| 665 | 2 | const int previous = rowForTabId(m_previousTabId); | |
| 666 |
2/4✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
|
2 | return activateTab(previous >= 0 && previous != m_activeTab ? previous : 0); |
| 667 | } | ||
| 668 | |||
| 669 | // ── Sprint 108 S108.9.1: compose tabs ─────────────────────────────────── | ||
| 670 | |||
| 671 | 301 | bool WorkspaceState::validComposeSessionId(const QString &sessionId) { | |
| 672 |
5/6✓ Branch 3 → 4 taken 300 times.
✓ Branch 3 → 6 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 300 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 300 times.
|
301 | if (sessionId.isEmpty() || sessionId.size() > 64) return false; |
| 673 | 300 | return std::all_of(sessionId.cbegin(), sessionId.cend(), [](QChar c) { | |
| 674 |
10/14✓ Branch 5 → 6 taken 9354 times.
✓ Branch 5 → 10 taken 1173 times.
✓ Branch 9 → 10 taken 3319 times.
✓ Branch 9 → 29 taken 6035 times.
✓ Branch 13 → 14 taken 3319 times.
✓ Branch 13 → 18 taken 1173 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 29 taken 3319 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 26 taken 1173 times.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 29 not taken.
✓ Branch 28 → 29 taken 1171 times.
✓ Branch 28 → 30 taken 2 times.
|
10527 | return (c >= u'0' && c <= u'9') || (c >= u'a' && c <= u'z') || (c >= u'A' && c <= u'Z') || c == u'-'; |
| 675 | 300 | }); | |
| 676 | } | ||
| 677 | |||
| 678 | 219 | int WorkspaceState::openCompose(const QString &sessionId, const QString &title, bool activate) { | |
| 679 |
3/3✓ Branch 2 → 3 taken 219 times.
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 217 times.
|
219 | if (!validComposeSessionId(sessionId)) return -1; |
| 680 | 217 | const int existing = rowForComposeSession(sessionId); | |
| 681 |
2/2✓ Branch 6 → 7 taken 112 times.
✓ Branch 6 → 10 taken 105 times.
|
217 | if (existing >= 0) { |
| 682 |
2/3✓ Branch 7 → 8 taken 112 times.
✗ Branch 7 → 9 not taken.
✓ Branch 8 → 9 taken 112 times.
|
112 | if (activate) activateTab(existing); |
| 683 | 112 | return existing; | |
| 684 | } | ||
| 685 |
1/2✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 105 times.
|
105 | if (m_tabs.size() >= MaximumTabs) return -1; |
| 686 |
1/1✓ Branch 13 → 14 taken 105 times.
|
105 | Tab tab; |
| 687 |
2/2✓ Branch 14 → 15 taken 105 times.
✓ Branch 15 → 16 taken 105 times.
|
105 | tab.id = QUuid::createUuid().toString(QUuid::WithoutBraces); |
| 688 | 105 | tab.kind = QStringLiteral("compose"); | |
| 689 |
1/1✓ Branch 24 → 25 taken 105 times.
|
105 | tab.title = title.left(1024); |
| 690 | 105 | tab.sessionId = sessionId; | |
| 691 | 105 | tab.mode = m_configuredMode; | |
| 692 | 105 | const int row = m_tabs.size(); | |
| 693 |
1/1✓ Branch 31 → 32 taken 105 times.
|
105 | beginInsertRows({}, row, row); |
| 694 |
1/1✓ Branch 32 → 33 taken 105 times.
|
105 | m_tabs.append(tab); |
| 695 |
1/1✓ Branch 33 → 34 taken 105 times.
|
105 | endInsertRows(); |
| 696 |
3/3✓ Branch 34 → 35 taken 3 times.
✓ Branch 34 → 36 taken 102 times.
✓ Branch 35 → 36 taken 3 times.
|
105 | if (activate) activateTab(row); |
| 697 |
2/6✓ Branch 36 → 37 taken 105 times.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 46 → 38 not taken.
✓ Branch 46 → 47 taken 105 times.
|
105 | qCInfo(lcCompose) << "compose tab opened for session" << sessionId; |
| 698 | 105 | return row; | |
| 699 | 105 | } | |
| 700 | |||
| 701 | 106 | bool WorkspaceState::setComposeTitle(const QString &sessionId, const QString &title) { | |
| 702 | 106 | const int row = rowForComposeSession(sessionId); | |
| 703 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 105 times.
|
106 | if (row < 0) return false; |
| 704 |
3/3✓ Branch 5 → 6 taken 105 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 104 times.
|
105 | if (m_tabs.at(row).title == title.left(1024)) return true; |
| 705 |
2/2✓ Branch 11 → 12 taken 104 times.
✓ Branch 12 → 13 taken 104 times.
|
104 | m_tabs[row].title = title.left(1024); |
| 706 |
4/4✓ Branch 15 → 16 taken 104 times.
✓ Branch 17 → 18 taken 104 times.
✓ Branch 19 → 20 taken 104 times.
✓ Branch 20 → 21 taken 104 times.
|
104 | emit dataChanged(index(row), index(row), {TitleRole}); |
| 707 | 104 | return true; | |
| 708 | } | ||
| 709 | |||
| 710 | 38 | bool WorkspaceState::closeCompose(const QString &sessionId) { | |
| 711 | 38 | const int row = rowForComposeSession(sessionId); | |
| 712 |
3/4✓ Branch 3 → 4 taken 37 times.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 5 → 6 taken 37 times.
✗ Branch 5 → 7 not taken.
|
38 | return row >= 0 && closeTab(row); |
| 713 | } | ||
| 714 | |||
| 715 | 189 | QString WorkspaceState::composeSessionAt(int row) const { | |
| 716 |
2/4✓ Branch 2 → 3 taken 189 times.
✗ Branch 2 → 7 not taken.
✓ Branch 4 → 5 taken 189 times.
✗ Branch 4 → 7 not taken.
|
189 | return row >= 0 && row < m_tabs.size() ? m_tabs.at(row).sessionId : QString(); |
| 717 | } | ||
| 718 | |||
| 719 | 508 | int WorkspaceState::rowForComposeSession(const QString &sessionId) const { | |
| 720 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 508 times.
|
508 | if (sessionId.isEmpty()) return -1; |
| 721 |
2/2✓ Branch 19 → 6 taken 924 times.
✓ Branch 19 → 20 taken 220 times.
|
1144 | for (int row = 0; row < m_tabs.size(); ++row) |
| 722 |
6/6✓ Branch 9 → 10 taken 381 times.
✓ Branch 9 → 14 taken 543 times.
✓ Branch 12 → 13 taken 288 times.
✓ Branch 12 → 14 taken 93 times.
✓ Branch 15 → 16 taken 288 times.
✓ Branch 15 → 17 taken 636 times.
|
924 | if (m_tabs.at(row).kind == QLatin1String("compose") && m_tabs.at(row).sessionId == sessionId) return row; |
| 723 | 220 | return -1; | |
| 724 | } | ||
| 725 | |||
| 726 | 945 | QStringList WorkspaceState::composeSessionIds() const { | |
| 727 | 945 | QStringList ids; | |
| 728 |
2/2✓ Branch 11 → 4 taken 1158 times.
✓ Branch 11 → 12 taken 945 times.
|
2103 | for (const auto &tab : m_tabs) |
| 729 |
3/3✓ Branch 7 → 8 taken 74 times.
✓ Branch 7 → 9 taken 1084 times.
✓ Branch 8 → 9 taken 74 times.
|
1158 | if (tab.kind == QLatin1String("compose")) ids.append(tab.sessionId); |
| 730 | 945 | return ids; | |
| 731 | ✗ | } | |
| 732 | |||
| 733 | 8 | int WorkspaceState::openOutbox(const QString &title) { | |
| 734 |
2/2✓ Branch 11 → 3 taken 1 time.
✓ Branch 11 → 12 taken 7 times.
|
8 | for (int row = 1; row < m_tabs.size(); ++row) |
| 735 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 9 not taken.
|
1 | if (m_tabs.at(row).kind == QLatin1String("outbox")) { |
| 736 |
1/1✓ Branch 7 → 8 taken 1 time.
|
1 | activateTab(row); |
| 737 | 1 | return row; | |
| 738 | } | ||
| 739 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 7 times.
|
7 | if (m_tabs.size() >= MaximumTabs) return -1; |
| 740 |
1/1✓ Branch 15 → 16 taken 7 times.
|
7 | Tab tab; |
| 741 |
2/2✓ Branch 16 → 17 taken 7 times.
✓ Branch 17 → 18 taken 7 times.
|
7 | tab.id = QUuid::createUuid().toString(QUuid::WithoutBraces); |
| 742 | 7 | tab.kind = QStringLiteral("outbox"); | |
| 743 |
1/1✓ Branch 26 → 27 taken 7 times.
|
7 | tab.title = title.left(1024); |
| 744 | 7 | tab.mode = m_configuredMode; | |
| 745 | 7 | const int row = m_tabs.size(); | |
| 746 |
1/1✓ Branch 32 → 33 taken 7 times.
|
7 | beginInsertRows({}, row, row); |
| 747 |
1/1✓ Branch 33 → 34 taken 7 times.
|
7 | m_tabs.append(tab); |
| 748 |
1/1✓ Branch 34 → 35 taken 7 times.
|
7 | endInsertRows(); |
| 749 |
1/1✓ Branch 35 → 36 taken 7 times.
|
7 | activateTab(row); |
| 750 | 7 | return row; | |
| 751 | 7 | } | |
| 752 |