File indexing completed on 2024-04-28 08:43:24
0001 /* 0002 SPDX-FileCopyrightText: 2020 Sashmita Raghav 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #pragma once 0007 0008 #include "bin/bin.h" 0009 #include "definitions.h" 0010 #include "undohelper.hpp" 0011 #include "utils/gentime.h" 0012 0013 #include <QAbstractListModel> 0014 #include <QReadWriteLock> 0015 0016 #include <array> 0017 #include <map> 0018 #include <memory> 0019 #include <mlt++/Mlt.h> 0020 #include <mlt++/MltProperties.h> 0021 #include <unordered_set> 0022 0023 class DocUndoStack; 0024 class SnapInterface; 0025 class AssetParameterModel; 0026 class TimelineItemModel; 0027 0028 /** @class SubtitleModel 0029 @brief This class is the model for a list of subtitles. 0030 */ 0031 class SubtitleModel : public QAbstractListModel 0032 { 0033 Q_OBJECT 0034 0035 public: 0036 static const int RAZOR_MODE_DUPLICATE = 0; 0037 static const int RAZOR_MODE_AFTER_FIRST_LINE = 1; 0038 0039 /** @brief Construct a subtitle list bound to the timeline */ 0040 explicit SubtitleModel(std::shared_ptr<TimelineItemModel> timeline = nullptr, 0041 const std::weak_ptr<SnapInterface> &snapModel = std::weak_ptr<SnapInterface>(), QObject *parent = nullptr); 0042 0043 enum { SubtitleRole = Qt::UserRole + 1, StartPosRole, EndPosRole, StartFrameRole, EndFrameRole, IdRole, SelectedRole, GrabRole }; 0044 /** @brief Function that parses through a subtitle file */ 0045 bool addSubtitle(int id, GenTime start, GenTime end, const QString &str, bool temporary = false, bool updateFilter = true); 0046 bool addSubtitle(GenTime start, GenTime end, const QString &str, Fun &undo, Fun &redo, bool updateFilter = true); 0047 /** @brief Converts string of time to GenTime */ 0048 GenTime stringtoTime(QString &str, const double factor = 1.); 0049 /** @brief Return model data item according to the role passed */ 0050 QVariant data(const QModelIndex &index, int role) const override; 0051 QHash<int, QByteArray> roleNames() const override; // override the same function of QAbstractListModel 0052 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0053 0054 /** @brief Returns all subtitles in the model */ 0055 QList<SubtitledTime> getAllSubtitles() const; 0056 0057 /** @brief Get subtitle at position */ 0058 SubtitledTime getSubtitle(GenTime startFrame) const; 0059 /** @brief Returns all subtitle ids in a range */ 0060 std::unordered_set<int> getItemsInRange(int startFrame, int endFrame) const; 0061 0062 /** @brief Registers a snap model to the subtitle model */ 0063 void registerSnap(const std::weak_ptr<SnapInterface> &snapModel); 0064 0065 /** @brief Edit subtitle end timing 0066 @param startPos is start timing position of subtitles 0067 @param oldPos is the old position of the end time 0068 @param pos defines the new position of the end time 0069 */ 0070 void editEndPos(GenTime startPos, GenTime newEndPos, bool refreshModel = true); 0071 bool requestResize(int id, int size, bool right); 0072 bool requestResize(int id, int size, bool right, Fun &undo, Fun &redo, bool logUndo); 0073 0074 /** @brief Edit subtitle text 0075 @param id the model id of the subtitle 0076 @param newSubtitleText is (new) subtitle text 0077 */ 0078 bool editSubtitle(int id, const QString &newSubtitleText); 0079 0080 /** @brief Remove subtitle at start position (pos) */ 0081 bool removeSubtitle(int id, bool temporary = false, bool updateFilter = true); 0082 0083 /** @brief Remove all subtitles from subtitle model */ 0084 void removeAllSubtitles(); 0085 0086 /** @brief Update some properties in the view */ 0087 void updateSub(int id, const QVector<int> &roles); 0088 0089 /** @brief Move an existing subtitle 0090 @param subId is the subtitle's ID 0091 @param newPos is new start position of subtitle 0092 */ 0093 bool moveSubtitle(int subId, GenTime newPos, bool updateModel, bool updateView); 0094 void requestSubtitleMove(int clipId, GenTime position); 0095 0096 /** @brief Guess the text encoding of the file at the provided path 0097 * @param file The path to the text file 0098 * @return The name of the text encoding, as guessed by KEncodingProber, or 0099 * "" if an error occurred 0100 */ 0101 static QByteArray guessFileEncoding(const QString &file, bool *confidence); 0102 /** @brief Function that imports a subtitle file */ 0103 void importSubtitle(const QString &filePath, int offset = 0, bool externalImport = false, float startFramerate = 30.00, float targetFramerate = 30.00, const QByteArray &encoding = "UTF-8"); 0104 0105 /** @brief Exports the subtitle model to json */ 0106 QString toJson(); 0107 /** @brief Returns the path to sub file */ 0108 const QString getUrl(); 0109 /** @brief Get a subtitle Id from its start position*/ 0110 int getIdForStartPos(GenTime startTime) const; 0111 /** @brief Get the duration of a subtitle by id*/ 0112 int getSubtitlePlaytime(int id) const; 0113 int getSubtitleEnd(int id) const; 0114 /** @brief Mark the subtitle item as selected or not*/ 0115 void setSelected(int id, bool select); 0116 bool isSelected(int id) const; 0117 /** @brief Cut a subtitle */ 0118 bool cutSubtitle(int position); 0119 /** @brief Cut a subtitle, return the id of newly created subtitle */ 0120 int cutSubtitle(int position, Fun &undo, Fun &redo); 0121 QString getText(int id) const; 0122 int getRowForId(int id) const; 0123 GenTime getStartPosForId(int id) const; 0124 int getPreviousSub(int id) const; 0125 int getNextSub(int id) const; 0126 /** @brief Copy subtitle file to a new path 0127 * @param path the new subtitle path 0128 * @param checkOverwrite if true, warn before overwriting an existing subtitle file 0129 * @param updateFilter if true, the subtitle filter will be updated to us the new name, useful when saving the project file */ 0130 void copySubtitle(const QString &path, int ix, bool checkOverwrite, bool updateFilter = false); 0131 /** @brief Use the tmp work file for the subtitle filter after saving the project */ 0132 void restoreTmpFile(int ix); 0133 int trackDuration() const; 0134 void switchDisabled(); 0135 bool isDisabled() const; 0136 void switchLocked(); 0137 bool isLocked() const; 0138 /** @brief Load some subtitle filter properties from file */ 0139 void loadProperties(const QMap<QString, QString> &subProperties); 0140 /** @brief Add all subtitle items to snaps */ 0141 void allSnaps(std::vector<int> &snaps); 0142 /** @brief Returns an xml representation of the subtitle with id \@sid */ 0143 QDomElement toXml(int sid, QDomDocument &document); 0144 /** @brief Returns the position of the first blank frame before a position */ 0145 int getBlankStart(int pos) const; 0146 /** @brief Returns the position of the first subtitle after the blank at @position */ 0147 int getBlankEnd(int pos) const; 0148 /** @brief Returns the duration of the blank at @position */ 0149 int getBlankSizeAtPos(int frame) const; 0150 /** @brief If pos is blank, returns the position of the blank start. Otherwise returns the position of the next blank frame */ 0151 int getNextBlankStart(int pos) const; 0152 /** @brief Returns true is track is empty at pos */ 0153 bool isBlankAt(int pos) const; 0154 /** @brief Switch a subtitle's grab state */ 0155 void switchGrab(int sid); 0156 /** @brief Ungrab all items */ 0157 void clearGrab(); 0158 /** @brief Release timeline model pointer */ 0159 void unsetModel(); 0160 /** @brief Get in/out of a subtitle item */ 0161 QPair<int, int> getInOut(int sid) const; 0162 /** @brief Set subtitle style (font, color, etc) */ 0163 void setStyle(const QString &style); 0164 const QString getStyle() const; 0165 void subtitleFileFromZone(int in, int out, const QString &outFile); 0166 /** @brief Edit the subtitle text*/ 0167 Q_INVOKABLE void editSubtitle(int id, const QString &newText, const QString &oldText); 0168 /** @brief Edit the subtitle end */ 0169 Q_INVOKABLE void resizeSubtitle(int startFrame, int endFrame, int oldEndFrame, bool refreshModel); 0170 /** @brief Add subtitle clip at cursor's position in timeline */ 0171 Q_INVOKABLE void addSubtitle(int startframe = -1, QString text = QString()); 0172 /** @brief Delete subtitle clip with frame as start position*/ 0173 Q_INVOKABLE void deleteSubtitle(int frameframe, int endframe, const QString &text); 0174 /** @brief Cut a subtitle and split the text at \@param pos */ 0175 void doCutSubtitle(int id, int cursorPos); 0176 /** @brief Return a list of the existing subtitles in this model */ 0177 QMap<std::pair<int, QString>, QString> getSubtitlesList() const; 0178 /** @brief Load the current subtitles list in this model */ 0179 void setSubtitlesList(QMap<std::pair<int, QString>, QString> list); 0180 /** @brief Update a subtitle name */ 0181 void updateModelName(int ix, const QString &name); 0182 /** @brief Create a new subtitle track and return its subtitle index */ 0183 int createNewSubtitle(const QString subtitleName = QString(), int id = -1); 0184 bool deleteSubtitle(int ix); 0185 void activateSubtitle(int ix); 0186 /** @brief Get JSON data for all subtitles in this model */ 0187 const QString subtitlesFilesToJson(); 0188 0189 public Q_SLOTS: 0190 /** @brief Function that parses through a subtitle file */ 0191 void parseSubtitle(const QString &workPath); 0192 0193 /** @brief Import model to a temporary subtitle file to which the Subtitle effect is applied*/ 0194 void jsontoSubtitle(const QString &data); 0195 /** @brief Update a subtitle text*/ 0196 bool setText(int id, const QString &text); 0197 0198 private: 0199 std::shared_ptr<TimelineItemModel> m_timeline; 0200 std::weak_ptr<DocUndoStack> m_undoStack; 0201 /** @brief A list of subtitles as: start time, text, end time */ 0202 std::map<GenTime, std::pair<QString, GenTime>> m_subtitleList; 0203 /** @brief A list of all available subtitle files for this timeline 0204 * in the form: ({id, name}, path) where id for a subtitle never changes 0205 */ 0206 QMap<std::pair<int, QString>, QString> m_subtitlesList; 0207 QString scriptInfoSection, styleSection, eventSection; 0208 QString styleName; 0209 0210 // To get subtitle file from effects parameter: 0211 // std::unique_ptr<Mlt::Properties> m_asset; 0212 // std::shared_ptr<AssetParameterModel> m_model; 0213 0214 std::vector<std::weak_ptr<SnapInterface>> m_regSnaps; 0215 mutable QReadWriteLock m_lock; 0216 std::unique_ptr<Mlt::Filter> m_subtitleFilter; 0217 QVector<int> m_selected; 0218 QVector<int> m_grabbedIds; 0219 int saveSubtitleData(const QString &data, const QString &outFile); 0220 0221 Q_SIGNALS: 0222 void modelChanged(); 0223 void updateSubtitleStyle(const QString); 0224 0225 protected: 0226 /** @brief Add time as snap in the registered snap model */ 0227 void addSnapPoint(GenTime startpos); 0228 /** @brief Remove time as snap in the registered snap model */ 0229 void removeSnapPoint(GenTime startpos); 0230 /** @brief Connect changes in model with signal */ 0231 void setup(); 0232 }; 0233 Q_DECLARE_METATYPE(SubtitleModel *)