• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 18018707227

25 Sep 2025 07:35PM UTC coverage: 68.577% (-0.3%) from 68.889%
18018707227

push

github

paulmthompson
selection for lines appears to work well

11 of 59 new or added lines in 2 files covered. (18.64%)

797 existing lines in 9 files now uncovered.

42024 of 61280 relevant lines covered (68.58%)

1133.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.33
/src/WhiskerToolbox/GroupManagementWidget/GroupManager.cpp
1
#include "GroupManager.hpp"
2

3
#include "DataManager/Entity/EntityGroupManager.hpp"
4

5
#include <QDebug>
6

7
QVector<QColor> const GroupManager::DEFAULT_COLORS = {
8
        QColor(31, 119, 180), // Blue
9
        QColor(255, 127, 14), // Orange
10
        QColor(44, 160, 44),  // Green
11
        QColor(214, 39, 40),  // Red
12
        QColor(148, 103, 189),// Purple
13
        QColor(140, 86, 75),  // Brown
14
        QColor(227, 119, 194),// Pink
15
        QColor(127, 127, 127),// Gray
16
        QColor(188, 189, 34), // Olive
17
        QColor(23, 190, 207)  // Cyan
18
};
19

20
GroupManager::GroupManager(EntityGroupManager * entity_group_manager, QObject * parent)
34✔
21
    : QObject(parent),
22
      m_entity_group_manager(entity_group_manager),
34✔
23
      m_next_group_id(1) {
34✔
24
    // Assert that we have a valid EntityGroupManager
25
    Q_ASSERT(m_entity_group_manager != nullptr);
34✔
26
}
34✔
27

28
int GroupManager::createGroup(QString const & name) {
19✔
29
    QColor const color = getNextDefaultColor();
19✔
30
    return createGroup(name, color);
38✔
31
}
32

33
int GroupManager::createGroup(QString const & name, QColor const & color) {
19✔
34

35
    GroupId const entity_group_id = m_entity_group_manager->createGroup(name.toStdString());
57✔
36

37
    auto const group_id = static_cast<int>(entity_group_id);
19✔
38
    m_group_colors[group_id] = color;
19✔
39

40
    qDebug() << "GroupManager: Created group" << group_id << "with name" << name;
19✔
41

42
    emit groupCreated(group_id);
19✔
43
    return group_id;
19✔
44
}
45

46
bool GroupManager::removeGroup(int group_id) {
3✔
47
    auto entity_group_id = static_cast<GroupId>(group_id);
3✔
48

49
    if (!m_entity_group_manager->deleteGroup(entity_group_id)) {
3✔
50
        return false;
1✔
51
    }
52

53
    m_group_colors.remove(group_id);
2✔
54

55
    qDebug() << "GroupManager: Removed group" << group_id;
2✔
56

57
    emit groupRemoved(group_id);
2✔
58
    return true;
2✔
59
}
60

61
std::optional<GroupManager::Group> GroupManager::getGroup(int group_id) const {
15✔
62
    auto entity_group_id = static_cast<GroupId>(group_id);
15✔
63

64
    auto descriptor = m_entity_group_manager->getGroupDescriptor(entity_group_id);
15✔
65
    if (!descriptor.has_value()) {
15✔
66
        return std::nullopt;
×
67
    }
68

69
    Group group(group_id,
15✔
70
                QString::fromStdString(descriptor->name),
30✔
71
                m_group_colors.value(group_id, QColor(128, 128, 128)));
45✔
72

73
    return group;
15✔
74
}
15✔
75

76
bool GroupManager::setGroupName(int group_id, QString const & name) {
9✔
77
    auto entity_group_id = static_cast<GroupId>(group_id);
9✔
78

79
    // Get current descriptor to preserve description
80
    auto descriptor = m_entity_group_manager->getGroupDescriptor(entity_group_id);
9✔
81
    if (!descriptor.has_value()) {
9✔
82
        return false;
×
83
    }
84

85
    // Avoid redundant updates/signals if the name is unchanged
86
    if (QString::fromStdString(descriptor->name) == name) {
9✔
87
        return true;
5✔
88
    }
89

90
    if (!m_entity_group_manager->updateGroup(entity_group_id, name.toStdString(), descriptor->description)) {
4✔
91
        return false;
×
92
    }
93

94
    qDebug() << "GroupManager: Updated group" << group_id << "name to" << name;
4✔
95

96
    emit groupModified(group_id);
4✔
97
    return true;
4✔
98
}
9✔
99

100
bool GroupManager::setGroupColor(int group_id, QColor const & color) {
2✔
101
    auto entity_group_id = static_cast<GroupId>(group_id);
2✔
102

103
    if (!m_entity_group_manager->hasGroup(entity_group_id)) {
2✔
104
        return false;
×
105
    }
106

107
    m_group_colors[group_id] = color;
2✔
108

109
    qDebug() << "GroupManager: Updated group" << group_id << "color";
2✔
110

111
    emit groupModified(group_id);
2✔
112
    return true;
2✔
113
}
114

115
QMap<int, GroupManager::Group> GroupManager::getGroups() const {
49✔
116
    QMap<int, Group> result;
49✔
117

118
    auto group_ids = m_entity_group_manager->getAllGroupIds();
49✔
119
    for (GroupId const entity_group_id: group_ids) {
68✔
120
        auto descriptor = m_entity_group_manager->getGroupDescriptor(entity_group_id);
19✔
121
        if (descriptor.has_value()) {
19✔
122
            auto group_id = static_cast<int>(entity_group_id);
19✔
123
            Group const group(group_id,
19✔
124
                              QString::fromStdString(descriptor->name),
38✔
125
                              m_group_colors.value(group_id, QColor(128, 128, 128)));
57✔
126
            result[group_id] = group;
19✔
127
        }
19✔
128
    }
19✔
129

130
    return result;
49✔
131
}
49✔
132

133
// ===== EntityId-based API =====
134
bool GroupManager::assignEntitiesToGroup(int group_id, std::unordered_set<EntityId> const & entity_ids) {
13✔
135
    auto entity_group_id = static_cast<GroupId>(group_id);
13✔
136

137
    if (!m_entity_group_manager->hasGroup(entity_group_id)) {
13✔
138
        return false;
×
139
    }
140

141
    std::vector<EntityId> const entity_vector(entity_ids.begin(), entity_ids.end());
39✔
142

143
    std::size_t const added_count = m_entity_group_manager->addEntitiesToGroup(entity_group_id, entity_vector);
13✔
144

145
    qDebug() << "GroupManager: Assigned" << added_count << "entities to group" << group_id;
13✔
146
    if (added_count > 0) {
13✔
147
        emit groupModified(group_id);
11✔
148
    }
149

150
    return added_count > 0;
13✔
151
}
13✔
152

153
bool GroupManager::removeEntitiesFromGroup(int group_id, std::unordered_set<EntityId> const & entity_ids) {
6✔
154
    auto entity_group_id = static_cast<GroupId>(group_id);
6✔
155

156
    if (!m_entity_group_manager->hasGroup(entity_group_id)) {
6✔
157
        return false;
×
158
    }
159

160
    std::vector<EntityId> const entity_vector(entity_ids.begin(), entity_ids.end());
18✔
161

162
    std::size_t const removed_count = m_entity_group_manager->removeEntitiesFromGroup(entity_group_id, entity_vector);
6✔
163

164
    if (removed_count > 0) {
6✔
165
        qDebug() << "GroupManager: Removed" << removed_count << "entities from group" << group_id;
4✔
166
        emit groupModified(group_id);
4✔
167
    }
168

169
    return removed_count > 0;
6✔
170
}
6✔
171

172
void GroupManager::ungroupEntities(std::unordered_set<EntityId> const & entity_ids) {
1✔
173
    std::unordered_set<int> affected_groups;
1✔
174

175
    // For each entity, find which groups it belongs to and remove it
176
    for (EntityId const entity_id: entity_ids) {
2✔
177
        auto group_ids = m_entity_group_manager->getGroupsContainingEntity(entity_id);
1✔
178
        for (GroupId const entity_group_id: group_ids) {
3✔
179
            auto const group_id = static_cast<int>(entity_group_id);
2✔
180
            affected_groups.insert(group_id);
2✔
181

182
            std::vector<EntityId> const single_entity = {entity_id};
6✔
183
            m_entity_group_manager->removeEntitiesFromGroup(entity_group_id, single_entity);
2✔
184
        }
2✔
185
    }
1✔
186

187
    if (!affected_groups.empty()) {
1✔
188
        qDebug() << "GroupManager: Ungrouped" << entity_ids.size() << "entities from" << affected_groups.size() << "groups";
1✔
189
        for (int const gid: affected_groups) {
3✔
190
            emit groupModified(gid);
2✔
191
        }
192
    }
193
}
2✔
194

195
int GroupManager::getEntityGroup(EntityId id) const {
28✔
196
    auto group_ids = m_entity_group_manager->getGroupsContainingEntity(id);
28✔
197

198
    // Return the first group (assuming entities belong to at most one group for now)
199
    if (!group_ids.empty()) {
28✔
200
        return static_cast<int>(group_ids[0]);
4✔
201
    }
202

203
    return -1;// Not in any group
24✔
204
}
28✔
205

206
QColor GroupManager::getEntityColor(EntityId id, QColor const & default_color) const {
×
207
    int const group_id = getEntityGroup(id);
×
208
    if (group_id == -1) {
×
209
        return default_color;
×
210
    }
211

212
    return m_group_colors.value(group_id, default_color);
×
213
}
214

215
int GroupManager::getGroupMemberCount(int group_id) const {
18✔
216
    auto entity_group_id = static_cast<GroupId>(group_id);
18✔
217
    return static_cast<int>(m_entity_group_manager->getGroupSize(entity_group_id));
18✔
218
}
219

220
void GroupManager::clearAllGroups() {
×
221
    qDebug() << "GroupManager: Clearing all groups";
×
222

223
    // Clear EntityGroupManager
224
    m_entity_group_manager->clear();
×
225

226
    // Clear our color mappings
227
    m_group_colors.clear();
×
228

229
    m_next_group_id = 1;
×
230

231
    // Note: We don't emit specific signals here since everything is being cleared
232
}
×
233

234
QColor GroupManager::getNextDefaultColor() const {
19✔
235
    if (DEFAULT_COLORS.isEmpty()) {
19✔
236
        return {128, 128, 128};// Fallback gray
×
237
    }
238

239
    // Cycle through the default colors based on current group count
240
    auto group_ids = m_entity_group_manager->getAllGroupIds();
19✔
241
    auto color_index = static_cast<int>(group_ids.size()) % DEFAULT_COLORS.size();
19✔
242
    return DEFAULT_COLORS[color_index];
19✔
243
}
19✔
244

245
// ===== Common Group Operations for Context Menus =====
246

UNCOV
247
int GroupManager::createGroupWithEntities(std::unordered_set<EntityId> const & entity_ids) {
×
UNCOV
248
    if (entity_ids.empty()) {
×
UNCOV
249
        return -1;
×
250
    }
251

UNCOV
252
    QString group_name = QString("Group %1").arg(m_entity_group_manager->getAllGroupIds().size() + 1);
×
UNCOV
253
    int group_id = createGroup(group_name);
×
254
    
UNCOV
255
    if (group_id != -1) {
×
UNCOV
256
        assignEntitiesToGroup(group_id, entity_ids);
×
257
    }
258
    
UNCOV
259
    return group_id;
×
UNCOV
260
}
×
261

UNCOV
262
std::vector<std::pair<int, QString>> GroupManager::getGroupsForContextMenu() const {
×
UNCOV
263
    std::vector<std::pair<int, QString>> result;
×
264
    
UNCOV
265
    auto groups = getGroups();
×
UNCOV
266
    for (auto it = groups.begin(); it != groups.end(); ++it) {
×
UNCOV
267
        result.emplace_back(it.key(), it.value().name);
×
268
    }
269
    
UNCOV
270
    return result;
×
UNCOV
271
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc