#pragma once #include "item.h" #include "track.h" #include #include #include #include namespace LtsTimeline { class TimelineView; class LTSTIMELINE_EXPORT TimelineModel : public QAbstractItemModel { Q_OBJECT friend class TimelineViewSelectHandler; public: explicit TimelineModel(TimelineView *view, QObject *parent = nullptr); virtual ~TimelineModel() = default; void clear(); Track &rootTrack() { return m_rootTrack; } Track &track(int id) noexcept(false); const Track &track(int id) const noexcept(false); const Item &item(int id) const noexcept(false); Item &item(int id) noexcept(false); const QVector itemIds() const; const QVector itemIdsBetween(qint64 start, qint64 end, bool strict = false, bool complete = false, bool recursive = false, bool sorted = false) const; const QVector copyItemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool sorted) const; bool isItemsBetween(qint64 start, qint64 end, const QVector &ignoreIds = {}, bool strict = false, bool complete = false, bool recursive = false) const; bool isItemsBetween(qint64 start, qint64 end, int ignoreId = -1 , bool strict = false, bool complete = false, bool recursive = false) const; const Track &parentOfTrackId(int id) const noexcept(false); virtual void setItemStartTime(Track &t, Item &i, qint64 newStart); virtual void setItemStartTime(Item &i, qint64 newStart) noexcept(false); virtual void setItemStartTime(int itemId, qint64 newStart) noexcept(false); virtual void setItemDuration(Track &t, Item &i, int duration); virtual void setItemDuration(Item &i, int duration) noexcept(false); virtual void setItemDuration(int itemId, int duration) noexcept(false); void print(bool withItems = false) const { m_rootTrack.printTrackIds(withItems); } template ::value, TrackClass>::type> int addTrack(int parentTrackId, TrackClass &&newTrack ) noexcept(false) { int id = nextFreeTrackId(); TrackClass _track(std::move(newTrack)); _track.m_id = id; _track.m_parentId = parentTrackId; auto *ptr = track(parentTrackId).addTrack(std::move(_track)); m_trackCache.insert(std::pair(id, ptr)); return id; } template ::value, ItemClass>::type> int addItem(int parentTrackId, ItemClass &&item) noexcept(false) { int id = nextFreeItemId(); ItemClass _item(std::move(item)); _item.m_id = id; _item.m_parentTrackId = parentTrackId; if (m_isSnapEnabled) { _item.m_startTime = _item.m_startTime - (_item.m_startTime % 1000); _item.m_duration = _item.m_duration - (_item.m_duration % 1000); } Item *ptr = track(parentTrackId).addItem(std::move(_item)); m_itemCache.insert(std::pair(id, ptr)); QModelIndex idx = indexOfTrack(parentTrackId); emit dataChanged(idx, idx); return id; } bool isEditable() const { return m_isEditable; } void setEditable(bool editable) { m_isEditable = editable; } bool isSnapEnabled() const { return m_isSnapEnabled; } void setSnapEnabled(bool enabled) { m_isSnapEnabled = enabled; } int snapStep() const { return m_snapStep; } void setSnapStep(int step) { m_snapStep = step; } int snapTolerance() const { return m_snapTol; } void setSnapTolerance(int tolerance) { m_snapTol = tolerance; } qint64 snapTime(qint64 time) const { return m_isSnapEnabled ? time / m_snapStep * m_snapStep : time; } int minimumDuration() const { return m_minItemDuration; } void setMinimumDuration(int duration); QModelIndex indexOfTrack(int trackId) const; QModelIndex indexOfTrackSafe(int trackId) const noexcept(false); virtual void moveItemToTrack(int itemId, int trackId, qint64 time) noexcept(false); virtual void removeItem(int itemId) noexcept(false); virtual void removeTrack(int trackId) noexcept(false); virtual bool canDropItem(const Item &item, int trackId, qint64 start) const; virtual bool canMoveItem(const Item &item, qint64 start) const; virtual bool canResizeItem(const Item &item, qint64 start, int duration) const; virtual bool isItemDragged(int _itemId) const; virtual void copyToClipboard(const QVector &ids) noexcept(false); virtual void cutToClipboard(const QVector &ids) noexcept(false); virtual void pasteFromClipboard(qint64 time) noexcept(false); bool isClipboardEmpty() const { return m_clipboard.empty(); } int rowCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QModelIndex parent(const QModelIndex &index) const override; int columnCount(const QModelIndex &) const override { return 2; } protected: ItemPtrNCVRef _itemNCV(Track &track, int id) noexcept(false) { return track._itemNCV(id); } ItemPtrNCVRef _itemNCV(const TrackPtr &trackPtr, int id) noexcept(false) { return trackPtr->_itemNCV(id); } const ItemPtrRefs _items(const TrackPtr &trackPtr, bool recursive) const { return trackPtr->_items(recursive); } ItemPtrNCVRefs _itemsNCV(const TrackPtr &trackPtr, bool recursive) { return trackPtr->_itemsNCV(recursive); } int addItem(int parentTrackId, ItemPtr &&itemPtr, bool forceTheCompilerToUseMe = false) noexcept(false) { (void)forceTheCompilerToUseMe; int id = nextFreeItemId(); ItemPtr _itemPtr(std::move(itemPtr)); _itemPtr->m_id = id; _itemPtr->m_parentTrackId = parentTrackId; if (m_isSnapEnabled) { _itemPtr->m_startTime = _itemPtr->m_startTime - (_itemPtr->m_startTime % 1000); _itemPtr->m_duration = _itemPtr->m_duration - (_itemPtr->m_duration % 1000); } Item *ptr = track(parentTrackId).addItem(std::move(_itemPtr)); m_itemCache.insert(std::pair(id, ptr)); QModelIndex idx = indexOfTrack(parentTrackId); emit dataChanged(idx, idx); return id; } void clearItems(); int rowOfTrackId(int id) const noexcept(false); const Track &trackOfIndex(const QModelIndex &index) const; int indexOf(int id) const; const QVector _itemIdsBetween(Track &t, qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const; const QVector _copyItemIdsBetween(Track &t, qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const; bool _isItemsBetween(const Track &t, qint64 start, qint64 end, const QVector &ignoreIds, bool strict, bool complete, bool recursive, qint64 minimumDuration) const; bool _isItemsBetween(const Track &t, qint64 start, qint64 end, int ignoreId, bool strict, bool complete, bool recursive, qint64 minimumDuration) const; private: int nextFreeTrackId() { return m_currentTrackId++; } int nextFreeItemId() { return m_currentItemId++; } QModelIndex indexOfTrackFromIndex(const QModelIndex &idx, int trackId) const; QModelIndex indexOfTrackFromIndexSafe(const QModelIndex &idx, int trackId) const noexcept(false); public slots: virtual void onInsertTrack(const QModelIndex &index) { Q_UNUSED(index); } virtual void onRemoveTrack(const QModelIndex &index) { Q_UNUSED(index); } protected: TimelineView *m_view{nullptr}; Track m_rootTrack; int m_currentTrackId{0}; int m_currentItemId{0}; bool m_isEditable{true}; bool m_isSnapEnabled{false}; int m_snapStep{500}; int m_snapTol{1000}; int m_minItemDuration{0}; bool m_itemCaching{true}; bool m_trackCaching{true}; std::map m_trackCache; std::map m_itemCache; Items m_clipboard; NGL::INGLLogger &m_logger; }; }