658 lines
18 KiB
C++
658 lines
18 KiB
C++
|
|
|
|
#include "track.h"
|
|
|
|
#include <utility>
|
|
|
|
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 : std::as_const(m_childrenTracks))
|
|
{
|
|
try
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // self-recursive lookup: recurses via the deprecated public Track API
|
|
return track->track(id);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
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 : std::as_const(m_childrenTracks))
|
|
{
|
|
if (trackPtr->hasTrack(id, true))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Track::addCopyItemIds(const QSet<int>& 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 : std::as_const(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<int> Track::copyItemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool recursive,
|
|
bool sorted, qint64 minimumDuration) const
|
|
{
|
|
Q_UNUSED(minimumDuration);
|
|
auto itemPtrRefs = _copyItems();
|
|
|
|
if (recursive)
|
|
{
|
|
for (const TrackPtr& trackPtr : std::as_const(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);
|
|
}
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
return transformItemPtrsToIds(itemPtrRefs);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
|
|
const QVector<int> 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);
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
return transformItemPtrsToIds(itemPtrRefs);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
|
|
QVector<int> itemIds;
|
|
itemIds.reserve(m_items.size());
|
|
|
|
for (const ItemPtr& itemPtr : std::as_const(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 : std::as_const(m_childrenTracks))
|
|
itemIds += trackPtr->itemIdsBetween(start, end, strict, complete, true, minimumDuration);
|
|
|
|
return itemIds;
|
|
}
|
|
|
|
bool Track::isItemsBetween(qint64 start, qint64 end, const QVector<int>& ignoreIds, bool strict, bool complete,
|
|
bool recursive, qint64 minimumDuration) const
|
|
{
|
|
for (const ItemPtr& itemPtr : std::as_const(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 : std::as_const(m_copyItemIds))
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal lookup via the deprecated Track::item
|
|
const Item& i = item(itemId);
|
|
#pragma GCC diagnostic pop
|
|
if (!ignoreIds.contains(i.id()))
|
|
if (isItemBetween(i, start, end, strict, complete, minimumDuration))
|
|
return true;
|
|
}
|
|
|
|
if (!recursive)
|
|
return false;
|
|
|
|
for (const TrackPtr& trackPtr : std::as_const(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<int>({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 : std::as_const(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 : std::as_const(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 : std::as_const(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<int> Track::_itemIds(bool recursive) const
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
QVector<int> itemIds(transformItemPtrsToIds(m_items));
|
|
#pragma GCC diagnostic pop
|
|
|
|
if (!recursive)
|
|
return itemIds;
|
|
|
|
for (const TrackPtr& trackPtr : std::as_const(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 : std::as_const(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 : std::as_const(m_items))
|
|
{
|
|
fprintf(stderr, "%d ", itemPtr->id());
|
|
}
|
|
fprintf(stderr, ")");
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
for (const TrackPtr& trackPtr : std::as_const(m_childrenTracks))
|
|
trackPtr->printTrackIds(level + 1);
|
|
}
|
|
|
|
QVector<int> Track::itemIds(bool recursive, bool sorted) const
|
|
{
|
|
if (sorted)
|
|
{
|
|
if (!recursive)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
return transformItemPtrsToIds(m_items);
|
|
#pragma GCC diagnostic pop
|
|
|
|
ItemPtrRefs is(_items(true));
|
|
|
|
sort(is);
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
return transformItemPtrsToIds(is);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
|
|
QVector<int> itemIds;
|
|
itemIds.reserve(m_items.size());
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // internal call to the deprecated transformItemPtrsToIds helper
|
|
itemIds += transformItemPtrsToIds(m_items);
|
|
#pragma GCC diagnostic pop
|
|
|
|
if (!recursive)
|
|
return itemIds;
|
|
|
|
for (const TrackPtr& trackPtr : std::as_const(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
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // self-recursive lookup: recurses via the deprecated public Track API
|
|
return track->track(id);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
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
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // self-recursive lookup: recurses via the deprecated public Track API
|
|
return track->item(id);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
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 : std::as_const(m_childrenTracks))
|
|
{
|
|
try
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // self-recursive lookup: recurses via the deprecated public Track API
|
|
return track->item(id);
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
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 : std::as_const(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!");
|
|
;
|
|
}
|
|
|
|
} // namespace LtsTimeline
|