+ shared_ptr<sigrok::Device> device = session_.device();
+ assert(device);
+
+ // Collect a set of signals
+ unordered_map<shared_ptr<sigrok::Channel>, shared_ptr<Signal> >
+ signal_map;
+
+ shared_lock<shared_mutex> lock(session_.signals_mutex());
+ const vector< shared_ptr<Signal> > &sigs(session_.signals());
+
+ for (const shared_ptr<Signal> &sig : sigs)
+ signal_map[sig->channel()] = sig;
+
+ // Populate channel groups
+ for (auto entry : device->channel_groups())
+ {
+ const shared_ptr<sigrok::ChannelGroup> &group = entry.second;
+
+ if (group->channels().size() <= 1)
+ continue;
+
+ shared_ptr<TraceGroup> trace_group(new TraceGroup());
+ int child_offset = 0;
+ if (add_channels_to_owner(group->channels(),
+ trace_group.get(), child_offset, signal_map))
+ {
+ add_child_item(trace_group);
+ apply_offset(trace_group, offset);
+ }
+ }
+
+ // Add the remaining logic channels
+ shared_ptr<TraceGroup> logic_trace_group(new TraceGroup());
+ int child_offset = 0;
+
+ if (add_channels_to_owner(device->channels(),
+ logic_trace_group.get(), child_offset, signal_map,
+ [](shared_ptr<RowItem> r) -> bool {
+ return dynamic_pointer_cast<LogicSignal>(r) != nullptr;
+ }))
+
+ {
+ add_child_item(logic_trace_group);
+ apply_offset(logic_trace_group, offset);
+ }
+
+ // Add the remaining channels
+ add_channels_to_owner(device->channels(), this, offset, signal_map);
+ assert(signal_map.empty());