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 SUBTITLELINE_H
9 #define SUBTITLELINE_H
10
11 #include "core/time.h"
12 #include "core/formatdata.h"
13 #include "core/subtitletarget.h"
14 #include "helpers/objectref.h"
15
16 #include <QExplicitlySharedDataPointer>
17 #include <QObject>
18 #include <QString>
19
20 class QUndoCommand;
21
22 namespace SubtitleComposer {
23 class Subtitle;
24 class SString;
25 class RichDocument;
26 class UndoAction;
27
28 class SubtitleLine : public QObject
29 {
30 Q_OBJECT
31
32 friend class Subtitle;
33 friend class SubtitleAction;
34 friend class SwapLinesTextsAction;
35 friend class SubtitleLineAction;
36 friend class SetLinePrimaryTextAction;
37 friend class SetLineSecondaryTextAction;
38 friend class SetLineTextsAction;
39 friend class SetLineShowTimeAction;
40 friend class SetLineHideTimeAction;
41 friend class SetLineTimesAction;
42 friend class SetLineStyleFlagsAction;
43 friend class SetLineErrorsAction;
44 friend class ToggleLineMarkedAction;
45 friend class Format;
46 friend class ObjectRef<SubtitleLine>;
47
48 public:
49 typedef enum {
50 EmptyPrimaryTextID = 0, // Empty primary text
51 EmptySecondaryTextID, // Empty secondary text
52 MaxPrimaryCharsID, // Too many characters in primary text
53 MaxSecondaryCharsID, // Too many characters in secondary text
54 MaxPrimaryLinesID, // Too many line breaks in primary text
55 MaxSecondaryLinesID, // Too many line breaks in secondary text
56 PrimaryUnneededSpacesID, // Unnecessary spaces in primary text
57 SecondaryUnneededSpacesID, // Unnecessary spaces in secondary text
58 PrimaryUnneededDashID, // Unnecessary dash (-) in primary text
59 SecondaryUnneededDashID, // Unnecessary dash (-) in secondary text
60 PrimaryCapitalAfterEllipsisID, // Capital letter after ellipsis in primary text
61 SecondaryCapitalAfterEllipsisID, // Capital letter after ellipsis in secondary text
62 MinDurationPerPrimaryCharID, // Too short duration per primary text character
63 MinDurationPerSecondaryCharID, // Too short duration per secondary text character
64 MaxDurationPerPrimaryCharID, // Too long duration per primary text character
65 MaxDurationPerSecondaryCharID, // Too long duration per secondary text character
66 MinDurationID, // Too short duration
67 MaxDurationID, // Too long duration
68 OverlapsWithNextID, // Overlaps with next line
69 UntranslatedTextID, // Primary and translation text are the same
70 UserMarkID,
71 ErrorSIZE,
72 ErrorUNKNOWN
73 } ErrorID;
74
75 typedef enum {
76 EmptyPrimaryText = 0x1 << EmptyPrimaryTextID,
77 EmptySecondaryText = 0x1 << EmptySecondaryTextID,
78 MaxPrimaryChars = 0x1 << MaxPrimaryCharsID,
79 MaxSecondaryChars = 0x1 << MaxSecondaryCharsID,
80 MaxPrimaryLines = 0x1 << MaxPrimaryLinesID,
81 MaxSecondaryLines = 0x1 << MaxSecondaryLinesID,
82 PrimaryUnneededSpaces = 0x1 << PrimaryUnneededSpacesID,
83 SecondaryUnneededSpaces = 0x1 << SecondaryUnneededSpacesID,
84 PrimaryUnneededDash = 0x1 << PrimaryUnneededDashID,
85 SecondaryUnneededDash = 0x1 << SecondaryUnneededDashID,
86 PrimaryCapitalAfterEllipsis = 0x1 << PrimaryCapitalAfterEllipsisID,
87 SecondaryCapitalAfterEllipsis = 0x1 << SecondaryCapitalAfterEllipsisID,
88 MinDurationPerPrimaryChar = 0x1 << MinDurationPerPrimaryCharID,
89 MinDurationPerSecondaryChar = 0x1 << MinDurationPerSecondaryCharID,
90 MaxDurationPerPrimaryChar = 0x1 << MaxDurationPerPrimaryCharID,
91 MaxDurationPerSecondaryChar = 0x1 << MaxDurationPerSecondaryCharID,
92 MinDuration = 0x1 << MinDurationID,
93 MaxDuration = 0x1 << MaxDurationID,
94 OverlapsWithNext = 0x1 << OverlapsWithNextID,
95 UntranslatedText = 0x1 << UntranslatedTextID,
96 UserMark = 0x1 << UserMarkID,
97
98 PrimaryOnlyErrors = EmptyPrimaryText | MaxPrimaryChars | MaxPrimaryLines | PrimaryUnneededSpaces | PrimaryUnneededDash | PrimaryCapitalAfterEllipsis | MinDurationPerPrimaryChar | MaxDurationPerPrimaryChar,
99
100 SecondaryOnlyErrors = EmptySecondaryText | MaxSecondaryChars | MaxSecondaryLines | SecondaryUnneededSpaces | SecondaryUnneededDash | SecondaryCapitalAfterEllipsis | MinDurationPerSecondaryChar | MaxDurationPerSecondaryChar | UntranslatedText,
101
102 SharedErrors = MinDuration | MaxDuration | OverlapsWithNext | UserMark,
103
104 AllErrors = PrimaryOnlyErrors | SecondaryOnlyErrors | SharedErrors,
105
106 TimesErrors = MinDuration | MaxDuration | MinDurationPerPrimaryChar | MinDurationPerSecondaryChar | MaxDurationPerPrimaryChar | MaxDurationPerSecondaryChar | OverlapsWithNext,
107
108 TextErrors = EmptyPrimaryText | EmptySecondaryText | MaxPrimaryChars | MaxSecondaryChars | MaxPrimaryLines | MaxSecondaryLines | PrimaryUnneededSpaces | SecondaryUnneededSpaces | PrimaryUnneededDash | SecondaryUnneededDash | PrimaryCapitalAfterEllipsis | SecondaryCapitalAfterEllipsis | MinDurationPerPrimaryChar | MinDurationPerSecondaryChar | MaxDurationPerPrimaryChar | MaxDurationPerSecondaryChar | UntranslatedText
109 } ErrorFlag;
110
111 static int bitsCount(unsigned int bitFlags);
112
113 static ErrorFlag errorFlag(ErrorID id);
114 static ErrorID errorID(ErrorFlag flag);
115
116 static const QString & simpleErrorText(SubtitleLine::ErrorFlag errorFlag);
117 static const QString & simpleErrorText(SubtitleLine::ErrorID errorID);
118
119 QString fullErrorText(SubtitleLine::ErrorFlag errorFlag) const;
120 QString fullErrorText(SubtitleLine::ErrorID errorID) const;
121
122 SubtitleLine();
123 SubtitleLine(const Time &showTime, const Time &hideTime);
124 SubtitleLine(const SubtitleLine &line) = delete;
125 SubtitleLine & operator=(const SubtitleLine &line) = delete;
126 virtual ~SubtitleLine();
127
128 int number() const;
129 int index() const;
130
subtitle()131 inline Subtitle * subtitle() { return m_subtitle.data(); }
subtitle()132 inline const Subtitle * subtitle() const { return m_subtitle.constData(); }
133
134 inline SubtitleLine * prevLine() const;
135 inline SubtitleLine * nextLine() const;
136
primaryDoc()137 inline RichDocument * primaryDoc() const { return m_primaryDoc; }
secondaryDoc()138 inline RichDocument * secondaryDoc() const { return m_secondaryDoc; }
139
140 void breakText(int minBreakLength, SubtitleTarget target);
141 void unbreakText(SubtitleTarget target);
142 void simplifyTextWhiteSpace(SubtitleTarget target);
143
showTime()144 inline Time showTime() const { return m_showTime; }
145 void setShowTime(const Time &showTime);
146
hideTime()147 inline Time hideTime() const { return m_hideTime; }
148 void setHideTime(const Time &hideTime);
149
duration()150 inline double duration() const { return m_hideTime.toMillis() - m_showTime.toMillis(); }
durationTime()151 inline Time durationTime() const { return Time(duration()); }
setDurationTime(const Time & durationTime)152 inline void setDurationTime(const Time &durationTime) { setHideTime(m_showTime + durationTime); }
153 QColor durationColor(const QColor &textColor, bool usePrimary=true);
154
pauseTime()155 inline Time pauseTime() const { const SubtitleLine *p = prevLine(); return Time(showTime().toMillis() - (p ? p->hideTime().toMillis() : 0.)); }
156
157 void setTimes(const Time &showTime, const Time &hideTime);
158
containsTime(const Time & time)159 inline bool containsTime(const Time &time) const { return m_showTime <= time && time <= m_hideTime; }
intersectsTimespan(const Time & start,const Time & end)160 inline bool intersectsTimespan(const Time &start, const Time &end) const { return m_showTime <= end && start <= m_hideTime; }
161
162 int primaryCharacters() const;
163 int primaryWords() const;
164 int primaryLines() const;
165
166 int secondaryCharacters() const;
167 int secondaryWords() const;
168 int secondaryLines() const;
169
170 static Time autoDuration(const QString &text, int msecsPerChar, int msecsPerWord, int msecsPerLine);
171 Time autoDuration(int msecsPerChar, int msecsPerWord, int msecsPerLine, SubtitleTarget calculationTarget);
172
173 void shiftTimes(long mseconds);
174 void adjustTimes(double shiftMseconds, double scaleFactor);
175
176 int errorFlags() const;
177 int errorCount() const;
178 void setErrorFlags(int errorFlags);
179 void setErrorFlags(int errorFlags, bool value);
180
181 bool checkEmptyPrimaryText(bool update = true);
182 bool checkEmptySecondaryText(bool update = true);
183 bool checkUntranslatedText(bool update = true);
184 bool checkOverlapsWithNext(bool update = true);
185
186 bool checkMinDuration(int minMsecs, bool update = true);
187 bool checkMaxDuration(int maxMsecs, bool update = true);
188
189 bool checkMinDurationPerPrimaryChar(int minMsecsPerChar, bool update = true);
190 bool checkMinDurationPerSecondaryChar(int minMsecsPerChar, bool update = true);
191 bool checkMaxDurationPerPrimaryChar(int maxMsecsPerChar, bool update = true);
192 bool checkMaxDurationPerSecondaryChar(int maxMsecsPerChar, bool update = true);
193
194 bool checkMaxPrimaryChars(int maxCharacters, bool update = true);
195 bool checkMaxSecondaryChars(int maxCharacters, bool update = true);
196 bool checkMaxPrimaryLines(int maxLines, bool update = true);
197 bool checkMaxSecondaryLines(int maxLines, bool update = true);
198
199 bool checkPrimaryUnneededSpaces(bool update = true);
200 bool checkSecondaryUnneededSpaces(bool update = true);
201 bool checkPrimaryCapitalAfterEllipsis(bool update = true);
202 bool checkSecondaryCapitalAfterEllipsis(bool update = true);
203 bool checkPrimaryUnneededDash(bool update = true);
204 bool checkSecondaryUnneededDash(bool update = true);
205
206 int check(int errorFlagsToCheck, bool update = true);
207
208 signals:
209 void primaryTextChanged();
210 void secondaryTextChanged();
211 void showTimeChanged(const Time &showTime);
212 void hideTimeChanged(const Time &hideTime);
213 void errorFlagsChanged(int errorFlags);
214
215 private:
216 FormatData * formatData() const;
217 void setFormatData(const FormatData *formatData);
218
219 void processAction(UndoAction *action);
220 void processShowTimeSort(const Time &showTime);
221
222 void setPrimaryDoc(RichDocument *doc);
223 void setSecondaryDoc(RichDocument *doc);
224 void setTexts(RichDocument *pText, RichDocument *sText);
225 void primaryDocumentChanged();
226 void secondaryDocumentChanged();
227
228 void setupSignals();
229
ignoreDocChanges(bool ignore)230 inline bool ignoreDocChanges(bool ignore) {
231 bool r = m_ignoreDocChanges;
232 m_ignoreDocChanges = ignore;
233 return r;
234 }
235
236 private:
237 QExplicitlySharedDataPointer<Subtitle> m_subtitle;
238 RichDocument *m_primaryDoc;
239 RichDocument *m_secondaryDoc;
240 Time m_showTime;
241 Time m_hideTime;
242 int m_errorFlags;
243 bool m_ignoreDocChanges = false;
244
245 FormatData *m_formatData;
246
247 mutable ObjectRef<SubtitleLine> *m_ref = nullptr;
248 const QVector<ObjectRef<SubtitleLine>> * refContainer();
249 };
250 }
251
252 #include "core/subtitle.h"
253
254 namespace SubtitleComposer {
255
256 inline SubtitleLine *
prevLine()257 SubtitleLine::prevLine() const
258 {
259 return m_subtitle ? m_subtitle->line(index() - 1) : nullptr;
260 }
261
262 inline SubtitleLine *
nextLine()263 SubtitleLine::nextLine() const
264 {
265 return m_subtitle ? m_subtitle->line(index() + 1) : nullptr;
266 }
267
268 }
269
270 #endif
271