File indexing completed on 2024-12-22 04:40:05
0001 /* 0002 SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar> 0003 SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef SUBTITLE_H 0009 #define SUBTITLE_H 0010 0011 #include "core/range.h" 0012 #include "core/rangelist.h" 0013 #include "core/time.h" 0014 #include "core/richstring.h" 0015 #include "core/subtitletarget.h" 0016 #include "core/undo/undostack.h" 0017 #include "helpers/objectref.h" 0018 #include "formatdata.h" 0019 0020 #include <QObject> 0021 #include <QString> 0022 #include <QStringList> 0023 #include <QList> 0024 #include <QMap> 0025 0026 QT_FORWARD_DECLARE_CLASS(QUndoCommand) 0027 QT_FORWARD_DECLARE_CLASS(QTextEdit) 0028 0029 namespace SubtitleComposer { 0030 class RichDocument; 0031 class SubtitleLine; 0032 class UndoAction; 0033 class RichCSS; 0034 0035 class Subtitle : public QObject, public QSharedData 0036 { 0037 Q_OBJECT 0038 0039 friend class UndoStack; 0040 0041 friend class SubtitleLine; 0042 friend class SubtitleIterator; 0043 0044 friend class UndoAction; 0045 0046 friend class SubtitleAction; 0047 friend class SetFramesPerSecondAction; 0048 friend class InsertLinesAction; 0049 friend class RemoveLinesAction; 0050 friend class MoveLineAction; 0051 friend class EditStylesheetAction; 0052 0053 friend class SubtitleLineAction; 0054 friend class SetLinePrimaryTextAction; 0055 friend class SetLineSecondaryTextAction; 0056 friend class SetLineTextsAction; 0057 friend class SetLineShowTimeAction; 0058 friend class SetLineHideTimeAction; 0059 friend class SetLineTimesAction; 0060 friend class SetLineErrorsAction; 0061 friend class ToggleLineMarkedAction; 0062 0063 friend class SubtitleCompositeActionExecutor; 0064 0065 friend class Format; 0066 friend class InputFormat; 0067 0068 public: 0069 static double defaultFramesPerSecond(); 0070 static void setDefaultFramesPerSecond(double framesPerSecond); 0071 0072 Subtitle(double framesPerSecond = defaultFramesPerSecond()); 0073 virtual ~Subtitle(); 0074 0075 /// primary data includes primary text, timing information, format data and all errors except secondary only errors 0076 void setPrimaryData(const Subtitle &from, bool usePrimaryData); 0077 void clearPrimaryTextData(); 0078 0079 /// secondary data includes secondary text and secondary only errors 0080 void setSecondaryData(const Subtitle &from, bool usePrimaryData); 0081 void clearSecondaryTextData(); 0082 0083 inline bool isPrimaryDirty() const { return m_primaryDirtyState; } 0084 void clearPrimaryDirty(); 0085 0086 inline bool isSecondaryDirty() const { return m_secondaryDirtyState; } 0087 void clearSecondaryDirty(); 0088 0089 double framesPerSecond() const; 0090 void setFramesPerSecond(double framesPerSecond); 0091 void changeFramesPerSecond(double toFramesPerSecond, double fromFramesPerSecond = -1.0); 0092 0093 bool isEmpty() const { return m_lines.empty(); } 0094 int linesCount() const { return m_lines.count(); } 0095 int lastIndex() const { return m_lines.count() - 1; } 0096 0097 SubtitleLine * line(int index); 0098 const SubtitleLine * line(int index) const; 0099 0100 inline SubtitleLine * firstLine() { return m_lines.isEmpty() ? nullptr : m_lines.first().obj(); } 0101 inline const SubtitleLine * firstLine() const { return m_lines.isEmpty() ? nullptr : m_lines.first().obj(); } 0102 0103 inline SubtitleLine * lastLine() { return m_lines.isEmpty() ? nullptr : m_lines.last().obj(); } 0104 inline const SubtitleLine * lastLine() const { return m_lines.isEmpty() ? nullptr : m_lines.last().obj(); } 0105 0106 inline int count() const { return m_lines.size(); } 0107 inline const SubtitleLine * at(const int i) const { return m_lines.at(i).obj(); } 0108 inline SubtitleLine * at(const int i) { return m_lines.at(i).obj(); } 0109 inline const SubtitleLine * operator[](const int i) const { return m_lines.at(i).obj(); } 0110 inline SubtitleLine * operator[](const int i) { return m_lines.at(i).obj(); } 0111 0112 // inline const QVector<ObjectRef<SubtitleLine>> & allLines() const { return m_lines; } 0113 0114 // inline const QList<const SubtitleLine *> & anchoredLines() const { return m_anchoredLines; } 0115 0116 bool hasAnchors() const; 0117 bool isLineAnchored(int index) const; 0118 bool isLineAnchored(const SubtitleLine *line) const; 0119 void toggleLineAnchor(int index); 0120 void toggleLineAnchor(const SubtitleLine *line); 0121 void removeAllAnchors(); 0122 0123 void insertLine(SubtitleLine *line); 0124 SubtitleLine * insertNewLine(int index, bool timeAfter, SubtitleTarget target); 0125 void removeLines(const RangeList &ranges, SubtitleTarget target); 0126 0127 void swapTexts(const RangeList &ranges); 0128 0129 void splitLines(const RangeList &ranges); 0130 void joinLines(const RangeList &ranges); 0131 0132 void shiftAnchoredLine(SubtitleLine *anchoredLine, const Time &newShowTime); 0133 0134 void shiftLines(const RangeList &ranges, long msecs); 0135 void adjustLines(const Range &range, long firstTime, long lastTime); 0136 void sortLines(const Range &range); 0137 0138 void applyDurationLimits(const RangeList &ranges, const Time &minDuration, const Time &maxDuration, bool canOverlap); 0139 void setMaximumDurations(const RangeList &ranges); 0140 void setAutoDurations(const RangeList &ranges, int msecsPerChar, int msecsPerWord, int msecsPerLine, bool canOverlap, SubtitleTarget calculationTarget); 0141 0142 void fixOverlappingLines(const RangeList &ranges, const Time &minInterval = 100); 0143 0144 void fixPunctuation(const RangeList &ranges, bool spaces, bool quotes, bool englishI, bool ellipsis, SubtitleTarget target); 0145 0146 void lowerCase(const RangeList &ranges, SubtitleTarget target); 0147 void upperCase(const RangeList &ranges, SubtitleTarget target); 0148 void titleCase(const RangeList &ranges, bool lowerFirst, SubtitleTarget target); 0149 void sentenceCase(const RangeList &ranges, bool lowerFirst, SubtitleTarget target); 0150 0151 void breakLines(const RangeList &ranges, unsigned minLengthForLineBreak, SubtitleTarget target); 0152 void unbreakTexts(const RangeList &ranges, SubtitleTarget target); 0153 void simplifyTextWhiteSpace(const RangeList &ranges, SubtitleTarget target); 0154 0155 void syncWithSubtitle(const Subtitle &refSubtitle); 0156 void appendSubtitle(const Subtitle &srcSubtitle, double shiftMsecsBeforeAppend); 0157 void splitSubtitle(Subtitle &dstSubtitle, const Time &splitTime, bool shiftSplitLines); 0158 0159 void toggleStyleFlag(const RangeList &ranges, RichString::StyleFlag styleFlag); 0160 void changeTextColor(const RangeList &ranges, QRgb color); 0161 0162 void setMarked(const RangeList &ranges, bool value); 0163 void toggleMarked(const RangeList &ranges); 0164 0165 void clearErrors(const RangeList &ranges, int errorFlags); 0166 void checkErrors(const RangeList &ranges, int errorFlags); 0167 void recheckErrors(const RangeList &ranges); 0168 0169 inline bool metaExists(const QByteArray &key) const { return m_metaData.contains(key); } 0170 inline int metaRemove(const QByteArray &key) { return m_metaData.remove(key); } 0171 inline const QString meta(const QByteArray &key) const { return m_metaData.value(key); } 0172 inline void meta(const QByteArray &key, const QString &value) { m_metaData.insert(key, value); } 0173 0174 void stylesheetEdit(QTextEdit *textEdit); 0175 void stylesheetAppend(const QString &css); 0176 void stylesheetClear(); 0177 inline const RichCSS *stylesheet() const { return m_stylesheet; } 0178 0179 signals: 0180 void primaryChanged(); 0181 void secondaryChanged(); 0182 0183 void primaryDirtyStateChanged(bool dirty); 0184 void secondaryDirtyStateChanged(bool dirty); 0185 0186 void framesPerSecondChanged(double fps); 0187 void linesAboutToBeInserted(int firstIndex, int lastIndex); 0188 void linesInserted(int firstIndex, int lastIndex); 0189 void linesAboutToBeRemoved(int firstIndex, int lastIndex); 0190 void linesRemoved(int firstIndex, int lastIndex); 0191 0192 void compositeActionStart(); 0193 void compositeActionEnd(); 0194 0195 void lineAnchorChanged(const SubtitleLine *line, bool anchored); 0196 0197 /// forwarded line signals 0198 void linePrimaryTextChanged(SubtitleLine *line); 0199 void lineSecondaryTextChanged(SubtitleLine *line); 0200 void lineShowTimeChanged(SubtitleLine *line); 0201 void lineHideTimeChanged(SubtitleLine *line); 0202 void lineErrorFlagsChanged(SubtitleLine *line); 0203 void lineMarkChanged(SubtitleLine *line); 0204 0205 private: 0206 inline int insertIndex(const Time &showTime) const { return insertIndex(showTime, 0, m_lines.isEmpty() ? 0 : m_lines.count() - 1); } 0207 int insertIndex(const Time &showTime, int start, int end) const; 0208 void insertLine(SubtitleLine *line, int index); 0209 0210 FormatData * formatData() const; 0211 void setFormatData(const FormatData *formatData); 0212 0213 void beginCompositeAction(const QString &title) const; 0214 void endCompositeAction(UndoStack::DirtyMode dirtyOverride = UndoStack::Invalid) const; 0215 void processAction(UndoAction *action) const; 0216 0217 bool isPrimaryDirty(int index) const; 0218 bool isSecondaryDirty(int index) const; 0219 void updateState(); 0220 0221 inline int normalizeRangeIndex(int index) const { return index >= m_lines.count() ? m_lines.count() - 1 : index; } 0222 0223 inline SubtitleLine * takeAt(const int i) { SubtitleLine *s = m_lines.at(i).obj(); m_lines.remove(i); return s; } 0224 0225 inline bool ignoreDocChanges(bool ignore) { 0226 bool r = m_ignoreDocChanges; 0227 m_ignoreDocChanges = ignore; 0228 return r; 0229 } 0230 0231 private: 0232 bool m_primaryDirtyState; 0233 int m_primaryCleanIndex; 0234 bool m_secondaryDirtyState; 0235 int m_secondaryCleanIndex; 0236 0237 bool m_ignoreDocChanges = false; 0238 0239 double m_framesPerSecond; 0240 mutable QVector<ObjectRef<SubtitleLine>> m_lines; 0241 QList<const SubtitleLine *> m_anchoredLines; 0242 0243 QMap<QByteArray, QString> m_metaData; 0244 0245 RichCSS *m_stylesheet; 0246 0247 FormatData *m_formatData; 0248 0249 static double s_defaultFramesPerSecond; 0250 }; 0251 0252 class SubtitleCompositeActionExecutor 0253 { 0254 public: 0255 SubtitleCompositeActionExecutor(const Subtitle *subtitle, const QString &title); 0256 ~SubtitleCompositeActionExecutor(); 0257 0258 private: 0259 const Subtitle *m_subtitle; 0260 }; 0261 } 0262 0263 #include "subtitleline.h" 0264 0265 #endif