1 /* 2 SPDX-FileCopyrightText: 2017 Nicolas Carion 3 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 4 */ 5 6 #ifndef MARKERLISTMODEL_H 7 #define MARKERLISTMODEL_H 8 9 #include "definitions.h" 10 #include "gentime.h" 11 #include "undohelper.hpp" 12 13 #include <QAbstractListModel> 14 #include <QReadWriteLock> 15 16 #include <array> 17 #include <map> 18 #include <memory> 19 20 class ClipController; 21 class DocUndoStack; 22 class SnapInterface; 23 24 /** @class MarkerListModel 25 @brief This class is the model for a list of markers. 26 A marker is defined by a time, a type (the color used to represent it) and a comment string. 27 We store them in a sorted fashion using a std::map 28 29 A marker is essentially bound to a clip. We can also define guides, that are timeline-wise markers. For that, use the constructors without clipId 30 */ 31 class MarkerListModel : public QAbstractListModel 32 { 33 Q_OBJECT 34 35 public: 36 /** @brief Construct a marker list bound to the bin clip with given id */ 37 explicit MarkerListModel(QString clipId, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent = nullptr); 38 39 /** @brief Construct a guide list (bound to the timeline) */ 40 MarkerListModel(std::weak_ptr<DocUndoStack> undo_stack, QObject *parent = nullptr); 41 42 enum { CommentRole = Qt::UserRole + 1, PosRole, FrameRole, ColorRole, TypeRole, IdRole }; 43 44 /** @brief Adds a marker at the given position. If there is already one, the comment will be overridden 45 @param pos defines the position of the marker, relative to the clip 46 @param comment is the text associated with the marker 47 @param type is the type (color) associated with the marker. If -1 is passed, then the value is pulled from kdenlive's defaults 48 */ 49 bool addMarker(GenTime pos, const QString &comment, int type = -1); 50 bool addMarkers(QMap <GenTime, QString> markers, int type = -1); 51 52 protected: 53 /** @brief Same function but accumulates undo/redo */ 54 bool addMarker(GenTime pos, const QString &comment, int type, Fun &undo, Fun &redo); 55 56 public: 57 /** @brief Removes the marker at the given position. 58 Returns false if no marker was found at given pos 59 */ 60 bool removeMarker(GenTime pos); 61 /** @brief Delete all the markers of the model */ 62 bool removeAllMarkers(); 63 64 /** @brief Same function but accumulates undo/redo */ 65 bool removeMarker(GenTime pos, Fun &undo, Fun &redo); 66 67 public: 68 /** @brief Edit a marker 69 @param oldPos is the old position of the marker 70 @param pos defines the new position of the marker, relative to the clip 71 @param comment is the text associated with the marker 72 @param type is the type (color) associated with the marker. If -1 is passed, then the value is pulled from kdenlive's defaults 73 */ 74 bool editMarker(GenTime oldPos, GenTime pos, QString comment = QString(), int type = -1); 75 76 /** @brief Moves all markers from on to another position 77 @param markers list of markers to move 78 @param fromPos 79 @param toPos 80 @param undo 81 @param redo 82 */ 83 bool moveMarkers(QList<CommentedTime> markers, GenTime fromPos, GenTime toPos, Fun &undo, Fun &redo); 84 bool moveMarker(int mid, GenTime pos); 85 void moveMarkersWithoutUndo(QVector<int> markersId, int offset, bool updateView = true); 86 87 /** @brief This describes the available markers type and their corresponding colors */ 88 static std::array<QColor, 9> markerTypes; 89 90 /** @brief Returns a marker data at given pos */ 91 CommentedTime getMarker(const GenTime &pos, bool *ok) const; 92 93 /** @brief Returns all markers in model */ 94 QList<CommentedTime> getAllMarkers() const; 95 96 /** @brief Returns all markers of model that are intersect with a given range. 97 * @param start is the position where start to search for markers 98 * @param end is the position after which markers will not be returned, set to -1 to get all markers after start 99 */ 100 QList<CommentedTime> getMarkersInRange(int start, int end) const; 101 QVector<int> getMarkersIdInRange(int start, int end) const; 102 103 /** @brief Returns a marker position in frames given it's id */ 104 int getMarkerPos(int mid) const; 105 106 /** @brief Returns all markers positions in model */ 107 std::vector<int> getSnapPoints() const; 108 109 /** @brief Returns true if a marker exists at given pos 110 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 111 */ 112 Q_INVOKABLE bool hasMarker(int frame) const; 113 bool hasMarker(GenTime pos) const; 114 CommentedTime marker(GenTime pos) const; 115 116 /** @brief Registers a snapModel to the marker model. 117 This is intended to be used for a guide model, so that the timelines can register their snapmodel to be updated when the guide moves. This is also used 118 on the clip monitor to keep tracking the clip markers 119 The snap logic for clips is managed from the Timeline 120 Note that no deregistration is necessary, the weak_ptr will be discarded as soon as it becomes invalid. 121 */ 122 void registerSnapModel(const std::weak_ptr<SnapInterface> &snapModel); 123 124 /** @brief Exports the model to json using format above */ 125 QString toJson() const; 126 127 /** @brief Shows a dialog to edit a marker/guide 128 @param pos: position of the marker to edit, or new position for a marker 129 @param widget: qt widget that will be the parent of the dialog 130 @param createIfNotFound: if true, we create a marker if none is found at pos 131 @param clip: pointer to the clip if we are editing a marker 132 @return true if dialog was accepted and modification successful 133 */ 134 bool editMarkerGui(const GenTime &pos, QWidget *parent, bool createIfNotFound, ClipController *clip = nullptr, bool createOnly = false); 135 136 // Mandatory overloads 137 QVariant data(const QModelIndex &index, int role) const override; 138 QHash<int, QByteArray> roleNames() const override; 139 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 140 141 public slots: 142 /** @brief Imports a list of markers from json data 143 The data should be formatted as follows: 144 [{"pos":0.2, "comment":"marker 1", "type":1}, {...}, ...] 145 return true on success and logs undo object 146 @param ignoreConflicts: if set to false, it aborts if the data contains a marker with same position but different comment and/or type. If set to true, 147 such markers are overridden silently 148 @param pushUndo: if true, create an undo object 149 */ 150 bool importFromJson(const QString &data, bool ignoreConflicts, bool pushUndo = true); 151 bool importFromJson(const QString &data, bool ignoreConflicts, Fun &undo, Fun &redo); 152 153 protected: 154 /** @brief Adds a snap point at marker position in the registered snap models 155 (those that are still valid)*/ 156 void addSnapPoint(GenTime pos); 157 158 /** @brief Deletes a snap point at marker position in the registered snap models 159 (those that are still valid)*/ 160 void removeSnapPoint(GenTime pos); 161 162 /** @brief Helper function that generate a lambda to change comment / type of given marker */ 163 Fun changeComment_lambda(GenTime pos, const QString &comment, int type); 164 165 /** @brief Helper function that generate a lambda to add given marker */ 166 Fun addMarker_lambda(GenTime pos, const QString &comment, int type); 167 168 /** @brief Helper function that generate a lambda to remove given marker */ 169 Fun deleteMarker_lambda(GenTime pos); 170 171 /** @brief Helper function that retrieves a pointer to the markermodel, given whether it's a guide model and its clipId*/ 172 static std::shared_ptr<MarkerListModel> getModel(bool guide, const QString &clipId); 173 174 /** @brief Connects the signals of this object */ 175 void setup(); 176 177 private: 178 std::weak_ptr<DocUndoStack> m_undoStack; 179 /** @brief whether this model represents timeline-wise guides */ 180 bool m_guide; 181 /** @brief the Id of the clip this model corresponds to, if any. */ 182 QString m_clipId; 183 184 /** @brief This is a lock that ensures safety in case of concurrent access */ 185 mutable QReadWriteLock m_lock; 186 187 std::map<int, CommentedTime> m_markerList; 188 std::vector<std::weak_ptr<SnapInterface>> m_registeredSnaps; 189 int getRowfromId(int mid) const; 190 int getIdFromPos(const GenTime &pos) const; 191 192 signals: 193 void modelChanged(); 194 195 }; 196 Q_DECLARE_METATYPE(MarkerListModel *) 197 198 #endif 199