[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