#include "track.h" namespace LtsTimeline { const Track &Track::track(int id) const noexcept(false) { auto const it = std::find_if(m_childrenTracks.cbegin(), m_childrenTracks.cend(), [id](const TrackPtr &trackPtr) { return (trackPtr.get()->id() == id); }); if (it != m_childrenTracks.cend()) return **it; for (const TrackPtr &track : qAsConst(m_childrenTracks)) { try { return track->track(id); } catch(...) { } } throw QStringLiteral("lookup failed!");; } bool Track::hasTrack(int id, bool recursive) const { if (std::find_if(m_childrenTracks.cbegin(), m_childrenTracks.cend(), [id](const TrackPtr &trackPtr) { return (trackPtr.get()->id() == id); }) != m_childrenTracks.cend()) return true; if (!recursive) return false; for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) { if (trackPtr->hasTrack(id, true)) return true; } return false; } void Track::addCopyItemIds(const QSet &ids) { m_copyItemIds += ids; } void Track::addCopyItemId(int id) { m_copyItemIds += id; } const Track &Track::parentOf(int id) const noexcept(false) { for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) { if (trackPtr->hasTrack(id)) return *trackPtr; if (trackPtr->hasTrack(id, true)) return trackPtr->parentOf(id); } throw("not found"); } bool Track::isItemBetween(const Item &item, qint64 start, qint64 end, bool strict, bool complete, qint64 minimumDuration) { if (end - start == -1) { if (item.duration() == -1) { if (!complete) return true; return strict ? item.startTime() > start : item.startTime() >= start; } if (strict) { return (complete && item.startTime() > start) || (!complete && item.startTime() + item.duration() > start); } else { return (complete && item.startTime() >= start) || (!complete && item.startTime() + item.duration() >= start); } } if (item.duration() == -1) { if (complete) return false; return strict ? item.startTime() < end : item.startTime() <= end; } Q_ASSERT(end+1 > start); qint64 itemStart = item.startTime(), itemEnd = item.startTime() + (std::max((qint64)item.duration(), minimumDuration)); if (strict) return ((complete && (itemStart > start && itemEnd < end)) || (!complete && (itemEnd > start && itemStart < end))); else return ((complete && (itemStart >= start && itemEnd <= end)) || (!complete && (itemEnd >= start && itemStart <= end))); } void Track::removeCopyItem(int itemId) noexcept(false) { m_copyItemIds.remove(itemId); for (TrackPtr &t : m_childrenTracks) { t->removeCopyItem(itemId); } } const QVector Track::copyItemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const { auto itemPtrRefs = _copyItems(); if (recursive) { for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) { auto itemPtrRefs2 = trackPtr->_copyItems(); itemPtrRefs.insert(itemPtrRefs.end(), itemPtrRefs2.begin(), itemPtrRefs2.end()); } } itemPtrRefs.erase(std::remove_if(itemPtrRefs.begin(), itemPtrRefs.end(), [this, start, end, strict, complete](const ItemPtr &itemPtr) { return !isItemBetween(*itemPtr, start, end, strict, complete); }), itemPtrRefs.end()); if (sorted) { sort(itemPtrRefs); } return transformItemPtrsToIds(itemPtrRefs); } const QVector Track::itemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const { if (sorted) { auto itemPtrRefs = _items(recursive); itemPtrRefs.erase(std::remove_if(itemPtrRefs.begin(), itemPtrRefs.end(), [this, start, end, strict, complete, minimumDuration](const ItemPtr &itemPtr) { return !isItemBetween(*itemPtr, start, end, strict, complete, minimumDuration); }), itemPtrRefs.end()); sort(itemPtrRefs); return transformItemPtrsToIds(itemPtrRefs); } QVector itemIds; itemIds.reserve(m_items.size()); for (const ItemPtr &itemPtr : qAsConst(m_items)) { const Item &item = *itemPtr; if (isItemBetween(item, start, end, strict, complete, minimumDuration)) itemIds += item.id(); } if (!recursive) { itemIds.squeeze(); return itemIds; } for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) itemIds += trackPtr->itemIdsBetween(start, end, strict, complete, true, minimumDuration); return itemIds; } bool Track::isItemsBetween(qint64 start, qint64 end, const QVector &ignoreIds, bool strict, bool complete, bool recursive, qint64 minimumDuration) const { for (const ItemPtr &itemPtr : qAsConst(m_items)) { const Item &i = *itemPtr; if (!ignoreIds.contains(i.id())) if (isItemBetween(i, start, end, strict, complete, minimumDuration)) return true; } for (const int itemId : qAsConst(m_copyItemIds)) { const Item &i = item(itemId); if (!ignoreIds.contains(i.id())) if (isItemBetween(i, start, end, strict, complete, minimumDuration)) return true; } if (!recursive) return false; for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) if (trackPtr->isItemsBetween(start, end, ignoreIds, strict, complete, true, minimumDuration)) return true; return false; } bool Track::isItemsBetween(qint64 start, qint64 end, int ignoreId, bool strict, bool complete, bool recursive, qint64 minimumDuration) const { return isItemsBetween(start, end, QVector({ ignoreId }), strict, complete, recursive, minimumDuration); } ItemPtrRefs Track::_items(bool recursive) const { ItemPtrRefs x(m_items.cbegin(), m_items.cend()); if (!m_copyItemIds.isEmpty()) x.reserve(x.size() + m_copyItemIds.count()); for (const int itemId : qAsConst(m_copyItemIds)) { try { x.push_back(std::cref(_item(itemId))); } catch (const QString &msg) { fprintf(stderr, "cannot add item ptr ref from copy item with copy item id %d: %s\n", itemId, msg.toStdString().c_str()); } } if (!recursive) return x; for (const TrackPtr &t : qAsConst(m_childrenTracks)) { const ItemPtrRefs x2(t->_items(true)); x.insert(x.end(), x2.begin(), x2.end()); } return x; } ItemPtrRefs Track::_copyItems() const { ItemPtrRefs x; for (int id : qAsConst(m_copyItemIds)) { try { x.push_back(_item(id)); } catch(...) { fprintf(stderr, "Track::_copyItems: cannot find item for item id %d\n", id); continue; } } return x; } ItemPtrNCVRefs Track::_itemsNCV(bool recursive) { ItemPtrNCVRefs x(m_items.begin(), m_items.end()); if (!recursive) return x; for (TrackPtr &t : m_childrenTracks) { ItemPtrNCVRefs x2(t->_itemsNCV(true)); x.insert(x.end(), x2.begin(), x2.end()); } return x; } const QVector Track::_itemIds(bool recursive) const { QVector itemIds(transformItemPtrsToIds(m_items)); if (!recursive) return itemIds; for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) itemIds += trackPtr->_itemIds(true); return itemIds; } ItemPtrRef Track::_item(int id) const noexcept(false) { auto const it = std::find_if(m_items.cbegin(), m_items.cend(), [id](const ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.cend()) return *it; for (const TrackPtr &track : qAsConst(m_childrenTracks)) { try { return track->_item(id); } catch(...) { } } throw QStringLiteral("_item: item with id %1 not found!").arg(id); } void Track::printTrackIds(bool withItems, int level) const { fprintf(stderr, "%*c Track %16.16s ", level * 2, '>', text().toStdString().c_str()); if (withItems) { fprintf(stderr, " ( "); for (const ItemPtr &itemPtr : qAsConst(m_items)) { fprintf(stderr, "%d ", itemPtr->id()); } fprintf(stderr, ")"); } fprintf(stderr, "\n"); for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) trackPtr->printTrackIds(level + 1); } QVector Track::itemIds(bool recursive, bool sorted) const { if (sorted) { if (!recursive) return transformItemPtrsToIds(m_items); ItemPtrRefs is(_items(true)); sort(is); return transformItemPtrsToIds(is); } QVector itemIds; itemIds.reserve(m_items.size()); itemIds += transformItemPtrsToIds(m_items); if (!recursive) return itemIds; for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) itemIds += trackPtr->_itemIds(true); return itemIds; } void Track::addItemPtr(ItemPtr &&itemPtr) { m_items.insert(std::upper_bound(m_items.begin(), m_items.end(), itemPtr->startTime(), [](qint64 startTime, const ItemPtr &other) { return (other->startTime() > startTime); }), std::move(itemPtr)); } void Track::removeItem(int itemId) noexcept(false) { auto it = std::find_if(m_items.begin(), m_items.end(), [itemId](const ItemPtr &itemPtr) { return (itemPtr->id() == itemId); }); if (it == m_items.end()) throw QStringLiteral("removeItem: item %1 not found").arg(itemId); m_items.erase(it); } void Track::removeTrack(int trackId) noexcept(false) { auto it = std::find_if(m_childrenTracks.begin(), m_childrenTracks.end(), [trackId](const TrackPtr &trackPtr) { return (trackPtr->id() == trackId); }); if (it == m_childrenTracks.end()) throw QStringLiteral("removeTrack: track %1 not found on track %2").arg(trackId, id()); m_childrenTracks.erase(it); } ItemPtr Track::takeItem(int itemId) noexcept(false) { auto it = std::find_if(m_items.begin(), m_items.end(), [itemId](const ItemPtr &itemPtr) { return (itemPtr->id() == itemId); }); if (it == m_items.end()) throw QStringLiteral("Track::takeItem: item with id %1 not found").arg(itemId); ItemPtr ptr = std::move(*it); m_items.erase(it); return ptr; } Track &Track::track(int id) noexcept(false) { auto it = std::find_if(m_childrenTracks.begin(), m_childrenTracks.end(), [id](TrackPtr &trackPtr) { return (trackPtr.get()->id() == id); }); if (it != m_childrenTracks.end()) { Track &t = **it; return t; } for (TrackPtr &track : m_childrenTracks) { try { return track->track(id); } catch(...) { } } throw QStringLiteral("Track: track with id %1 not found").arg(id); } ItemPtrNCVRef Track::_itemNCV(int id) noexcept(false) { auto const it = std::find_if(m_items.begin(), m_items.end(), [id](ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.end()) return *it; for (TrackPtr &track : m_childrenTracks) { try { return track->_itemNCV(id); } catch(...) { } } throw QStringLiteral("lookup failed!");; } Item &Track::item(int id) noexcept(false) { auto const it = std::find_if(m_items.begin(), m_items.end(), [id](ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.end()) return **it; for (TrackPtr &track : m_childrenTracks) { try { return track->item(id); } catch(...) { } } throw QStringLiteral("lookup failed!");; } const Item &Track::item(int id) const noexcept(false) { auto const it = std::find_if(m_items.cbegin(), m_items.cend(), [id](const ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.cend()) return **it; for (const TrackPtr &track : qAsConst(m_childrenTracks)) { try { return track->item(id); } catch(...) { } } throw QStringLiteral("lookup failed!");; } Item &Track::previous(int id) noexcept(false) { auto it = std::find_if(m_items.begin(), m_items.end(), [id](ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.end() && (*it) != m_items.front()) return **(--it); throw QStringLiteral("Track::previous: previous item for id %1 not found").arg(id); } Item &Track::next(int id) noexcept(false) { auto it = std::find_if(m_items.begin(), m_items.end(), [id](ItemPtr &itemPtr) { return (itemPtr.get()->id() == id); }); if (it != m_items.end() && (*it) != m_items.back()) return **(++it); throw QStringLiteral("lookup failed!");; } int Track::rowOfTrack(int id) const noexcept(false) { int row = 0; for (const TrackPtr &trackPtr : qAsConst(m_childrenTracks)) { if (trackPtr->id() == id) return row; row++; } throw("not found"); } Track &Track::trackAt(int index) noexcept(false) { return *m_childrenTracks.at(index); } const Track &Track::trackAt(int index) const noexcept(false) { return *m_childrenTracks.at(index); } const Item &Track::copyItemAt(qint64 time) const noexcept(false) { auto const itemPtrRefs = _copyItems(); const ItemPtrRefs::const_iterator it = std::find_if(itemPtrRefs.cbegin(), itemPtrRefs.cend(), [time](const ItemPtr &itemPtr) { return itemPtr.get()->startTime() <= time && time <= itemPtr.get()->startTime() + itemPtr.get()->duration(); }); if (it != itemPtrRefs.cend()) return *it->get(); throw QStringLiteral("Track: can't find copy item at %1").arg(time); } Item &Track::itemAt(qint64 time) noexcept(false) { auto it = std::find_if(m_items.cbegin(), m_items.cend(), [time](const ItemPtr &itemPtr) { return itemPtr.get()->startTime() <= time && time <= itemPtr.get()->startTime() + itemPtr.get()->duration(); }); if (it != m_items.cend()) return **it; throw QStringLiteral("lookup failed!");; } const Item &Track::itemAt(qint64 time) const noexcept(false) { auto const it = std::find_if(m_items.cbegin(), m_items.cend(), [time](const ItemPtr &itemPtr) { return itemPtr.get()->startTime() <= time && time <= itemPtr.get()->startTime() + itemPtr.get()->duration(); }); if (it != m_items.cend()) return **it; throw QStringLiteral("lookup failed!");; } }