File indexing completed on 2024-04-21 04:51:16
0001 /* 0002 SPDX-FileCopyrightText: 2012 Till Theato <root@ttill.de> 0003 SPDX-FileCopyrightText: 2014 Jean-Baptiste Mardelle <jb@kdenlive.org> 0004 SPDX-FileCopyrightText: 2017 Nicolas Carion 0005 This file is part of Kdenlive. See www.kdenlive.org. 0006 0007 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0008 */ 0009 0010 #pragma once 0011 0012 #include "abstractmodel/abstracttreemodel.hpp" 0013 #include "bin/abstractprojectitem.h" 0014 #include "definitions.h" 0015 #include "undohelper.hpp" 0016 #include <QDomElement> 0017 #include <QFileInfo> 0018 #include <QIcon> 0019 #include <QReadWriteLock> 0020 #include <QSize> 0021 #include <QTimer> 0022 #include <QUuid> 0023 0024 class BinPlaylist; 0025 class FileWatcher; 0026 class MarkerListModel; 0027 class ProjectClip; 0028 class ProjectFolder; 0029 class EffectStackModel; 0030 class QProgressDialog; 0031 0032 namespace Mlt { 0033 class Producer; 0034 class Properties; 0035 class Tractor; 0036 class Service; 0037 } // namespace Mlt 0038 0039 /** 0040 * @class ProjectItemModel 0041 * @brief Acts as an adaptor to be able to use BinModel with item views. 0042 */ 0043 class ProjectItemModel : public AbstractTreeModel 0044 { 0045 Q_OBJECT 0046 0047 protected: 0048 explicit ProjectItemModel(QObject *parent); 0049 0050 public: 0051 static std::shared_ptr<ProjectItemModel> construct(QObject *parent = nullptr); 0052 ~ProjectItemModel() override; 0053 0054 friend class ProjectClip; 0055 friend class ThumbnailCache; 0056 /** @brief Timer checking if we have missing clips in the project */ 0057 QTimer missingClipTimer; 0058 0059 /** @brief Builds the MLT playlist, can only be done after MLT is correctly initialized */ 0060 void buildPlaylist(const QUuid uuid); 0061 0062 /** @brief Returns a clip from the hierarchy, given its id */ 0063 std::shared_ptr<ProjectClip> getClipByBinID(const QString &binId); 0064 /** @brief Returns audio levels for a clip from its id */ 0065 const QVector <uint8_t>getAudioLevelsByBinID(const QString &binId, int stream); 0066 double getAudioMaxLevel(const QString &binId, int stream); 0067 0068 /** @brief Returns a list of clips using the given url */ 0069 QStringList getClipByUrl(const QFileInfo &url) const; 0070 0071 /** @brief Helper to check whether a clip with a given id exists */ 0072 bool hasClip(const QString &binId); 0073 0074 /** @brief Gets a folder by its id. If none is found, nullptr is returned */ 0075 std::shared_ptr<ProjectFolder> getFolderByBinId(const QString &binId); 0076 /** @brief Gets a list of all folders in this project */ 0077 QList <std::shared_ptr<ProjectFolder> > getFolders(); 0078 /** @brief Gets a id folder by its name. If none is found, empty string returned */ 0079 const QString getFolderIdByName(const QString &folderName); 0080 0081 /** @brief Gets any item by its id. */ 0082 std::shared_ptr<AbstractProjectItem> getItemByBinId(const QString &binId); 0083 0084 /** @brief This function change the global enabled state of the bin effects */ 0085 void setBinEffectsEnabled(bool enabled); 0086 0087 /** @brief Returns some info about the folder containing the given index */ 0088 QStringList getEnclosingFolderInfo(const QModelIndex &index) const; 0089 0090 /** @brief Deletes all element and start a fresh model */ 0091 void clean(); 0092 0093 /** @brief Returns the id of all the clips (excluding folders) */ 0094 std::vector<QString> getAllClipIds() const; 0095 0096 /** @brief Updates the list of all created bin thumbnails */ 0097 void updateCacheThumbnail(std::unordered_map<QString, std::vector<int>> &thumbData); 0098 0099 /** @brief Convenience method to access root folder */ 0100 std::shared_ptr<ProjectFolder> getRootFolder() const; 0101 0102 void loadSubClips(const QString &id, const QString &dataMap, Fun &undo, Fun &redo); 0103 0104 /** @brief Convenience method to retrieve a pointer to an element given its index */ 0105 std::shared_ptr<AbstractProjectItem> getBinItemByIndex(const QModelIndex &index) const; 0106 0107 /** @brief Load the folders given the property containing them */ 0108 bool loadFolders(Mlt::Properties &folders, std::unordered_map<QString, QString> &binIdCorresp); 0109 0110 /** @brief Parse a bin playlist from the document tractor and reconstruct the tree 0111 * @return A list of invalid sequence clips found in Project Bin (can be caused by 23.04.0 bug) 0112 */ 0113 QList<QUuid> loadBinPlaylist(Mlt::Service *documentTractor, std::unordered_map<QString, QString> &binIdCorresp, QStringList &expandedFolders, 0114 const QUuid &activeUuid, int &zoomLevel); 0115 void loadTractorPlaylist(Mlt::Tractor documentTractor, std::unordered_map<QString, QString> &binIdCorresp); 0116 0117 /** @brief Save document properties in MLT's bin playlist */ 0118 void saveDocumentProperties(const QMap<QString, QString> &props, const QMap<QString, QString> &metadata); 0119 0120 /** @brief Save a property to main bin */ 0121 void saveProperty(const QString &name, const QString &value); 0122 0123 /** @brief Returns item data depending on role requested */ 0124 QVariant data(const QModelIndex &index, int role) const override; 0125 /** @brief Called when user edits an item */ 0126 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; 0127 /** @brief Allow selection and drag & drop */ 0128 Qt::ItemFlags flags(const QModelIndex &index) const override; 0129 /** @brief Returns column names in case we want to use columns in QTreeView */ 0130 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 0131 /** @brief Mandatory reimplementation from QAbstractItemModel */ 0132 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0133 /** @brief Returns the MIME type used for Drag actions */ 0134 QStringList mimeTypes() const override; 0135 /** @brief Create data that will be used for Drag events */ 0136 QMimeData *mimeData(const QModelIndexList &indices) const override; 0137 /** @brief Set size for thumbnails */ 0138 void setIconSize(QSize s); 0139 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; 0140 Qt::DropActions supportedDropActions() const override; 0141 0142 /** @brief Request deletion of a bin clip from the project bin 0143 @param clip : pointer to the clip to delete 0144 @param undo,redo: lambdas that are updated to accumulate operation. 0145 */ 0146 bool requestBinClipDeletion(const std::shared_ptr<AbstractProjectItem> &clip, Fun &undo, Fun &redo); 0147 0148 /** @brief Request creation of a bin folder 0149 @param id Id of the requested bin. If this is empty or invalid (already used, for example), it will be used as a return parameter to give the automatic 0150 bin id used. 0151 @param name Name of the folder 0152 @param parentId Bin id of the parent folder 0153 @param undo,redo: lambdas that are updated to accumulate operation. 0154 */ 0155 bool requestAddFolder(QString &id, const QString &name, const QString &parentId, Fun &undo, Fun &redo); 0156 /** @brief Request creation of a bin clip 0157 @param id Id of the requested bin. If this is empty, it will be used as a return parameter to give the automatic bin id used. 0158 @param description Xml description of the clip 0159 @param parentId Bin id of the parent folder 0160 @param undo,redo: lambdas that are updated to accumulate operation. 0161 @param readyCallBack: lambda that will be executed when the clip becomes ready. It is given the binId as parameter 0162 */ 0163 bool requestAddBinClip(QString &id, const QDomElement &description, const QString &parentId, Fun &undo, Fun &redo, 0164 const std::function<void(const QString &)> &readyCallBack = [](const QString &) {}); 0165 bool requestAddBinClip(QString &id, const QDomElement &description, const QString &parentId, const QString &undoText = QString(), const std::function<void(const QString &)> &readyCallBack = [](const QString &) {}); 0166 0167 /** @brief This is the addition function when we already have a producer for the clip*/ 0168 bool requestAddBinClip( 0169 QString &id, std::shared_ptr<Mlt::Producer> &producer, const QString &parentId, Fun &undo, Fun &redo, 0170 const std::function<void(const QString &)> &readyCallBack = [](const QString &) {}); 0171 0172 /** @brief Create a subClip 0173 @param id Id of the requested bin. If this is empty, it will be used as a return parameter to give the automatic bin id used. 0174 @param parentId Bin id of the parent clip 0175 @param in,out : zone that corresponds to the subclip 0176 @param undo,redo: lambdas that are updated to accumulate operation. 0177 */ 0178 bool requestAddBinSubClip(QString &id, int in, int out, const QMap<QString, QString> &zoneProperties, const QString &parentId, Fun &undo, Fun &redo); 0179 bool requestAddBinSubClip(QString &id, int in, int out, const QMap<QString, QString> &zoneProperties, const QString &parentId); 0180 0181 /** @brief Request that a folder's name is changed 0182 @param clip : pointer to the folder to rename 0183 @param name: new name of the folder 0184 @param undo,redo: lambdas that are updated to accumulate operation. 0185 */ 0186 bool requestRenameFolder(const std::shared_ptr<AbstractProjectItem> &folder, const QString &name, Fun &undo, Fun &redo); 0187 /* Same functions but pushes the undo object directly */ 0188 bool requestRenameFolder(std::shared_ptr<AbstractProjectItem> folder, const QString &name); 0189 0190 /** @brief Request that the unused clips are deleted */ 0191 bool requestCleanupUnused(); 0192 0193 /** @brief Request that all clips using one of the given urls are removed from the project and deleted from the hard disk*/ 0194 bool requestTrashClips(QStringList &ids, QStringList &urls); 0195 0196 /** @brief Retrieves the next id available for attribution to a folder */ 0197 int getFreeFolderId(); 0198 0199 /** @brief Retrieves the next id available for attribution to a clip */ 0200 int getFreeClipId(); 0201 0202 /** @brief Check whether a given id is currently used or not*/ 0203 bool isIdFree(const QString &id) const; 0204 0205 /** @brief Retrieve a list of proxy/original urls */ 0206 QMap<QString, QString> getProxies(const QString &root); 0207 0208 /** @brief Request that the producer of a given clip is reloaded */ 0209 void reloadClip(const QString &binId); 0210 0211 /** @brief Set the status of the clip to "waiting". This happens when the corresponding file has changed*/ 0212 void setClipWaiting(const QString &binId); 0213 void setClipInvalid(const QString &binId); 0214 0215 /** @brief Returns true if current project has a clip with id \@clipId and a hash of \@clipHash */ 0216 bool validateClip(const QString &binId, const QString &clipHash); 0217 /** @brief Returns clip id if folder "folderId" has a clip with hash of "clipHash" or empty if not found */ 0218 QString validateClipInFolder(const QString &folderId, const QString &clipHash); 0219 0220 /** @brief Number of clips in the bin playlist */ 0221 int clipsCount() const; 0222 /** @brief Returns true if we have proxied clips in the project */ 0223 bool hasProxies() const; 0224 /** @brief Get a secondary timeline tractor by its uuid */ 0225 std::shared_ptr<Mlt::Tractor> getExtraTimeline(const QString &uuid); 0226 void setExtraTimelineSaved(const QString &uuid); 0227 /** @brief Check if a file is already in Bin */ 0228 bool urlExists(const QString &path) const; 0229 /** @brief Returns the unique uuid for this project item model */ 0230 QUuid uuid() const { return m_uuid; }; 0231 /** @brief Retrieve the Bin clip id from a sequence uuid */ 0232 const QString getSequenceId(const QUuid &uuid); 0233 /** @brief Check if we already have a sequence with this uuid */ 0234 bool hasSequenceId(const QUuid &uuid) const; 0235 /** @brief Return a project sequence clip from its uuid */ 0236 std::shared_ptr<ProjectClip> getSequenceClip(const QUuid &uuid); 0237 /** @brief Returns uuid / bin id of all sequence clips in the project */ 0238 QMap<QUuid, QString> getAllSequenceClips() const; 0239 /** @brief Return the main project tractor (container of all playlists) */ 0240 std::shared_ptr<Mlt::Tractor> projectTractor(); 0241 const QString sceneList(const QString &root, const QString &fullPath, const QString &filterData, Mlt::Tractor *activeTractor, int duration); 0242 /** @brief Ensure that sequence @destUuid is not embedded in any dependency of sequence @srcUuid */ 0243 bool canBeEmbeded(const QUuid destUuid, const QUuid srcUuid); 0244 /** @brief Store a newly created sequence tractor for reuse */ 0245 void storeSequence(const QString uuid, std::shared_ptr<Mlt::Tractor> tractor, bool internalSave = true); 0246 /** @brief Returns the count of sequences in this project */ 0247 int sequenceCount() const; 0248 /** @brief The id of the folder where new sequences will be created, -1 if none */ 0249 int defaultSequencesFolder() const; 0250 void setSequencesFolder(int id); 0251 /** @brief The id of the folder where new audio captures will be created, -1 if none */ 0252 int defaultAudioCaptureFolder() const; 0253 void setAudioCaptureFolder(int id); 0254 /** @brief Remove clip references for a timeline. */ 0255 void removeReferencedClips(const QUuid &uuid, bool onDeletion); 0256 /** @brief Check that all sequences are correctly stored in the model */ 0257 void checkSequenceIntegrity(const QString activeSequenceId); 0258 std::shared_ptr<EffectStackModel> getClipEffectStack(int itemId); 0259 0260 protected: 0261 bool closing; 0262 /** @brief Register the existence of a new element 0263 */ 0264 void registerItem(const std::shared_ptr<TreeItem> &item) override; 0265 /** @brief Deregister the existence of a new element*/ 0266 void deregisterItem(int id, TreeItem *item) override; 0267 0268 /** @brief Helper function to generate a lambda that rename a folder */ 0269 Fun requestRenameFolder_lambda(const std::shared_ptr<AbstractProjectItem> &folder, const QString &newName); 0270 0271 /** @brief Helper function to add a given item to the tree */ 0272 bool addItem(const std::shared_ptr<AbstractProjectItem> &item, const QString &parentId, Fun &undo, Fun &redo); 0273 0274 /** @brief Function to be called when the url of a clip changes */ 0275 void updateWatcher(const std::shared_ptr<ProjectClip> &item); 0276 0277 public Q_SLOTS: 0278 /** @brief An item in the list was modified, notify */ 0279 void onItemUpdated(const std::shared_ptr<AbstractProjectItem> &item, const QVector<int> &roles); 0280 void onItemUpdated(const QString &binId, int role); 0281 0282 void setDragType(PlaylistState::ClipState type); 0283 /** @brief Create the subclips defined in the parent clip. 0284 @param id is the id of the parent clip 0285 @param data is a definition of the subclips (keys are subclips' names, value are "in:out")*/ 0286 void loadSubClips(const QString &id, const QString &clipData, bool logUndo); 0287 0288 private Q_SLOTS: 0289 /** @brief Check how many invalid clips we have. */ 0290 void slotUpdateInvalidCount(); 0291 0292 private: 0293 /** @brief Return reference to column specific data */ 0294 int mapToColumn(int column) const; 0295 /** @brief Return column number(s) responsible for a specific data type*/ 0296 QList<int> mapDataToColumn(AbstractProjectItem::DataType type) const; 0297 0298 mutable QReadWriteLock m_lock; // This is a lock that ensures safety in case of concurrent access 0299 0300 std::unique_ptr<BinPlaylist> m_binPlaylist; 0301 0302 std::unique_ptr<FileWatcher> m_fileWatcher; 0303 std::unordered_map<QString, std::shared_ptr<Mlt::Tractor>> m_extraPlaylists; 0304 std::shared_ptr<Mlt::Tractor> m_projectTractor; 0305 std::map<int, std::shared_ptr<ProjectClip>> m_allClipItems; 0306 QList<int> m_allIds; 0307 0308 int m_nextId; 0309 QIcon m_blankThumb; 0310 PlaylistState::ClipState m_dragType; 0311 QUuid m_uuid; 0312 /** @brief The id of the folder where new sequences will be created, -1 if none */ 0313 int m_sequenceFolderId; 0314 /** @brief The id of the folder where new audio captures will be created, -1 if none */ 0315 int m_audioCaptureFolderId; 0316 /** @brief Remove an item from the project */ 0317 Fun removeProjectItem_lambda(int binId, int id); 0318 0319 Q_SIGNALS: 0320 /** @brief thumbs of the given clip were modified, request update of the monitor if need be */ 0321 void refreshAudioThumbs(const QString &id); 0322 void refreshClip(const QString &id); 0323 void emitMessage(const QString &, int, MessageType); 0324 void refreshPanel(const QString &id); 0325 void requestAudioThumbs(const QString &id, long duration); 0326 // TODO 0327 void markersNeedUpdate(const QString &id, const QList<int> &); 0328 void itemDropped(const QStringList, const QModelIndex); 0329 void urlsDropped(const QList<QUrl>, const QModelIndex); 0330 void effectDropped(const QStringList &, const QModelIndex &); 0331 void addTag(const QString &, const QModelIndex &); 0332 void addClipCut(const QString &, int, int); 0333 void resetPlayOrLoopZone(const QString &id); 0334 };