[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kdenlive/refactoring_timeline] src/timeline2/model: [Timeline2][Model] Change ItemModel id scheme a
From: Nicolas Carion <null () kde ! org>
Date: 2017-01-31 12:12:04
Message-ID: E1cYXI4-0003Zz-Ko () code ! kde ! org
[Download RAW message or body]
Git commit 4ba05ceb10994cc64e7d6f3ac397567162a456e1 by Nicolas Carion.
Committed on 31/01/2017 at 12:14.
Pushed by alcinos into branch 'refactoring_timeline'.
[Timeline2][Model] Change ItemModel id scheme and reduce unnecessary access to \
underlying Melt objects
M +66 -65 src/timeline2/model/timelinemodel.cpp
M +8 -0 src/timeline2/model/timelinemodel.hpp
M +17 -0 src/timeline2/model/trackmodel.cpp
M +11 -0 src/timeline2/model/trackmodel.hpp
https://commits.kde.org/kdenlive/4ba05ceb10994cc64e7d6f3ac397567162a456e1
diff --git a/src/timeline2/model/timelinemodel.cpp \
b/src/timeline2/model/timelinemodel.cpp index 3b2f67dfe..186452dd7 100644
--- a/src/timeline2/model/timelinemodel.cpp
+++ b/src/timeline2/model/timelinemodel.cpp
@@ -31,9 +31,9 @@
#include <mlt++/MltProfile.h>
int TimelineModel::next_id = 0;
-static const quintptr NO_PARENT_ID = quintptr(-1);
-TimelineModel::TimelineModel() : QAbstractItemModel(),
+TimelineModel::TimelineModel() :
+ QAbstractItemModel(),
m_tractor(new Mlt::Tractor())
{
Mlt::Profile profile;
@@ -75,16 +75,17 @@ QModelIndex TimelineModel::index(int row, int column, const \
QModelIndex &parent) // LOG_DEBUG() << __FUNCTION__ << row << column << parent;
QModelIndex result;
if (parent.isValid()) {
- //TODO: do we need a separate index like shotcut?
- int i = row; //m_trackList.at(parent.row()).mlt_index;
- QScopedPointer<Mlt::Producer> track(m_tractor->track(i));
- if (track) {
- Mlt::Playlist playlist((mlt_playlist) track->get_producer());
- if (row < playlist.count())
- result = createIndex(row, column, parent.row());
+ int trackId = static_cast<int>(parent.internalId());
+ Q_ASSERT(isTrack(trackId));
+ int clipId = getTrackById_const(trackId)->getClipByRow(row);
+ if (clipId != -1) {
+ result = createIndex(row, 0, quintptr(clipId));
}
} else if (row < getTracksCount()) {
- result = createIndex(row, column, NO_PARENT_ID);
+ auto it = m_allTracks.cbegin();
+ std::advance(it, row);
+ int trackId = (*it)->getId();
+ result = createIndex(row, column, quintptr(trackId));
}
return result;
}
@@ -97,36 +98,31 @@ QModelIndex TimelineModel::makeIndex(int trackIndex, int \
clipIndex) const QModelIndex TimelineModel::parent(const QModelIndex &index) const
{
// LOG_DEBUG() << __FUNCTION__ << index;
- if (!index.isValid() || index.internalId() == NO_PARENT_ID)
+ const int id = static_cast<int>(index.internalId());
+ if (!index.isValid() || isTrack(id)) {
return QModelIndex();
- else
- return createIndex(index.internalId(), 0, NO_PARENT_ID);
+ } else {
+ Q_ASSERT(isClip(id)); //if id is not a track it must be a clip.
+ const int trackId = getClipTrackId(id);
+ auto it = m_iteratorTable.at(trackId); //iterator to the element
+ decltype(m_allTracks.cbegin()) const_it(it);
+ int row = (int)std::distance(m_allTracks.cbegin(), const_it); //compute \
index in list + return createIndex(row, 0, quintptr(trackId));
+ }
}
int TimelineModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
if (parent.isValid()) {
- // return number of clip in a specific track
- if (parent.internalId() != NO_PARENT_ID)
+ const int id = (int)parent.internalId();
+ if (isClip(id) || !isTrack(id)) {
+ //clips don't have children
+ //if it is not a track and not a clip, it is something invalid
return 0;
- QScopedPointer<Mlt::Producer> track(m_tractor->track(parent.row()));
- if (track) {
- Mlt::Playlist playlist((mlt_playlist) track->get_producer());
- return playlist.count();
}
- return 0;
- /*int i = m_trackList.at(parent.row()).mlt_index;
- QScopedPointer<Mlt::Producer> track(m_tractor->track(i));
- if (track) {
- Mlt::Playlist playlist(*track);
- int n = playlist.count();
-// LOG_DEBUG() << __FUNCTION__ << parent << i << n;
- return n;
- } else {
- return 0;
- }*/
+ // return number of clip in a specific track
+ return getTrackClipsCount(id);
}
return getTracksCount();
}
@@ -169,49 +165,44 @@ QVariant TimelineModel::data(const QModelIndex &index, int \
role) const if (!m_tractor || !index.isValid()) {
return QVariant();
}
- if (index.parent().isValid()) {
+ const int id = (int)index.internalId();
+ if (isClip(id)) {
// Get data for a clip
- QScopedPointer<Mlt::Producer> track(m_tractor->track(index.internalId()));
- if (track) {
- Mlt::Playlist playlist((mlt_playlist) track->get_producer());
- QScopedPointer<Mlt::ClipInfo> info(playlist.clip_info(index.row()));
- if (info) switch (role) {
+ switch (role) {
//TODO
- case NameRole:
- case ResourceRole:
- case Qt::DisplayRole: {
- QString result = QString::fromUtf8(info->resource);
- if (result == "<producer>" && info->producer
- && info->producer->is_valid() && \
info->producer->get("mlt_service"))
- result = QString::fromUtf8(info->producer->get("mlt_service"));
- return result;
- }
- case ServiceRole:
- return QString("service2");
- break;
- case IsBlankRole:
- return playlist.is_blank(index.row());
- case StartRole:
- return info->start;
- case DurationRole:
- return info->frame_count;
- case InPointRole:
- return info->frame_in;
- case OutPointRole:
- return info->frame_out;
- case FramerateRole:
- return info->fps;
- default:
- break;
+ case NameRole:
+ case ResourceRole:
+ case Qt::DisplayRole:{
+ QString result = QString::fromUtf8("clip name");
+ return result;
}
+ case ServiceRole:
+ return QString("service2");
+ break;
+ case IsBlankRole: //probably useless
+ return false;
+ case StartRole:
+ return m_allClips.at(id)->getPosition();
+ case DurationRole:
+ return m_allClips.at(id)->getPlaytime();
+
+ //Are these really needed ??
+ case InPointRole:
+ return 0;
+ case OutPointRole:
+ return 1;
+ case FramerateRole:
+ return 25;
+ default:
+ break;
}
- } else {
+ } else if(isTrack(id)) {
switch (role) {
case NameRole:
case Qt::DisplayRole:
return QString("Track \
%1").arg(getTrackById_const(index.row())->getId()); case DurationRole:
- return 100;
+ return m_tractor->get_playtime();
case IsMuteRole:
return 0;
case IsHiddenRole:
@@ -393,6 +384,16 @@ int TimelineModel::getNextId()
return TimelineModel::next_id++;
}
+bool TimelineModel::isClip(int id) const
+{
+ return m_allClips.count(id) > 0;
+}
+
+bool TimelineModel::isTrack(int id) const
+{
+ return m_iteratorTable.count(id) > 0;
+}
+
int TimelineModel::duration() const
{
return m_tractor->get_playtime();
diff --git a/src/timeline2/model/timelinemodel.hpp \
b/src/timeline2/model/timelinemodel.hpp index ed49e1673..4fc3e7566 100644
--- a/src/timeline2/model/timelinemodel.hpp
+++ b/src/timeline2/model/timelinemodel.hpp
@@ -177,6 +177,14 @@ protected:
/* @brief Returns next valid unique id to create an object
*/
static int getNextId();
+
+ /* @brief Helper function that returns true if the given ID correspond to a clip
+ */
+ bool isClip(int id) const;
+
+ /* @brief Helper function that returns true if the given ID correspond to a \
track + */
+ bool isTrack(int id) const;
private:
Mlt::Tractor *m_tractor;
QVector<int> m_snapPoints; // this will be modified from a lot of different \
places, we will probably need a mutex
diff --git a/src/timeline2/model/trackmodel.cpp b/src/timeline2/model/trackmodel.cpp
index d71b44a41..60ee4895e 100644
--- a/src/timeline2/model/trackmodel.cpp
+++ b/src/timeline2/model/trackmodel.cpp
@@ -29,6 +29,7 @@
TrackModel::TrackModel(std::weak_ptr<TimelineModel> parent) :
m_parent(parent)
, m_id(TimelineModel::getNextId())
+ , m_currentInsertionOrder(0)
{
}
@@ -61,6 +62,7 @@ int TrackModel::getClipsCount()
}
}
Q_ASSERT(count == static_cast<int>(m_allClips.size()));
+ Q_ASSERT(count == static_cast<int>(m_clipsByInsertionOrder.size()));
return count;
}
@@ -103,6 +105,9 @@ bool TrackModel::requestClipInsertion(std::shared_ptr<ClipModel> \
clip, int posit }
}
m_allClips[clip->getId()] = clip;
+ m_insertionOrder[clip->getId()] = m_currentInsertionOrder;
+ m_clipsByInsertionOrder[m_currentInsertionOrder] = clip->getId();
+ m_currentInsertionOrder++;
clip->setPosition(position);
return true;
}
@@ -122,6 +127,8 @@ bool TrackModel::requestClipDeletion(int cid, bool dry)
if (prod != nullptr) {
m_playlist.consolidate_blanks();
m_allClips.erase(cid);
+ m_clipsByInsertionOrder.erase(m_insertionOrder[cid]);
+ m_insertionOrder.erase(cid);
return true;
}
return false;
@@ -206,6 +213,16 @@ int TrackModel::getId() const
return m_id;
}
+int TrackModel::getClipByRow(int row) const
+{
+ if (row >= static_cast<int>(m_allClips.size())) {
+ return -1;
+ }
+ auto it = m_clipsByInsertionOrder.cbegin();
+ std::advance(it, row);
+ return (*it).second;
+}
+
QVariant TrackModel::getProperty(const QString &name)
{
return m_playlist.get(name.toUtf8().constData());
diff --git a/src/timeline2/model/trackmodel.hpp b/src/timeline2/model/trackmodel.hpp
index 08d7ea9e8..81c6baaec 100644
--- a/src/timeline2/model/trackmodel.hpp
+++ b/src/timeline2/model/trackmodel.hpp
@@ -98,9 +98,15 @@ protected:
@param dry If this parameter is true, no action is actually executed, but we \
return true if it would be possible to do it.
*/
bool requestClipResize(int cid, int in, int out, bool right, bool dry = false);
+
/*@brief Returns the (unique) construction id of the track*/
int getId() const;
+ /*@brief This function is used only by the QAbstractItemModel
+ Given a row in the model, retrieves the corresponding clip id. If it does not \
exist, returns -1 + */
+ int getClipByRow(int row) const;
+
/*@brief This is an helper function that test frame level consistancy with the \
MLT structures */ bool checkConsistency();
public slots:
@@ -112,8 +118,13 @@ private:
int m_id; //this is the creation id of the track, used for book-keeping
Mlt::Playlist m_playlist;
+ int m_currentInsertionOrder;
std::unordered_map<int, std::shared_ptr<ClipModel>> m_allClips;
+ std::map<int, int> m_clipsByInsertionOrder; //This map stores the order in which \
the clips were inserted. This implicitly gives the model Row of each clip since they \
remain sorted even after deletion. Note that it is important to keep an ordered data \
structure such has std::map (QMap is NOT ordered). +
+ std::unordered_map<int, int> m_insertionOrder; //This is a reverse map of \
m_clipsByInsertionOrder. Note that order is not important thus we can use an \
unordered_map. +
};
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic