File indexing completed on 2024-04-28 04:51:21
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #pragma once 0007 0008 #include "definitions.h" 0009 #include "undohelper.hpp" 0010 #include "utils/gentime.h" 0011 0012 #include <QAbstractListModel> 0013 #include <QReadWriteLock> 0014 0015 #include <array> 0016 #include <map> 0017 #include <memory> 0018 0019 class ProjectClip; 0020 class DocUndoStack; 0021 class SnapInterface; 0022 0023 /** @class MarkerListModel 0024 @brief This class is the model for a list of markers. 0025 A marker is defined by a time, a type (the color used to represent it) and a comment string. 0026 We store them in a sorted fashion using a std::map 0027 0028 A marker is essentially bound to a clip. 0029 */ 0030 class MarkerListModel : public QAbstractListModel, public enable_shared_from_this_virtual<MarkerListModel> 0031 { 0032 Q_OBJECT 0033 0034 friend class ClipController; 0035 0036 public: 0037 /** @brief Construct a marker list bound to the bin clip with given id */ 0038 explicit MarkerListModel(QString clipId, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent = nullptr); 0039 0040 enum { CommentRole = Qt::UserRole + 1, PosRole, FrameRole, ColorRole, TypeRole, IdRole, TCRole }; 0041 0042 /** @brief Adds a marker at the given position. If there is already one, the comment will be overridden 0043 @param pos defines the position of the marker, relative to the clip 0044 @param comment is the text associated with the marker 0045 @param type is the type (color) associated with the marker. If -1 is passed, then the value is pulled from kdenlive's defaults 0046 */ 0047 bool addMarker(GenTime pos, const QString &comment, int type = -1); 0048 bool addMarkers(const QMap<GenTime, QString> &markers, int type = -1); 0049 0050 protected: 0051 /** @brief Same function but accumulates undo/redo */ 0052 bool addMarker(GenTime pos, const QString &comment, int type, Fun &undo, Fun &redo); 0053 0054 public: 0055 /** @brief Removes the marker at the given position. 0056 Returns false if no marker was found at given pos 0057 */ 0058 bool removeMarker(GenTime pos); 0059 /** @brief Delete all the markers of the model */ 0060 bool removeAllMarkers(); 0061 0062 /** @brief Same function but accumulates undo/redo */ 0063 bool removeMarker(GenTime pos, Fun &undo, Fun &redo); 0064 0065 public: 0066 /** @brief Edit a marker 0067 @param oldPos is the old position of the marker 0068 @param pos defines the new position of the marker, relative to the clip 0069 @param comment is the text associated with the marker 0070 @param type is the type (color) associated with the marker. If -1 is passed, then the value is pulled from kdenlive's defaults 0071 */ 0072 bool editMarker(GenTime oldPos, GenTime pos, QString comment = QString(), int type = -1); 0073 0074 /** @brief Moves all markers from on to another position 0075 @param markers list of markers to move 0076 @param fromPos 0077 @param toPos 0078 @param undo 0079 @param redo 0080 */ 0081 bool moveMarkers(const QList<CommentedTime> &markers, GenTime fromPos, GenTime toPos, Fun &undo, Fun &redo); 0082 bool moveMarker(int mid, GenTime pos); 0083 void moveMarkersWithoutUndo(const QVector<int> &markersId, int offset, bool updateView = true); 0084 0085 /** @brief Returns a marker data at given pos */ 0086 CommentedTime getMarker(const GenTime &pos, bool *ok) const; 0087 CommentedTime getMarker(int frame, bool *ok) const; 0088 0089 /** @brief Returns all markers in model or – if a type is given – all markers of the given type */ 0090 QList<CommentedTime> getAllMarkers(int type = -1) const; 0091 0092 /** @brief Returns all markers of model that are intersect with a given range. 0093 * @param start is the position where start to search for markers 0094 * @param end is the position after which markers will not be returned, set to -1 to get all markers after start 0095 */ 0096 QList<CommentedTime> getMarkersInRange(int start, int end) const; 0097 QVector<int> getMarkersIdInRange(int start, int end) const; 0098 0099 /** @brief Returns a marker position in frames given it's id */ 0100 int getMarkerPos(int mid) const; 0101 0102 /** @brief Returns all markers positions in model */ 0103 std::vector<int> getSnapPoints() const; 0104 0105 /** @brief Returns true if a marker exists at given pos 0106 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 0107 */ 0108 Q_INVOKABLE bool hasMarker(int frame) const; 0109 /** @brief Returns a marker id at frame pos. Returns -1 if no marker exists at that position 0110 */ 0111 int markerIdAtFrame(int pos) const; 0112 bool hasMarker(GenTime pos) const; 0113 CommentedTime marker(GenTime pos) const; 0114 CommentedTime marker(int frame) const; 0115 CommentedTime markerById(int mid) const; 0116 0117 /** @brief Registers a snapModel to the marker model. 0118 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 0119 on the clip monitor to keep tracking the clip markers 0120 The snap logic for clips is managed from the Timeline 0121 Note that no deregistration is necessary, the weak_ptr will be discarded as soon as it becomes invalid. 0122 */ 0123 void registerSnapModel(const std::weak_ptr<SnapInterface> &snapModel); 0124 0125 /** @brief Exports the model to json using format above 0126 * @param categories will only export selected categories. If param is empty, all categories will be exported 0127 */ 0128 QString toJson(QList<int> categories = {}) const; 0129 0130 /** @brief Shows a dialog to edit a marker/guide 0131 @param pos: position of the marker to edit, or new position for a marker 0132 @param widget: qt widget that will be the parent of the dialog 0133 @param createIfNotFound: if true, we create a marker if none is found at pos 0134 @param clip: pointer to the clip if we are editing a marker 0135 @return true if dialog was accepted and modification successful 0136 */ 0137 bool editMarkerGui(const GenTime &pos, QWidget *parent, bool createIfNotFound, ProjectClip *clip = nullptr, bool createOnly = false); 0138 /** @brief Shows a dialog to change the category of multiple markers/guides 0139 @param positions: List of the markers positions to edit 0140 @param widget: qt widget that will be the parent of the dialog 0141 @return true if dialog was accepted and modification successful 0142 */ 0143 bool editMultipleMarkersGui(const QList<GenTime> positions, QWidget *parent); 0144 /** @brief Shows a dialog to add multiple markers/guide 0145 @param pos: position of the marker to edit, or new position for a marker 0146 @param widget: qt widget that will be the parent of the dialog 0147 @param createIfNotFound: if true, we create a marker if none is found at pos 0148 @param clip: pointer to the clip if we are editing a marker 0149 @return true if dialog was accepted and modification successful 0150 */ 0151 bool addMultipleMarkersGui(const GenTime &pos, QWidget *parent, bool createIfNotFound, ProjectClip *clip = nullptr); 0152 void exportGuidesGui(QWidget *parent, GenTime projectDuration) const; 0153 /** @brief Load the marker categories from a stringList 0154 * @return the list of deleted categories ids (if any) 0155 */ 0156 void loadCategoriesWithUndo(const QStringList &categories, const QStringList ¤tCategories, const QMap<int, int> remapCategories = {}); 0157 QList<int> loadCategories(const QStringList &categories, bool notify = true); 0158 QStringList guideCategoriesToStringList(const QString &categoriesData); 0159 /** @brief Returns the marker categories in the form of a stringList for saving */ 0160 const QStringList categoriesToStringList() const; 0161 const QString categoriesToJSon() const; 0162 static const QString categoriesListToJSon(const QStringList categories); 0163 0164 // Mandatory overloads 0165 QVariant data(const QModelIndex &index, int role) const override; 0166 QHash<int, QByteArray> roleNames() const override; 0167 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0168 0169 public Q_SLOTS: 0170 /** @brief Imports a list of markers from json data 0171 The data should be formatted as follows: 0172 [{"pos":0.2, "comment":"marker 1", "type":1}, {...}, ...] 0173 return true on success and logs undo object 0174 @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, 0175 such markers are overridden silently 0176 @param pushUndo: if true, create an undo object 0177 */ 0178 bool importFromJson(const QString &data, bool ignoreConflicts, bool pushUndo = true); 0179 bool importFromJson(const QString &data, bool ignoreConflicts, Fun &undo, Fun &redo); 0180 bool importFromTxt(const QString &fileName, Fun &undo, Fun &redo); 0181 bool importFromFile(const QString &fileData, bool ignoreConflicts); 0182 0183 protected: 0184 /** @brief Adds a snap point at marker position in the registered snap models 0185 (those that are still valid)*/ 0186 void addSnapPoint(GenTime pos); 0187 0188 /** @brief Deletes a snap point at marker position in the registered snap models 0189 (those that are still valid)*/ 0190 void removeSnapPoint(GenTime pos); 0191 0192 /** @brief Helper function that generate a lambda to change comment / type of given marker */ 0193 Fun changeComment_lambda(GenTime pos, const QString &comment, int type); 0194 0195 /** @brief Helper function that generate a lambda to add given marker */ 0196 Fun addMarker_lambda(GenTime pos, const QString &comment, int type); 0197 0198 /** @brief Helper function that generate a lambda to remove given marker */ 0199 Fun deleteMarker_lambda(GenTime pos); 0200 0201 /** @brief Helper function that retrieves a pointer to the markermodel, given whether it's a guide model and its clipId*/ 0202 std::shared_ptr<MarkerListModel> getModel(const QString &clipId); 0203 0204 /** @brief Connects the signals of this object */ 0205 void setup(); 0206 0207 private: 0208 std::weak_ptr<DocUndoStack> m_undoStack; 0209 /** @brief the Id of the clip this model corresponds to. */ 0210 QString m_clipId; 0211 0212 /** @brief This is a lock that ensures safety in case of concurrent access */ 0213 mutable QReadWriteLock m_lock; 0214 0215 std::map<int, CommentedTime> m_markerList; 0216 /** @brief A list of {marker frame,marker id}, useful to quickly find a marker */ 0217 QMap<int, int> m_markerPositions; 0218 0219 std::vector<std::weak_ptr<SnapInterface>> m_registeredSnaps; 0220 int getRowfromId(int mid) const; 0221 int getIdFromPos(const GenTime &pos) const; 0222 int getIdFromPos(int frame) const; 0223 0224 Q_SIGNALS: 0225 void modelChanged(); 0226 void categoriesChanged(); 0227 }; 0228 Q_DECLARE_METATYPE(MarkerListModel *)