Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 1155febb authored by Nicolas Carion's avatar Nicolas Carion

[Timeline2][Model] Split away AbstractItemModel related methods

parent c8fa621f
......@@ -2,6 +2,7 @@ set(kdenlive_SRCS
${kdenlive_SRCS}
timeline2/model/clipmodel.cpp
timeline2/model/groupsmodel.cpp
timeline2/model/timelineitemmodel.cpp
timeline2/model/timelinemodel.cpp
timeline2/model/trackmodel.cpp
timeline2/model/snapmodel.cpp
......
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "timelineitemmodel.hpp"
#include "trackmodel.hpp"
#include "clipmodel.hpp"
#include "groupsmodel.hpp"
#include "doc/docundostack.hpp"
#include <mlt++/MltTractor.h>
#include <mlt++/MltProfile.h>
TimelineItemModel::TimelineItemModel(std::weak_ptr<DocUndoStack> undo_stack) :
QAbstractItemModel()
, TimelineModel(undo_stack)
{
}
std::shared_ptr<TimelineItemModel> TimelineItemModel::construct(std::weak_ptr<DocUndoStack> undo_stack, bool populate)
{
std::shared_ptr<TimelineItemModel> ptr(new TimelineItemModel(undo_stack));
ptr->m_groups = std::unique_ptr<GroupsModel>(new GroupsModel(ptr));
if (populate) {
// Testing: add a clip on first track
Mlt::Profile profile;
std::shared_ptr<Mlt::Producer> prod(new Mlt::Producer(profile,"color", "red"));
prod->set("length", 200);
prod->set("out", 24);
int ix = TrackModel::construct(ptr);
int ix2 = TrackModel::construct(ptr);
int ix3 = TrackModel::construct(ptr);
int clipId = ClipModel::construct(ptr, prod);
int clipId2 = ClipModel::construct(ptr, prod);
int clipId3 = ClipModel::construct(ptr, prod);
int clipId4 = ClipModel::construct(ptr, prod);
ptr->requestClipMove(clipId, ix, 100, true);
ptr->requestClipMove(clipId2, ix, 50, true);
ptr->requestClipMove(clipId3, ix, 250, true);
ptr->requestClipMove(clipId4, ix2, 112, true);
ptr->getTrackById(ix)->setProperty("kdenlive:trackheight", "60");
ptr->getTrackById(ix2)->setProperty("kdenlive:trackheight", "140");
ptr->getTrackById(ix3)->setProperty("kdenlive:trackheight", "140");
ptr->requestGroupClips({clipId, clipId4});
}
return ptr;
}
TimelineItemModel::~TimelineItemModel()
{
for(auto tracks : m_iteratorTable) {
deleteTrackById(tracks.first);
}
}
QModelIndex TimelineItemModel::index(int row, int column, const QModelIndex &parent) const
{
if (column > 0)
return QModelIndex();
// LOG_DEBUG() << __FUNCTION__ << row << column << parent;
QModelIndex result;
if (parent.isValid()) {
int trackId = 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()) {
auto it = m_allTracks.cbegin();
std::advance(it, row);
int trackId = (*it)->getId();
result = createIndex(row, column, quintptr(trackId));
}
return result;
}
QModelIndex TimelineItemModel::makeIndex(int trackIndex, int clipIndex) const
{
return index(clipIndex, 0, index(trackIndex));
}
QModelIndex TimelineItemModel::makeClipIndexFromID(int cid) const
{
Q_ASSERT(m_allClips.count(cid) > 0);
int tid = m_allClips.at(cid)->getCurrentTrackId();
return index(getTrackById_const(tid)->getRowfromClip(cid), 0, makeTrackIndexFromID(tid) );
}
QModelIndex TimelineItemModel::makeTrackIndexFromID(int tid) const
{
// we retrieve iterator
Q_ASSERT(m_iteratorTable.count(tid) > 0);
auto it = m_iteratorTable.at(tid);
int ind = (int)std::distance<decltype(m_allTracks.cbegin())>(m_allTracks.begin(), it);
return index(ind);
}
QModelIndex TimelineItemModel::parent(const QModelIndex &index) const
{
// LOG_DEBUG() << __FUNCTION__ << index;
const int id = static_cast<int>(index.internalId());
if (!index.isValid() || isTrack(id)) {
return QModelIndex();
} 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 TimelineItemModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
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;
}
// return number of clip in a specific track
return getTrackClipsCount(id);
}
return getTracksCount();
}
int TimelineItemModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 1;
}
QHash<int, QByteArray> TimelineItemModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[ResourceRole] = "resource";
roles[ServiceRole] = "mlt_service";
roles[IsBlankRole] = "blank";
roles[StartRole] = "start";
roles[DurationRole] = "duration";
roles[InPointRole] = "in";
roles[OutPointRole] = "out";
roles[FramerateRole] = "fps";
roles[IsMuteRole] = "mute";
roles[IsHiddenRole] = "hidden";
roles[IsAudioRole] = "audio";
roles[AudioLevelsRole] = "audioLevels";
roles[IsCompositeRole] = "composite";
roles[IsLockedRole] = "locked";
roles[FadeInRole] = "fadeIn";
roles[FadeOutRole] = "fadeOut";
roles[IsTransitionRole] = "isTransition";
roles[FileHashRole] = "hash";
roles[SpeedRole] = "speed";
roles[HeightRole] = "trackHeight";
roles[ItemIdRole] = "item";
return roles;
}
QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
{
if (!m_tractor || !index.isValid()) {
return QVariant();
}
const int id = (int)index.internalId();
if (role == ItemIdRole) {
return id;
}
//qDebug() << "DATA requested "<<index<<roleNames()[role];
if (isClip(id)) {
// Get data for a clip
switch (role) {
//TODO
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 if(isTrack(id)) {
switch (role) {
case NameRole:
case Qt::DisplayRole:
return QString("Track %1").arg(getTrackById_const(index.row())->getId());
case DurationRole:
return m_tractor->get_playtime();
case IsMuteRole:
return 0;
case IsHiddenRole:
return 0;
case IsAudioRole:
return false;
case IsLockedRole:
return 0;
case HeightRole: {
int height = getTrackById_const(index.row())->getProperty("kdenlive:trackheight").toInt();
return (height > 0 ? height : 50);
}
case IsCompositeRole: {
return Qt::Unchecked;
}
default:
break;
}
}
return QVariant();
}
void TimelineItemModel::notifyChange(const QModelIndex& topleft, const QModelIndex& bottomright, bool start, bool duration)
{
QVector<int> roles;
if (start) {
roles.push_back(StartRole);
}
if (duration) {
roles.push_back(DurationRole);
}
emit dataChanged(topleft, bottomright, roles);
}
void TimelineItemModel::_beginRemoveRows(const QModelIndex& i, int j, int k)
{
beginRemoveRows(i, j, k);
}
void TimelineItemModel::_beginInsertRows(const QModelIndex& i, int j, int k)
{
beginInsertRows(i, j, k);
}
void TimelineItemModel::_endRemoveRows()
{
endRemoveRows();
}
void TimelineItemModel::_endInsertRows()
{
endInsertRows();
}
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef TIMELINEITEMMODEL_H
#define TIMELINEITEMMODEL_H
#include <QAbstractItemModel>
#include "undohelper.hpp"
#include "timelinemodel.hpp"
/* @brief This class is the thin wrapper around the TimelineModel that provides interface for the QML.
It derives from AbstractItemModel to provide the model to the QML interface. An itemModel is organized with row and columns that contain the data. It can be hierarchical, meaning that a given index (row,column) can contain another level of rows and column.
Our organization is as follows: at the top level, each row contains a track. These rows are in the same order as in the actual timeline.
Then each of this row contains itself sub-rows that correspond to the clips.
Here the order of these sub-rows is unrelated to the chronological order of the clips,
but correspond to their Id order. For example, if you have three clips, with ids 12, 45 and 150, they will receive row index 0,1 and 2.
This is because the order actually doesn't matter since the clips are rendered based on their positions rather than their row order.
The id order has been choosed because it is consistant with a valid ordering of the clips.
The columns are never used, so the data is always in column 0
An ModelIndex in the ItemModel consists of a row number, a column number, and a parent index. In our case, tracks have always an empty parent, and the clip have a track index as parent.
A ModelIndex can also store one additional integer, and we exploit this feature to store the unique ID of the object it corresponds to.
*/
class TimelineItemModel : public QAbstractItemModel, public TimelineModel
{
Q_OBJECT
public:
/* @brief construct a timeline object and returns a pointer to the created object
@param undo_stack is a weak pointer to the undo stack of the project
*/
static std::shared_ptr<TimelineItemModel> construct(std::weak_ptr<DocUndoStack> undo_stack, bool populate = false);
protected:
/* @brief this constructor should not be called. Call the static construct instead
*/
TimelineItemModel(std::weak_ptr<DocUndoStack> undo_stack);
public:
~TimelineItemModel();
/// Two level model: tracks and clips on track
enum {
NameRole = Qt::UserRole + 1,
ResourceRole, /// clip only
ServiceRole, /// clip only
IsBlankRole, /// clip only
StartRole, /// clip only
DurationRole,
InPointRole, /// clip only
OutPointRole, /// clip only
FramerateRole, /// clip only
IsMuteRole, /// track only
IsHiddenRole, /// track only
IsAudioRole,
AudioLevelsRole, /// clip only
IsCompositeRole, /// track only
IsLockedRole, /// track only
HeightRole, /// track only
FadeInRole, /// clip only
FadeOutRole, /// clip only
IsTransitionRole,/// clip only
FileHashRole, /// clip only
SpeedRole, /// clip only
ItemIdRole
};
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex makeIndex(int trackIndex, int clipIndex) const;
/* @brief Creates an index based on the ID of the clip*/
QModelIndex makeClipIndexFromID(int cid) const override;
/* @brief Creates an index based on the ID of the track*/
QModelIndex makeTrackIndexFromID(int tid) const override;
QModelIndex parent(const QModelIndex &index) const override;
void notifyChange(const QModelIndex& topleft, const QModelIndex& bottomright, bool start, bool duration) override;
virtual void _beginRemoveRows(const QModelIndex&, int , int) override;
virtual void _beginInsertRows(const QModelIndex&, int , int) override;
virtual void _endRemoveRows() override;
virtual void _endInsertRows() override;
};
#endif
This diff is collapsed.
......@@ -25,8 +25,6 @@
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <QVector>
#include <QAbstractItemModel>
#include <mlt++/MltTractor.h>
#include "undohelper.hpp"
......@@ -48,7 +46,7 @@ class DocUndoStack;
This kind of behaviour frees us from the burden of simulating the actions before actually applying theme. This is a good thing because this simulation step would be very sensitive to corruptions and small discrepancies, which we try to avoid at all cost.
It derives from AbstractItemModel to provide the model to the QML interface. An itemModel is organized with row and columns that contain the data. It can be hierarchical, meaning that a given index (row,column) can contain another level of rows and column.
It derives from AbstractItemModel (indirectly through TimelineItemModel) to provide the model to the QML interface. An itemModel is organized with row and columns that contain the data. It can be hierarchical, meaning that a given index (row,column) can contain another level of rows and column.
Our organization is as follows: at the top level, each row contains a track. These rows are in the same order as in the actual timeline.
Then each of this row contains itself sub-rows that correspond to the clips.
Here the order of these sub-rows is unrelated to the chronological order of the clips,
......@@ -61,15 +59,8 @@ class DocUndoStack;
A ModelIndex can also store one additional integer, and we exploit this feature to store the unique ID of the object it corresponds to.
*/
class TimelineModel : public QAbstractItemModel, public std::enable_shared_from_this<TimelineModel>
class TimelineModel : public std::enable_shared_from_this<TimelineModel>
{
Q_OBJECT
public:
/* @brief construct a timeline object and returns a pointer to the created object
@param undo_stack is a weak pointer to the undo stack of the project
*/
static std::shared_ptr<TimelineModel> construct(std::weak_ptr<DocUndoStack> undo_stack, bool populate = false);
protected:
/* @brief this constructor should not be called. Call the static construct instead
......@@ -81,44 +72,7 @@ public:
friend class ClipModel;
friend class GroupsModel;
~TimelineModel();
/// Two level model: tracks and clips on track
enum {
NameRole = Qt::UserRole + 1,
ResourceRole, /// clip only
ServiceRole, /// clip only
IsBlankRole, /// clip only
StartRole, /// clip only
DurationRole,
InPointRole, /// clip only
OutPointRole, /// clip only
FramerateRole, /// clip only
IsMuteRole, /// track only
IsHiddenRole, /// track only
IsAudioRole,
AudioLevelsRole, /// clip only
IsCompositeRole, /// track only
IsLockedRole, /// track only
HeightRole, /// track only
FadeInRole, /// clip only
FadeOutRole, /// clip only
IsTransitionRole,/// clip only
FileHashRole, /// clip only
SpeedRole, /// clip only
ItemIdRole
};
int rowCount(const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex makeIndex(int trackIndex, int clipIndex) const;
/* @brief Creates an index based on the ID of the clip*/
QModelIndex makeClipIndexFromID(int cid) const;
/* @brief Creates an index based on the ID of the track*/
QModelIndex makeTrackIndexFromID(int tid) const;
QModelIndex parent(const QModelIndex &index) const override;
virtual ~TimelineModel();
Mlt::Tractor* tractor() const { return m_tractor.get(); }
/* @brief returns the number of tracks */
......@@ -268,9 +222,8 @@ protected:
/* @brief Helper function that returns true if the given ID correspond to a track
*/
bool isTrack(int id) const;
private:
protected:
std::unique_ptr<Mlt::Tractor> m_tractor;
QVector<int> m_snapPoints; // this will be modified from a lot of different places, we will probably need a mutex
std::list<std::unique_ptr<TrackModel>> m_allTracks;
......@@ -286,6 +239,16 @@ private:
std::weak_ptr<DocUndoStack> m_undoStack;
//what follows are some virtual function that corresponds to the QML. They are implemented in TimelineItemModel
protected:
virtual void _beginRemoveRows(const QModelIndex&, int , int) = 0;
virtual void _beginInsertRows(const QModelIndex&, int , int) = 0;
virtual void _endRemoveRows() = 0;
virtual void _endInsertRows() = 0;
virtual void notifyChange(const QModelIndex& topleft, const QModelIndex& bottomright, bool start, bool duration) = 0;
virtual QModelIndex makeClipIndexFromID(int) const = 0;
virtual QModelIndex makeTrackIndexFromID(int) const = 0;
};
#endif
......@@ -43,6 +43,7 @@ public:
TrackModel() = delete;
friend class TimelineModel;
friend class TimelineItemModel;
friend class ClipModel;
private:
/* This constructor is private, call the static construct instead */
......
......@@ -30,7 +30,7 @@
TimelineWidget::TimelineWidget(BinController *binController, std::weak_ptr<DocUndoStack> undoStack, QWidget *parent)
: QQuickWidget(parent)
, m_binController(binController)
, m_model(TimelineModel::construct(undoStack, true))
, m_model(TimelineItemModel::construct(undoStack, true))
, m_position(0)
{
registerTimelineItems();
......
......@@ -23,7 +23,7 @@
#define TIMELINEWIDGET_H
#include "mltcontroller/bincontroller.h"
#include "timeline2/model/timelinemodel.hpp"
#include "timeline2/model/timelineitemmodel.hpp"
#include <QQuickWidget>
class BinController;
......@@ -65,7 +65,7 @@ public slots:
void onSeeked(int position);
private:
std::shared_ptr<TimelineModel> m_model;
std::shared_ptr<TimelineItemModel> m_model;
BinController *m_binController;
struct Selection {
QList<int> selectedClips;
......
......@@ -17,6 +17,7 @@ SET(Tests_SRCS
../src/doc/docundostack.cpp
../src/timeline2/model/clipmodel.cpp
../src/timeline2/model/groupsmodel.cpp
../src/timeline2/model/timelineitemmodel.cpp
../src/timeline2/model/timelinemodel.cpp
../src/timeline2/model/trackmodel.cpp
../src/timeline2/model/snapmodel.cpp
......
......@@ -5,6 +5,7 @@
#define protected public
#include "timeline2/model/groupsmodel.hpp"
#include "timeline2/model/timelinemodel.hpp"
#include "timeline2/model/timelineitemmodel.hpp"
#include "timeline2/model/clipmodel.hpp"
#include "doc/docundostack.hpp"
#include <mlt++/MltProducer.h>
......@@ -13,7 +14,7 @@
TEST_CASE("Functional test of the group hierarchy", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
std::function<bool (void)> redo = [](){return true;};
......@@ -190,7 +191,7 @@ TEST_CASE("Functional test of the group hierarchy", "[GroupsModel]")
TEST_CASE("Interface test of the group hierarchy", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
......@@ -317,7 +318,7 @@ TEST_CASE("Interface test of the group hierarchy", "[GroupsModel]")
TEST_CASE("Orphan groups deletion", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
GroupsModel groups(timeline);
std::function<bool (void)> undo = [](){return true;};
std::function<bool (void)> redo = [](){return true;};
......@@ -371,7 +372,7 @@ TEST_CASE("Orphan groups deletion", "[GroupsModel]")
TEST_CASE("Undo/redo", "[GroupsModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
Mlt::Profile profile;
std::shared_ptr<Mlt::Producer> producer = std::make_shared<Mlt::Producer>(profile, "color", "red");
......
......@@ -6,6 +6,7 @@
#define protected public
#include "timeline2/model/trackmodel.hpp"
#include "timeline2/model/timelinemodel.hpp"
#include "timeline2/model/timelineitemmodel.hpp"
#include "timeline2/model/clipmodel.hpp"
#include "doc/docundostack.hpp"
......@@ -21,7 +22,7 @@ Mlt::Profile profile_model;
TEST_CASE("Basic creation/deletion of a track", "[TrackModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
int id1 = TrackModel::construct(timeline);
REQUIRE(timeline->getTracksCount() == 1);
......@@ -49,7 +50,7 @@ TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
std::shared_ptr<Mlt::Producer> producer = std::make_shared<Mlt::Producer>(profile_model, "color", "red");
......@@ -82,7 +83,7 @@ TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
TEST_CASE("Clip manipulation", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
std::shared_ptr<Mlt::Producer> producer = std::make_shared<Mlt::Producer>(profile_model, "color", "red");
......@@ -573,7 +574,7 @@ TEST_CASE("Clip manipulation", "[ClipModel]")
TEST_CASE("Check id unicity", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
std::shared_ptr<Mlt::Producer> producer = std::make_shared<Mlt::Producer>(profile_model, "color", "red");
producer->set("length", 20);
......@@ -610,7 +611,7 @@ TEST_CASE("Check id unicity", "[ClipModel]")
TEST_CASE("Undo and Redo", "[ClipModel]")
{
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
std::shared_ptr<Mlt::Producer> producer = std::make_shared<Mlt::Producer>(profile_model, "color", "red");
std::shared_ptr<Mlt::Producer> producer2 = std::make_shared<Mlt::Producer>(profile_model, "color", "blue");
......
......@@ -6,6 +6,7 @@
#define protected public
#include "timeline2/model/trackmodel.hpp"
#include "timeline2/model/timelinemodel.hpp"
#include "timeline2/model/timelineitemmodel.hpp"
#include "timeline2/model/clipmodel.hpp"
#include "doc/docundostack.hpp"
......@@ -17,7 +18,7 @@
TEST_CASE("Regression") {
Mlt::Profile profile;
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
std::shared_ptr<TimelineModel> timeline = TimelineModel::construct(undoStack);
std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(undoStack);
TimelineModel::next_id = 0;
undoStack->undo();
undoStack->redo();
......