762 lines
16 KiB
C++
Executable File
762 lines
16 KiB
C++
Executable File
|
|
|
|
|
|
#include "timeline_model.h"
|
|
#include "timeline_view_drag_handler.h"
|
|
#include "track.h"
|
|
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
namespace LtsTimeline
|
|
{
|
|
|
|
TimelineModel::TimelineModel(TimelineView *view, QObject *parent)
|
|
: QAbstractItemModel(parent)
|
|
, m_view(view)
|
|
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Timeline.TimelineModel"))
|
|
{
|
|
m_rootTrack.m_id = nextFreeTrackId();
|
|
m_trackCache.insert(std::pair<int, Track *>(m_rootTrack.m_id, &m_rootTrack));
|
|
}
|
|
|
|
|
|
void TimelineModel::clear()
|
|
{
|
|
m_rootTrack.m_childrenTracks.clear();
|
|
m_rootTrack.m_items.clear();
|
|
|
|
|
|
m_rootTrack.m_copyItemIds.clear();
|
|
m_trackCache.clear();
|
|
|
|
m_itemCache.clear();
|
|
|
|
m_currentTrackId = 1;
|
|
m_currentItemId = 0;
|
|
m_trackCache.insert(std::pair<int, Track *>(m_rootTrack.m_id, &m_rootTrack));
|
|
}
|
|
|
|
|
|
void TimelineModel::clearItems()
|
|
{
|
|
for (std::pair<int , Track *> p : m_trackCache)
|
|
p.second->clearItems();
|
|
|
|
m_itemCache.clear();
|
|
m_currentItemId = 0;
|
|
}
|
|
|
|
|
|
Track &TimelineModel::track(int id) noexcept(false)
|
|
{
|
|
if (!m_trackCaching)
|
|
{
|
|
if (id == m_rootTrack.id())
|
|
return m_rootTrack;
|
|
return m_rootTrack.track(id);
|
|
}
|
|
|
|
auto it = m_trackCache.find(id);
|
|
|
|
if (it == m_trackCache.end())
|
|
throw QStringLiteral("Model: track with id %1 not found in cache").arg(id);
|
|
|
|
return *it->second;
|
|
}
|
|
|
|
|
|
const Track &TimelineModel::track(int id) const noexcept(false)
|
|
{
|
|
if (!m_trackCaching)
|
|
{
|
|
if (id == m_rootTrack.id())
|
|
return m_rootTrack;
|
|
return m_rootTrack.track(id);
|
|
}
|
|
|
|
std::map<int , Track *>::const_iterator it = m_trackCache.find(id);
|
|
|
|
if (it == m_trackCache.cend())
|
|
throw QStringLiteral("Model: const track with id %1 not found in cache").arg(id);
|
|
|
|
return *it->second;
|
|
}
|
|
|
|
|
|
Item &TimelineModel::item(int id) noexcept(false)
|
|
{
|
|
if (!m_itemCaching)
|
|
return m_rootTrack.item(id);
|
|
|
|
auto it = m_itemCache.find(id);
|
|
|
|
if (it == m_itemCache.end())
|
|
throw QStringLiteral("Model: item with id %1 not found in cache").arg(id);
|
|
|
|
return *it->second;
|
|
}
|
|
|
|
|
|
const Item &TimelineModel::item(int id) const noexcept(false)
|
|
{
|
|
if (!m_itemCaching)
|
|
return m_rootTrack.item(id);
|
|
|
|
decltype(m_itemCache)::const_iterator it = m_itemCache.find(id);
|
|
|
|
if (it == m_itemCache.cend())
|
|
throw QStringLiteral("Model: const item with id %1 not found in cache").arg(id);
|
|
|
|
return *it->second;
|
|
}
|
|
|
|
|
|
const QVector<int> TimelineModel::itemIds() const
|
|
{
|
|
if (!m_itemCaching)
|
|
return m_rootTrack.itemIds(true);
|
|
|
|
QVector<int> ids;
|
|
std::transform(m_itemCache.cbegin(), m_itemCache.cend(), std::back_inserter(ids),
|
|
[](const std::pair<int, Item *> &pair)
|
|
{
|
|
return pair.first;
|
|
});
|
|
|
|
return ids;
|
|
}
|
|
|
|
|
|
|
|
const QVector<int> TimelineModel::itemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted) const
|
|
{
|
|
return m_rootTrack.itemIdsBetween(start, end, strict, complete, recursive, sorted);
|
|
}
|
|
|
|
bool TimelineModel::isItemsBetween(qint64 start, qint64 end, const QVector<int> &ignoreIds, bool strict, bool complete, bool recursive) const
|
|
{
|
|
return m_rootTrack.isItemsBetween(start, end, ignoreIds, strict, complete, recursive);
|
|
}
|
|
|
|
const QVector<int> TimelineModel::copyItemIdsBetween(qint64 start, qint64 end, bool strict, bool complete, bool sorted) const
|
|
{
|
|
return m_rootTrack.copyItemIdsBetween(start, end, strict, complete, true, sorted);
|
|
}
|
|
|
|
bool TimelineModel::isItemsBetween(qint64 start, qint64 end, int ignoreId, bool strict, bool complete, bool recursive) const
|
|
{
|
|
return m_rootTrack.isItemsBetween(start, end, ignoreId, strict, complete, recursive);
|
|
}
|
|
|
|
|
|
const QVector<int> TimelineModel::_copyItemIdsBetween(Track &t, qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const
|
|
{
|
|
QVector<int> itemIds;
|
|
itemIds.reserve(t.itemCount());
|
|
|
|
|
|
for (const int itemId : qAsConst(t.copyItemIds()))
|
|
{
|
|
const Item &i = item(itemId);
|
|
if (Track::isItemBetween(i, start, end, strict, complete, minimumDuration))
|
|
itemIds += i.id();
|
|
}
|
|
|
|
if (recursive)
|
|
for (const TrackPtr &trackPtr : qAsConst(t.tracks()))
|
|
itemIds += _copyItemIdsBetween(*trackPtr.get(), start, end, strict, complete, true, false, minimumDuration);
|
|
|
|
|
|
itemIds.erase(std::unique(itemIds.begin(), itemIds.end()), itemIds.end());
|
|
|
|
itemIds.squeeze();
|
|
|
|
if (!sorted)
|
|
return itemIds;
|
|
|
|
|
|
std::sort(itemIds.begin(), itemIds.end(), [this](const int itemIdA, const int itemIdB)
|
|
{
|
|
try
|
|
{
|
|
return item(itemIdA).startTime() < item(itemIdB).startTime();
|
|
}
|
|
catch (...) { return false; }
|
|
});
|
|
|
|
return itemIds;
|
|
}
|
|
|
|
|
|
const QVector<int> TimelineModel::_itemIdsBetween(Track &t, qint64 start, qint64 end, bool strict, bool complete, bool recursive, bool sorted, qint64 minimumDuration) const
|
|
{
|
|
QVector<int> itemIds;
|
|
itemIds.reserve(t.itemCount());
|
|
|
|
for (const ItemPtr &itemPtr : qAsConst(t.items()))
|
|
{
|
|
const Item &i = *itemPtr;
|
|
if (Track::isItemBetween(i, start, end, strict, complete, minimumDuration))
|
|
itemIds += i.id();
|
|
}
|
|
|
|
if (recursive)
|
|
for (const TrackPtr &trackPtr : qAsConst(t.tracks()))
|
|
itemIds += _itemIdsBetween(*trackPtr.get(), start, end, strict, complete, true, false, minimumDuration);
|
|
|
|
|
|
|
|
|
|
itemIds.squeeze();
|
|
|
|
if (!sorted)
|
|
return itemIds;
|
|
|
|
|
|
std::sort(itemIds.begin(), itemIds.end(), [this](const int itemIdA, const int itemIdB)
|
|
{
|
|
try
|
|
{
|
|
return item(itemIdA).startTime() < item(itemIdB).startTime();
|
|
}
|
|
catch (...) { return false; }
|
|
});
|
|
|
|
return itemIds;
|
|
}
|
|
|
|
|
|
bool TimelineModel::_isItemsBetween(const Track &t, qint64 start, qint64 end, const QVector<int> &ignoreIds, bool strict, bool complete, bool recursive, qint64 minimumDuration) const
|
|
{
|
|
for (const ItemPtr &itemPtr : qAsConst(t.items()))
|
|
{
|
|
const Item &i = *itemPtr;
|
|
if (!ignoreIds.contains(i.id()))
|
|
if (Track::isItemBetween(i, start, end, strict, complete, minimumDuration))
|
|
return true;
|
|
}
|
|
|
|
if (!recursive)
|
|
return false;
|
|
|
|
for (const TrackPtr &trackPtr : qAsConst(t.tracks()))
|
|
if (_isItemsBetween(*trackPtr.get(), start, end, ignoreIds, strict, complete, true, minimumDuration))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool TimelineModel::_isItemsBetween(const Track &t, qint64 start, qint64 end, int ignoreId, bool strict, bool complete, bool recursive, qint64 minimumDuration) const
|
|
{
|
|
return _isItemsBetween(t, start, end, QVector<int>({ ignoreId }), strict, complete, recursive, minimumDuration);
|
|
}
|
|
|
|
|
|
QVariant TimelineModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if ((role != Qt::DisplayRole && role != Qt::UserRole) || !index.isValid())
|
|
return {};
|
|
|
|
int trackId = index.internalId();
|
|
int column = index.column();
|
|
|
|
if (column == 1 && role == Qt::DisplayRole)
|
|
return trackId;
|
|
|
|
if (role == Qt::UserRole)
|
|
{
|
|
if (column == 0)
|
|
return trackId;
|
|
|
|
try
|
|
{
|
|
const Track &t = track(trackId);
|
|
return t.userData();
|
|
}
|
|
catch(...)
|
|
{
|
|
Q_ASSERT(false);
|
|
return {};
|
|
}
|
|
}
|
|
|
|
|
|
if (column != 0)
|
|
return {};
|
|
|
|
|
|
QString text;
|
|
|
|
try
|
|
{
|
|
const Track &t = track(trackId);
|
|
|
|
#if 0
|
|
text = QStringLiteral("[%1] %3").arg(t.id()).arg(t.text());
|
|
#else
|
|
text = t.text();
|
|
#endif
|
|
}
|
|
catch(...)
|
|
{
|
|
Q_ASSERT(false);
|
|
return QStringLiteral("[?????]");
|
|
}
|
|
|
|
if (text.isEmpty())
|
|
text = tr("[unknown]");
|
|
|
|
return text;
|
|
}
|
|
|
|
|
|
Qt::ItemFlags TimelineModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return {};
|
|
|
|
return QAbstractItemModel::flags(index);
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::index(int row, int column, const QModelIndex &parent) const
|
|
{
|
|
if (!hasIndex(row, column, parent))
|
|
return {};
|
|
|
|
int childTrackId;
|
|
try
|
|
{
|
|
const Track &parentTrack = parent.isValid() ? track(parent.internalId()) : m_rootTrack;
|
|
const Track &childTrack = parentTrack.trackAt(row);
|
|
childTrackId = childTrack.id();
|
|
}
|
|
catch (const QString &msg)
|
|
{
|
|
DEBUG_LOG(m_logger) << Q_FUNC_INFO << "cannot get parent track " << msg;
|
|
return {};
|
|
}
|
|
catch (const std::out_of_range &oor)
|
|
{
|
|
DEBUG_LOG(m_logger) << Q_FUNC_INFO << "cannot get child track " << QString::fromUtf8(oor.what());
|
|
return {};
|
|
}
|
|
|
|
return createIndex(row, column, childTrackId);
|
|
}
|
|
|
|
|
|
int TimelineModel::rowOfTrackId(int id) const noexcept(false)
|
|
{
|
|
const Track &parent = track(track(id).parentId());
|
|
|
|
if (parent.items().empty())
|
|
throw("parent doesn't have items");
|
|
|
|
int row = 0;
|
|
|
|
for (const TrackPtr &trackPtr : qAsConst(parent.tracks()))
|
|
{
|
|
if (trackPtr->id() == id)
|
|
return row;
|
|
row++;
|
|
}
|
|
|
|
throw("not found");
|
|
}
|
|
|
|
|
|
const Track &TimelineModel::trackOfIndex(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
throw QStringLiteral("trackOfIndex: index is invalid!");
|
|
|
|
|
|
try
|
|
{
|
|
return track(index.internalId());
|
|
}
|
|
catch (const QString &msg)
|
|
{
|
|
throw QStringLiteral("trackOfIndex: cannot find track by internal id %1: %2").arg(index.internalId()).arg(msg);
|
|
}
|
|
|
|
|
|
return m_rootTrack;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Track &TimelineModel::parentOfTrackId(int id) const noexcept(false)
|
|
{
|
|
if (!m_trackCaching)
|
|
{
|
|
if (m_rootTrack.hasTrack(id))
|
|
return m_rootTrack;
|
|
|
|
|
|
}
|
|
|
|
const Track &theTrack = track(id);
|
|
|
|
if (theTrack.parentId() == m_rootTrack.id())
|
|
return m_rootTrack;
|
|
|
|
return track(theTrack.parentId());
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::parent(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int trackId = index.internalId();
|
|
int parentId;
|
|
int superParentId;
|
|
try
|
|
{
|
|
const Track &parent = parentOfTrackId(trackId);
|
|
parentId = parent.id();
|
|
superParentId = parent.parentId();
|
|
}
|
|
catch (const QString &msg)
|
|
{
|
|
DEBUG_LOG(m_logger) << Q_FUNC_INFO << "cannot get parent of track with id" << trackId << msg;
|
|
return {};
|
|
}
|
|
|
|
if (parentId == m_rootTrack.id())
|
|
return {};
|
|
|
|
int parentsRow;
|
|
try
|
|
{
|
|
const Track &superParent = track(superParentId);
|
|
|
|
try
|
|
{
|
|
parentsRow = superParent.rowOfTrack(parentId);
|
|
}
|
|
catch (const QString &msg)
|
|
{
|
|
DEBUG_LOG(m_logger) << Q_FUNC_INFO << "row of track for parent not found for parent id" << parentId << "-" << msg;
|
|
return {};
|
|
}
|
|
}
|
|
catch (const QString &msg)
|
|
{
|
|
DEBUG_LOG(m_logger) << Q_FUNC_INFO << "super parent not found for super parent id" << superParentId << "-" << msg;
|
|
return {};
|
|
}
|
|
|
|
return createIndex(parentsRow, 0, parentId);
|
|
}
|
|
|
|
|
|
void TimelineModel::setItemStartTime(Track &t, Item &i, qint64 newStart)
|
|
{
|
|
i._setStartTime(newStart);
|
|
t.sort();
|
|
}
|
|
|
|
|
|
void TimelineModel::setItemStartTime(Item &i, qint64 newStart) noexcept(false)
|
|
{
|
|
setItemStartTime(track(i.parentTrackId()), i, newStart);
|
|
}
|
|
|
|
|
|
void TimelineModel::setItemStartTime(int itemId, qint64 newStart) noexcept(false)
|
|
{
|
|
setItemStartTime(item(itemId), newStart);
|
|
}
|
|
|
|
|
|
void TimelineModel::setItemDuration(Track &t, Item &i, int duration)
|
|
{
|
|
i._setDuration(std::max(duration, m_minItemDuration));
|
|
t.sort();
|
|
}
|
|
|
|
void TimelineModel::setItemDuration(Item &i, int duration) noexcept(false)
|
|
{
|
|
setItemDuration(track(i.parentTrackId()), i, duration);
|
|
}
|
|
|
|
void TimelineModel::setItemDuration(int itemId, int duration) noexcept(false)
|
|
{
|
|
setItemDuration(item(itemId), duration);
|
|
}
|
|
|
|
|
|
void TimelineModel::copyToClipboard(const QVector<int> &ids) noexcept(false)
|
|
{
|
|
m_clipboard.clear();
|
|
m_clipboard.reserve(ids.size());
|
|
qint64 tStartMin = LLONG_MAX;
|
|
for (int itemId : qAsConst(ids))
|
|
{
|
|
const Item &i = item(itemId);
|
|
ItemPtr iPtr = std::make_unique<Item>(Item(i.startTime(), i.duration(), i.color()));
|
|
iPtr->m_parentTrackId = i.m_parentTrackId;
|
|
m_clipboard.push_back(std::move(iPtr));
|
|
tStartMin = std::min(tStartMin, i.startTime());
|
|
}
|
|
for (ItemPtr &iPtr : m_clipboard)
|
|
iPtr->_setStartTime(iPtr->startTime() - tStartMin);
|
|
}
|
|
|
|
void TimelineModel::cutToClipboard(const QVector<int> &ids) noexcept(false)
|
|
{
|
|
copyToClipboard(ids);
|
|
for (int itemId : qAsConst(ids))
|
|
removeItem(itemId);
|
|
}
|
|
|
|
void TimelineModel::pasteFromClipboard(qint64 time) noexcept(false)
|
|
{
|
|
if (m_isSnapEnabled)
|
|
time -= (time % m_snapStep);
|
|
for (ItemPtr &iPtr : m_clipboard)
|
|
{
|
|
iPtr->_setStartTime(time + iPtr->startTime());
|
|
addItem(iPtr->parentTrackId(), std::move(iPtr));
|
|
}
|
|
m_clipboard.clear();
|
|
}
|
|
|
|
|
|
int TimelineModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
if (parent.column() > 0)
|
|
return 0;
|
|
|
|
if (!parent.isValid())
|
|
return m_rootTrack.tracks().size();
|
|
|
|
try
|
|
{
|
|
return track(parent.internalId()).tracks().size();
|
|
}
|
|
catch(...) {}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::indexOfTrack(int trackId) const
|
|
{
|
|
for (int row = 0; row < rowCount(); ++row)
|
|
{
|
|
QModelIndex idx = indexOfTrackFromIndex(index(row, 0, {}), trackId);
|
|
if (idx.isValid())
|
|
return idx;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::indexOfTrackFromIndex(const QModelIndex &idx, int trackId) const
|
|
{
|
|
if (static_cast<int>(idx.internalId()) == trackId)
|
|
return index(idx.row(), 1, idx.parent());
|
|
|
|
for (int row = 0; row < rowCount(idx); ++row)
|
|
{
|
|
const QModelIndex i = indexOfTrackFromIndex(index(row, 0, idx), trackId);
|
|
if (i.isValid())
|
|
return i;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::indexOfTrackSafe(int trackId) const noexcept(false)
|
|
{
|
|
for (int row = 0; row < rowCount(); ++row)
|
|
{
|
|
const QModelIndex idx(indexOfTrackFromIndex(index(row, 0 , {}), trackId));
|
|
if (idx.isValid())
|
|
return idx;
|
|
}
|
|
|
|
QString trackText;
|
|
try
|
|
{
|
|
trackText = track(trackId).text();
|
|
} catch(...){}
|
|
|
|
throw QStringLiteral("indexOfTrackSafe: index for trackId %1 ('%2') not found ").arg(trackId).arg(trackText.isEmpty() ? QStringLiteral("(unknown)") : trackText);
|
|
}
|
|
|
|
|
|
QModelIndex TimelineModel::indexOfTrackFromIndexSafe(const QModelIndex &idx, int trackId) const noexcept(false)
|
|
{
|
|
if (static_cast<int>(idx.internalId()) == trackId)
|
|
return idx;
|
|
|
|
for (int row = 0; row < rowCount(idx); ++row)
|
|
{
|
|
const QModelIndex i = indexOfTrackFromIndex(index(row, 1, idx), trackId);
|
|
if (i.isValid())
|
|
return i;
|
|
}
|
|
|
|
throw QStringLiteral("indexOfTrackFromIndexSafe: index for trackId %1 not found").arg(trackId);
|
|
}
|
|
|
|
|
|
void TimelineModel::moveItemToTrack(int itemId, int trackId, qint64 time) noexcept(false)
|
|
{
|
|
|
|
|
|
|
|
const Item &theItem = item(itemId);
|
|
Track &oldTrack = track(theItem.parentTrackId());
|
|
Track &newTrack = track(trackId);
|
|
|
|
ItemPtr itemPtr = oldTrack.takeItem(itemId);
|
|
|
|
Item *theItemPtr = newTrack.addItem(std::move(itemPtr));
|
|
setItemStartTime(newTrack, *theItemPtr, time);
|
|
theItemPtr->m_parentTrackId = trackId;
|
|
}
|
|
|
|
|
|
void TimelineModel::removeItem(int itemId) noexcept(false)
|
|
{
|
|
const Item &i = item(itemId);
|
|
Track &t = track(i.parentTrackId());
|
|
|
|
t.removeItem(itemId);
|
|
|
|
auto it = m_itemCache.find(itemId);
|
|
if (it == m_itemCache.end())
|
|
{
|
|
Q_ASSERT(false);
|
|
throw QStringLiteral("removeItem: item with id %1 not found").arg(itemId);
|
|
}
|
|
|
|
m_itemCache.erase(it);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
void TimelineModel::removeTrack(int trackId) noexcept(false)
|
|
{
|
|
if (trackId == m_rootTrack.id())
|
|
{
|
|
Q_ASSERT(false);
|
|
throw QStringLiteral("removeTrack: the root track shouldn't and *can't* be deleted");
|
|
}
|
|
|
|
|
|
const Track &t = track(trackId);
|
|
Track &parentTrack = track(t.parentId());
|
|
|
|
for (int itemId : t.itemIds(true))
|
|
{
|
|
auto it = m_itemCache.find(itemId);
|
|
|
|
if (it == m_itemCache.end())
|
|
{
|
|
Q_ASSERT(false);
|
|
continue;
|
|
}
|
|
|
|
m_itemCache.erase(it);
|
|
}
|
|
|
|
|
|
parentTrack.removeTrack(trackId);
|
|
|
|
auto it = m_trackCache.find(trackId);
|
|
if (it == m_trackCache.end())
|
|
{
|
|
Q_ASSERT(false);
|
|
return;
|
|
}
|
|
|
|
m_trackCache.erase(it);
|
|
}
|
|
|
|
|
|
void TimelineModel::setMinimumDuration(int duration)
|
|
{
|
|
if (duration < 0)
|
|
{
|
|
WARNING_LOG(m_logger) << "negative duration is not possible -> setting minimum duration to 0";
|
|
duration = 0;
|
|
}
|
|
if (duration % 1000 && m_isSnapEnabled)
|
|
WARNING_LOG(m_logger) << "Snapping to 1000ms enabled, yet minimum duration is not a multiple of 1000ms: " << duration;
|
|
m_minItemDuration = duration;
|
|
}
|
|
|
|
bool TimelineModel::canDropItem(const Item &item, int trackId, qint64 start) const
|
|
{
|
|
Q_UNUSED(item);
|
|
Q_UNUSED(trackId);
|
|
Q_UNUSED(start);
|
|
return true;
|
|
}
|
|
|
|
bool TimelineModel::canMoveItem(const Item &item, qint64 start) const
|
|
{
|
|
Q_UNUSED(item);
|
|
Q_UNUSED(start);
|
|
return true;
|
|
}
|
|
|
|
bool TimelineModel::canResizeItem(const Item &item, qint64 start, int duration) const
|
|
{
|
|
Q_UNUSED(item);
|
|
Q_UNUSED(start);
|
|
Q_UNUSED(duration);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool TimelineModel::isItemDragged(int _itemId) const
|
|
{
|
|
return m_view->dragHandler() ? m_view->dragHandler()->dragItemIds().contains(_itemId) : false;
|
|
}
|
|
|
|
}
|