* @brief Reorders @c m_columnUniqueIds to match FrameBuilder's parsing order. */
| 762 | * @brief Reorders @c m_columnUniqueIds to match FrameBuilder's parsing order. |
| 763 | */ |
| 764 | void Sessions::Player::alignColumnsToProject() |
| 765 | { |
| 766 | if (m_columnUniqueIds.empty()) |
| 767 | return; |
| 768 | |
| 769 | QMap<int, QPair<int, int>> uidToSrcIndex; |
| 770 | const auto& groups = DataModel::ProjectModel::instance().groups(); |
| 771 | for (const auto& g : groups) |
| 772 | for (const auto& d : g.datasets) |
| 773 | uidToSrcIndex.insert(d.uniqueId, qMakePair(g.sourceId, d.index)); |
| 774 | |
| 775 | QMap<int, std::vector<QPair<int, int>>> bySource; |
| 776 | std::vector<int> orphans; |
| 777 | for (int uid : m_columnUniqueIds) { |
| 778 | const auto it = uidToSrcIndex.constFind(uid); |
| 779 | if (it == uidToSrcIndex.constEnd()) { |
| 780 | orphans.push_back(uid); |
| 781 | continue; |
| 782 | } |
| 783 | |
| 784 | bySource[it.value().first].push_back(qMakePair(it.value().second, uid)); |
| 785 | } |
| 786 | |
| 787 | for (auto it = bySource.begin(); it != bySource.end(); ++it) |
| 788 | std::sort(it.value().begin(), it.value().end(), [](const auto& a, const auto& b) { |
| 789 | return a.first < b.first; |
| 790 | }); |
| 791 | |
| 792 | std::vector<int> aligned; |
| 793 | aligned.reserve(m_columnUniqueIds.size()); |
| 794 | for (auto it = bySource.constBegin(); it != bySource.constEnd(); ++it) |
| 795 | for (const auto& pair : it.value()) |
| 796 | aligned.push_back(pair.second); |
| 797 | |
| 798 | for (int uid : orphans) |
| 799 | aligned.push_back(uid); |
| 800 | |
| 801 | m_columnUniqueIds.swap(aligned); |
| 802 | |
| 803 | m_uidToColumn.clear(); |
| 804 | for (int i = 0; i < static_cast<int>(m_columnUniqueIds.size()); ++i) |
| 805 | m_uidToColumn.insert(m_columnUniqueIds[static_cast<size_t>(i)], i); |
| 806 | } |
| 807 | |
| 808 | /** |
| 809 | * @brief Builds the per-source column lists and installs the FrameBuilder replay map |