1 /*
2 SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar>
3 SPDX-FileCopyrightText: 2010-2018 Mladen Milinkovic <max@smoothware.net>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #ifndef SUBTITLE_H
9 #define SUBTITLE_H
10
11 #include "core/range.h"
12 #include "core/rangelist.h"
13 #include "core/time.h"
14 #include "core/sstring.h"
15 #include "core/subtitletarget.h"
16 #include "core/undo/undostack.h"
17 #include "helpers/objectref.h"
18 #include "formatdata.h"
19
20 #include <QObject>
21 #include <QString>
22 #include <QStringList>
23 #include <QList>
24
QT_FORWARD_DECLARE_CLASS(QUndoCommand)25 QT_FORWARD_DECLARE_CLASS(QUndoCommand)
26
27 namespace SubtitleComposer {
28 class RichDocument;
29 class SubtitleLine;
30 class UndoAction;
31
32 class Subtitle : public QObject, public QSharedData
33 {
34 Q_OBJECT
35
36 friend class UndoStack;
37
38 friend class SubtitleLine;
39 friend class SubtitleIterator;
40
41 friend class UndoAction;
42
43 friend class SubtitleAction;
44 friend class SetFramesPerSecondAction;
45 friend class InsertLinesAction;
46 friend class RemoveLinesAction;
47 friend class MoveLineAction;
48
49 friend class SubtitleLineAction;
50 friend class SetLinePrimaryTextAction;
51 friend class SetLineSecondaryTextAction;
52 friend class SetLineTextsAction;
53 friend class SetLineShowTimeAction;
54 friend class SetLineHideTimeAction;
55 friend class SetLineTimesAction;
56 friend class SetLineErrorsAction;
57 friend class ToggleLineMarkedAction;
58
59 friend class SubtitleCompositeActionExecutor;
60
61 friend class Format;
62 friend class InputFormat;
63
64 public:
65 static double defaultFramesPerSecond();
66 static void setDefaultFramesPerSecond(double framesPerSecond);
67
68 Subtitle(double framesPerSecond = defaultFramesPerSecond());
69 virtual ~Subtitle();
70
71 /// primary data includes primary text, timing information, format data and all errors except secondary only errors
72 void setPrimaryData(const Subtitle &from, bool usePrimaryData);
73 void clearPrimaryTextData();
74
75 /// secondary data includes secondary text and secondary only errors
76 void setSecondaryData(const Subtitle &from, bool usePrimaryData);
77 void clearSecondaryTextData();
78
79 inline bool isPrimaryDirty() const { return m_primaryDirtyState; }
80 void clearPrimaryDirty();
81
82 inline bool isSecondaryDirty() const { return m_secondaryDirtyState; }
83 void clearSecondaryDirty();
84
85 double framesPerSecond() const;
86 void setFramesPerSecond(double framesPerSecond);
87 void changeFramesPerSecond(double toFramesPerSecond, double fromFramesPerSecond = -1.0);
88
89 bool isEmpty() const { return m_lines.empty(); }
90 int linesCount() const { return m_lines.count(); }
91 int lastIndex() const { return m_lines.count() - 1; }
92
93 SubtitleLine * line(int index);
94 const SubtitleLine * line(int index) const;
95
96 inline SubtitleLine * firstLine() { return m_lines.isEmpty() ? nullptr : m_lines.first().obj(); }
97 inline const SubtitleLine * firstLine() const { return m_lines.isEmpty() ? nullptr : m_lines.first().obj(); }
98
99 inline SubtitleLine * lastLine() { return m_lines.isEmpty() ? nullptr : m_lines.last().obj(); }
100 inline const SubtitleLine * lastLine() const { return m_lines.isEmpty() ? nullptr : m_lines.last().obj(); }
101
102 inline int count() const { return m_lines.size(); }
103 inline const SubtitleLine * at(const int i) const { return m_lines.at(i).obj(); }
104 inline SubtitleLine * at(const int i) { return m_lines.at(i).obj(); }
105 inline const SubtitleLine * operator[](const int i) const { return m_lines.at(i).obj(); }
106 inline SubtitleLine * operator[](const int i) { return m_lines.at(i).obj(); }
107
108 // inline const QVector<ObjectRef<SubtitleLine>> & allLines() const { return m_lines; }
109
110 // inline const QList<const SubtitleLine *> & anchoredLines() const { return m_anchoredLines; }
111
112 bool hasAnchors() const;
113 bool isLineAnchored(int index) const;
114 bool isLineAnchored(const SubtitleLine *line) const;
115 void toggleLineAnchor(int index);
116 void toggleLineAnchor(const SubtitleLine *line);
117 void removeAllAnchors();
118
119 void insertLine(SubtitleLine *line);
120 SubtitleLine * insertNewLine(int index, bool timeAfter, SubtitleTarget target);
121 void removeLines(const RangeList &ranges, SubtitleTarget target);
122
123 void swapTexts(const RangeList &ranges);
124
125 void splitLines(const RangeList &ranges);
126 void joinLines(const RangeList &ranges);
127
128 void shiftAnchoredLine(SubtitleLine *anchoredLine, const Time &newShowTime);
129
130 void shiftLines(const RangeList &ranges, long msecs);
131 void adjustLines(const Range &range, long firstTime, long lastTime);
132 void sortLines(const Range &range);
133
134 void applyDurationLimits(const RangeList &ranges, const Time &minDuration, const Time &maxDuration, bool canOverlap);
135 void setMaximumDurations(const RangeList &ranges);
136 void setAutoDurations(const RangeList &ranges, int msecsPerChar, int msecsPerWord, int msecsPerLine, bool canOverlap, SubtitleTarget calculationTarget);
137
138 void fixOverlappingLines(const RangeList &ranges, const Time &minInterval = 100);
139
140 void fixPunctuation(const RangeList &ranges, bool spaces, bool quotes, bool englishI, bool ellipsis, SubtitleTarget target);
141
142 void lowerCase(const RangeList &ranges, SubtitleTarget target);
143 void upperCase(const RangeList &ranges, SubtitleTarget target);
144 void titleCase(const RangeList &ranges, bool lowerFirst, SubtitleTarget target);
145 void sentenceCase(const RangeList &ranges, bool lowerFirst, SubtitleTarget target);
146
147 void breakLines(const RangeList &ranges, unsigned minLengthForLineBreak, SubtitleTarget target);
148 void unbreakTexts(const RangeList &ranges, SubtitleTarget target);
149 void simplifyTextWhiteSpace(const RangeList &ranges, SubtitleTarget target);
150
151 void syncWithSubtitle(const Subtitle &refSubtitle);
152 void appendSubtitle(const Subtitle &srcSubtitle, double shiftMsecsBeforeAppend);
153 void splitSubtitle(Subtitle &dstSubtitle, const Time &splitTime, bool shiftSplitLines);
154
155 void toggleStyleFlag(const RangeList &ranges, SString::StyleFlag styleFlag);
156 void changeTextColor(const RangeList &ranges, QRgb color);
157
158 void setMarked(const RangeList &ranges, bool value);
159 void toggleMarked(const RangeList &ranges);
160
161 void clearErrors(const RangeList &ranges, int errorFlags);
162 void checkErrors(const RangeList &ranges, int errorFlags);
163 void recheckErrors(const RangeList &ranges);
164
165 signals:
166 void primaryChanged();
167 void secondaryChanged();
168
169 void primaryDirtyStateChanged(bool dirty);
170 void secondaryDirtyStateChanged(bool dirty);
171
172 void framesPerSecondChanged(double fps);
173 void linesAboutToBeInserted(int firstIndex, int lastIndex);
174 void linesInserted(int firstIndex, int lastIndex);
175 void linesAboutToBeRemoved(int firstIndex, int lastIndex);
176 void linesRemoved(int firstIndex, int lastIndex);
177
178 void compositeActionStart();
179 void compositeActionEnd();
180
181 void lineAnchorChanged(const SubtitleLine *line, bool anchored);
182
183 /// forwarded line signals
184 void linePrimaryTextChanged(SubtitleLine *line);
185 void lineSecondaryTextChanged(SubtitleLine *line);
186 void lineShowTimeChanged(SubtitleLine *line);
187 void lineHideTimeChanged(SubtitleLine *line);
188 void lineErrorFlagsChanged(SubtitleLine *line);
189 void lineMarkChanged(SubtitleLine *line);
190
191 private:
192 inline int insertIndex(const Time &showTime) const { return insertIndex(showTime, 0, m_lines.isEmpty() ? 0 : m_lines.count() - 1); }
193 int insertIndex(const Time &showTime, int start, int end) const;
194 void insertLine(SubtitleLine *line, int index);
195
196 FormatData * formatData() const;
197 void setFormatData(const FormatData *formatData);
198
199 void beginCompositeAction(const QString &title) const;
200 void endCompositeAction(UndoStack::DirtyMode dirtyOverride = UndoStack::Invalid) const;
201 void processAction(UndoAction *action) const;
202
203 bool isPrimaryDirty(int index) const;
204 bool isSecondaryDirty(int index) const;
205 void updateState();
206
207 inline int normalizeRangeIndex(int index) const { return index >= m_lines.count() ? m_lines.count() - 1 : index; }
208
209 inline SubtitleLine * takeAt(const int i) { SubtitleLine *s = m_lines.at(i).obj(); m_lines.remove(i); return s; }
210
211 private:
212 bool m_primaryDirtyState;
213 int m_primaryCleanIndex;
214 bool m_secondaryDirtyState;
215 int m_secondaryCleanIndex;
216
217 double m_framesPerSecond;
218 mutable QVector<ObjectRef<SubtitleLine>> m_lines;
219 QList<const SubtitleLine *> m_anchoredLines;
220
221 FormatData *m_formatData;
222
223 static double s_defaultFramesPerSecond;
224 };
225
226 class SubtitleCompositeActionExecutor
227 {
228 public:
229 SubtitleCompositeActionExecutor(const Subtitle *subtitle, const QString &title);
230 ~SubtitleCompositeActionExecutor();
231
232 private:
233 const Subtitle *m_subtitle;
234 };
235 }
236
237 #include "subtitleline.h"
238
239 #endif
240