264 lines
7.2 KiB
C++
Executable File
264 lines
7.2 KiB
C++
Executable File
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "item.h"
|
|
|
|
#include <LtsTimeline/ltstimeline_export.h>
|
|
|
|
#include <QObject>
|
|
#include <QSet>
|
|
#include <QVariant>
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
namespace LtsTimeline
|
|
{
|
|
class Track;
|
|
|
|
class TimelineModel;
|
|
|
|
typedef std::unique_ptr<Track> TrackPtr;
|
|
typedef std::vector<TrackPtr> Tracks;
|
|
typedef std::reference_wrapper<TrackPtr> TrackPtrRef;
|
|
typedef std::vector<TrackPtrRef> TrackPtrRefs;
|
|
|
|
|
|
class LTSTIMELINE_EXPORT Track
|
|
{
|
|
public:
|
|
Track(const QString &text = {})
|
|
: m_text(text)
|
|
{}
|
|
|
|
Track(const QString &text, int specialTrackType)
|
|
: m_text(text)
|
|
, m_userData(specialTrackType)
|
|
{}
|
|
|
|
Track(const Track &) = delete;
|
|
Track &operator=(const Track &) = delete;
|
|
Track(Track &&t) noexcept = default;
|
|
virtual ~Track() = default;
|
|
|
|
[[deprecated("Use model's track(int) instead.")]] const Track &track(int id) const noexcept(false);
|
|
[[deprecated("Use model's track(int) instead.")]] Track &track(int id) noexcept(false);
|
|
[[deprecated("Use model's item(int) instead.")]] Item &item(int id) noexcept(false);
|
|
[[deprecated("Use model's item(int) instead.")]] const Item &item(int id) const noexcept(false);
|
|
Item &previous(int id) noexcept(false);
|
|
Item &next(int id) noexcept(false);
|
|
|
|
const Item ©ItemAt(qint64 time) const noexcept(false);
|
|
Item &itemAt(qint64 time) noexcept(false);
|
|
const Item &itemAt(qint64 time) const noexcept(false);
|
|
Track &trackAt(int index) noexcept(false);
|
|
const Track &trackAt(int index) const noexcept(false);
|
|
bool hasTrack(int id, bool recursive = false) const;
|
|
bool hasTracks() const { return !m_childrenTracks.empty(); }
|
|
int rowOfTrack(int id) const noexcept(false);
|
|
const Track &parentOf(int id) const noexcept(false);
|
|
|
|
|
|
const QSet<int> ©ItemIds() const { return m_copyItemIds; }
|
|
void clearCopyItemIds() { m_copyItemIds.clear(); }
|
|
void addCopyItemIds(const QSet<int> &ids);
|
|
void addCopyItemId(int id);
|
|
bool hasItems() const { return !m_items.empty(); }
|
|
bool hasCopyItems() const { return !m_copyItemIds.empty(); }
|
|
int itemCount() const { return m_items.size(); }
|
|
Items &items() { return m_items; }
|
|
const Items &items() const { return m_items; }
|
|
int trackCount() const { return m_childrenTracks.size(); }
|
|
Tracks &tracks() { return m_childrenTracks; }
|
|
const Tracks &tracks() const { return m_childrenTracks; }
|
|
QVector<int> itemIds(bool recursive = false, bool sorted = false) const;
|
|
const QVector<int> itemIdsBetween(qint64 start, qint64 end, bool strict = false, bool complete = false, bool recursive = false, bool sorted = false, qint64 minimumDuration = 0) const;
|
|
[[deprecated]] const QVector<int> copyItemIdsBetween(qint64 start, qint64 end, bool strict = false, bool complete = false, bool recursive = false, bool sorted = false, qint64 minimumDuration = 0) const;
|
|
bool isItemsBetween(qint64 start, qint64 end, const QVector<int> &ignoreIds, bool strict = false, bool complete = false, bool recursive = false, qint64 minimumDuration = 0) const;
|
|
bool isItemsBetween(qint64 start, qint64 end, int ignoreId, bool strict = false, bool complete = false, bool recursive = false, qint64 minimumDuration = 0) const;
|
|
|
|
|
|
int id() const { return m_id; }
|
|
virtual const QString text() const { return m_text; }
|
|
int parent() const { return m_parentId; }
|
|
int parentId() const { return m_parentId; }
|
|
void printTrackIds(bool withItems = false, int level = 0) const;
|
|
void removeCopyItem(int itemId) noexcept(false);
|
|
void removeItem(int itemId) noexcept(false);
|
|
ItemPtr takeItem(int itemId) noexcept(false);
|
|
QVariant userData() const { return m_userData; }
|
|
void setUserData(const QVariant &data) { m_userData = data; }
|
|
|
|
|
|
inline static void sort(Items &items)
|
|
{
|
|
std::sort(items.begin(), items.end(), [](const ItemPtr &itemA, const ItemPtr &itemB)
|
|
{
|
|
return itemA->startTime() < itemB->startTime();
|
|
});
|
|
}
|
|
|
|
|
|
inline static void sort(ItemPtrNCVRefs &items)
|
|
{
|
|
std::sort(items.begin(), items.end(), [](const ItemPtrNCVRef &itemA, const ItemPtrNCVRef &itemB)
|
|
{
|
|
return itemA.get()->startTime() < itemB.get()->startTime();
|
|
});
|
|
}
|
|
|
|
|
|
inline static void sort(ItemPtrRefs &items)
|
|
{
|
|
std::sort(items.begin(), items.end(), [](const ItemPtrRef &itemA, const ItemPtrRef &itemB)
|
|
{
|
|
return itemA.get()->startTime() < itemB.get()->startTime();
|
|
});
|
|
}
|
|
|
|
bool hasInsertButton() const { return m_hasInsertButton; }
|
|
void setInsertButton(bool hasButton) { m_hasInsertButton = hasButton; }
|
|
bool hasRemoveButton() const { return m_hasRemoveButton; }
|
|
void setRemoveButton(bool hasButton) { m_hasRemoveButton = hasButton; }
|
|
|
|
|
|
protected:
|
|
QString m_text;
|
|
QVariant m_userData;
|
|
|
|
|
|
private:
|
|
void removeTrack(int trackId) noexcept(false);
|
|
void addItemPtr(ItemPtr &&itemPtr);
|
|
|
|
static bool isItemBetween(const Item &item, qint64 start, qint64 end, bool strict, bool complete, qint64 minimumDuration = 0);
|
|
ItemPtrRefs _copyItems() const;
|
|
ItemPtrRefs _items(bool recursive) const;
|
|
ItemPtrNCVRefs _itemsNCV(bool recursive);
|
|
ItemPtrNCVRef _itemNCV(int id) noexcept(false);
|
|
ItemPtrRef _item(int id) const noexcept(false);
|
|
const QVector<int> _itemIds(bool recursive) const;
|
|
|
|
|
|
public:
|
|
void clearItems() { m_items.clear(); }
|
|
private:
|
|
|
|
friend class TimelineModel;
|
|
|
|
|
|
void sort()
|
|
{
|
|
sort(m_items);
|
|
}
|
|
|
|
|
|
template <typename TrackClass>
|
|
Track *addTrack(TrackClass &&trackClass)
|
|
{
|
|
TrackClass _trackClass = std::move(trackClass);
|
|
m_childrenTracks.push_back(std::move(std::move(std::make_unique<TrackClass>(std::move(_trackClass)))));
|
|
return m_childrenTracks.back().get();
|
|
}
|
|
|
|
|
|
template <typename TrackClass>
|
|
[[deprecated("Use model's track(...) and call addTrack(TrackClass) directly on that track.")]]
|
|
Track *addTrack(int parentTrackId, TrackClass &&trackClass) noexcept(false)
|
|
{
|
|
if (m_id == parentTrackId)
|
|
return addTrack<TrackClass>(std::move(trackClass));
|
|
|
|
return track(parentTrackId).addTrack(std::move(trackClass));
|
|
}
|
|
|
|
|
|
template <typename ItemClass>
|
|
Item *addItem(ItemClass &&itemClass)
|
|
{
|
|
ItemClass _itemClass(std::move(itemClass));
|
|
|
|
auto it = m_items.insert(std::upper_bound(m_items.begin(), m_items.end(), _itemClass.startTime(),
|
|
[](qint64 startTime, const ItemPtr &other)
|
|
{
|
|
return (other->startTime() > startTime);
|
|
}), std::move(std::make_unique<ItemClass>(std::move(_itemClass))));
|
|
|
|
return it->get();
|
|
}
|
|
|
|
|
|
Item *addItem(ItemPtr &&itemPtr)
|
|
{
|
|
auto it = 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));
|
|
|
|
return it->get();
|
|
}
|
|
|
|
|
|
template <typename ItemContainer>
|
|
[[deprecated]]
|
|
QVector<int> transformItemPtrsToIds(const ItemContainer &itemContainer) const
|
|
{
|
|
QVector<int> ids;
|
|
std::transform(itemContainer.cbegin(), itemContainer.cend(), std::back_inserter(ids),
|
|
[](const ItemPtr &itemPtr) -> int
|
|
{
|
|
return itemPtr->id();
|
|
});
|
|
return ids;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int m_id { -1 };
|
|
Tracks m_childrenTracks;
|
|
Items m_items;
|
|
int m_parentId { -1 };
|
|
bool m_hasInsertButton { false };
|
|
bool m_hasRemoveButton { false };
|
|
|
|
|
|
QSet<int> m_copyItemIds;
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|