1 /* This file is part of the KDE project
2 * Copyright (C) 2006 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
4 * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "KoTextBlockData.h"
23
24 #include "KoTextBlockBorderData.h"
25 #include "KoTextBlockPaintStrategyBase.h"
26
27 class Q_DECL_HIDDEN KoTextBlockData::Private : public QTextBlockUserData
28 {
29 public:
Private()30 Private()
31 : counterWidth(-1.0)
32 , counterSpacing(0)
33 , counterIsImage(false)
34 , counterIndex(1)
35 , border(0)
36 , paintStrategy(0)
37 {
38 layoutedMarkupRanges[KoTextBlockData::Misspell] = false;
39 layoutedMarkupRanges[KoTextBlockData::Grammar] = false;
40 }
41
~Private()42 ~Private() override {
43 if (border && !border->deref())
44 delete border;
45 delete paintStrategy;
46 }
47 qreal counterWidth;
48 qreal counterSpacing;
49 QString counterPrefix;
50 QString counterPlainText;
51 QString counterSuffix;
52 QString partialCounterText;
53 bool counterIsImage;
54 int counterIndex;
55 QPointF counterPos;
56 QTextCharFormat labelFormat;
57 KoTextBlockBorderData *border;
58 KoTextBlockPaintStrategyBase *paintStrategy;
59 QMap<KoTextBlockData::MarkupType, QList<MarkupRange> > markupRangesMap;
60 QMap<KoTextBlockData::MarkupType, bool> layoutedMarkupRanges;
61 };
62
KoTextBlockData(QTextBlock & block)63 KoTextBlockData::KoTextBlockData(QTextBlock &block)
64 : d(block.userData() ? dynamic_cast<KoTextBlockData::Private *>(block.userData())
65 : new Private())
66 {
67 block.setUserData(d);
68 }
69
KoTextBlockData(QTextBlockUserData * userData)70 KoTextBlockData::KoTextBlockData(QTextBlockUserData *userData)
71 : d(dynamic_cast<KoTextBlockData::Private *>(userData))
72 {
73 Q_ASSERT(d);
74 }
75
~KoTextBlockData()76 KoTextBlockData::~KoTextBlockData()
77 {
78 // explicitly do not delete the d-pointer here
79 }
80
81
appendMarkup(MarkupType type,int firstChar,int lastChar)82 void KoTextBlockData::appendMarkup(MarkupType type, int firstChar, int lastChar)
83 {
84 Q_ASSERT(d->markupRangesMap[type].isEmpty() || d->markupRangesMap[type].last().lastChar < firstChar);
85
86 MarkupRange range;
87 range.firstChar = firstChar;
88 range.lastChar = lastChar;
89 d->layoutedMarkupRanges[type] = false;
90
91 d->markupRangesMap[type].append(range);
92 }
93
clearMarkups(MarkupType type)94 void KoTextBlockData::clearMarkups(MarkupType type)
95 {
96 d->markupRangesMap[type].clear();
97 d->layoutedMarkupRanges[type] = false;
98 }
99
findMarkup(MarkupType type,int positionWithin) const100 KoTextBlockData::MarkupRange KoTextBlockData::findMarkup(MarkupType type, int positionWithin) const
101 {
102 foreach (const MarkupRange &range, d->markupRangesMap[type]) {
103 if (positionWithin <= range.lastChar) {
104 // possible hit
105 if (positionWithin >= range.firstChar) {
106 return range;
107 } else {
108 return MarkupRange(); // we have passed it without finding
109 }
110 }
111 }
112 return MarkupRange(); // either no ranges or not in last either
113 }
114
rebaseMarkups(MarkupType type,int fromPosition,int delta)115 void KoTextBlockData::rebaseMarkups(MarkupType type, int fromPosition, int delta)
116 {
117 QList<MarkupRange>::Iterator markIt = markupsBegin(type);
118 QList<MarkupRange>::Iterator markEnd = markupsEnd(type);
119 while (markIt != markEnd) {
120 if (fromPosition <= markIt->lastChar) {
121 // we need to modify the end of this
122 markIt->lastChar += delta;
123 }
124 if (fromPosition < markIt->firstChar) {
125 // we need to modify the end of this
126 markIt->firstChar += delta;
127 }
128 ++markIt;
129 }
130 }
131
setMarkupsLayoutValidity(MarkupType type,bool valid)132 void KoTextBlockData::setMarkupsLayoutValidity(MarkupType type, bool valid)
133 {
134 d->layoutedMarkupRanges[type] = valid;
135 }
136
isMarkupsLayoutValid(MarkupType type) const137 bool KoTextBlockData::isMarkupsLayoutValid(MarkupType type) const
138 {
139 return d->layoutedMarkupRanges[type];
140 }
141
markupsBegin(MarkupType type)142 QList<KoTextBlockData::MarkupRange>::Iterator KoTextBlockData::markupsBegin(MarkupType type)
143 {
144 return d->markupRangesMap[type].begin();
145 }
146
markupsEnd(MarkupType type)147 QList<KoTextBlockData::MarkupRange>::Iterator KoTextBlockData::markupsEnd(MarkupType type)
148 {
149 return d->markupRangesMap[type].end();
150 }
151
hasCounterData() const152 bool KoTextBlockData::hasCounterData() const
153 {
154 return d->counterWidth >= 0 && (!d->counterPlainText.isNull() || d->counterIsImage);
155 }
156
counterWidth() const157 qreal KoTextBlockData::counterWidth() const
158 {
159 return qMax(qreal(0), d->counterWidth);
160 }
161
setBorder(KoTextBlockBorderData * border)162 void KoTextBlockData::setBorder(KoTextBlockBorderData *border)
163 {
164 if (d->border && !d->border->deref())
165 delete d->border;
166 d->border = border;
167 if (d->border)
168 d->border->ref();
169 }
170
setCounterWidth(qreal width)171 void KoTextBlockData::setCounterWidth(qreal width)
172 {
173 d->counterWidth = width;
174 }
175
counterSpacing() const176 qreal KoTextBlockData::counterSpacing() const
177 {
178 return d->counterSpacing;
179 }
180
setCounterSpacing(qreal spacing)181 void KoTextBlockData::setCounterSpacing(qreal spacing)
182 {
183 d->counterSpacing = spacing;
184 }
185
counterText() const186 QString KoTextBlockData::counterText() const
187 {
188 return d->counterPrefix + d->counterPlainText + d->counterSuffix;
189 }
190
clearCounter()191 void KoTextBlockData::clearCounter()
192 {
193 d->partialCounterText.clear();
194 d->counterPlainText.clear();
195 d->counterPrefix.clear();
196 d->counterSuffix.clear();
197 d->counterSpacing = 0.0;
198 d->counterWidth = 0.0;
199 d->counterIsImage = false;
200 }
201
setPartialCounterText(const QString & text)202 void KoTextBlockData::setPartialCounterText(const QString &text)
203 {
204 d->partialCounterText = text;
205 }
206
partialCounterText() const207 QString KoTextBlockData::partialCounterText() const
208 {
209 return d->partialCounterText;
210 }
211
setCounterPlainText(const QString & text)212 void KoTextBlockData::setCounterPlainText(const QString &text)
213 {
214 d->counterPlainText = text;
215 }
216
counterPlainText() const217 QString KoTextBlockData::counterPlainText() const
218 {
219 return d->counterPlainText;
220 }
221
setCounterPrefix(const QString & text)222 void KoTextBlockData::setCounterPrefix(const QString &text)
223 {
224 d->counterPrefix = text;
225 }
226
counterPrefix() const227 QString KoTextBlockData::counterPrefix() const
228 {
229 return d->counterPrefix;
230 }
231
setCounterSuffix(const QString & text)232 void KoTextBlockData::setCounterSuffix(const QString &text)
233 {
234 d->counterSuffix = text;
235 }
236
counterSuffix() const237 QString KoTextBlockData::counterSuffix() const
238 {
239 return d->counterSuffix;
240 }
241
setCounterIsImage(bool isImage)242 void KoTextBlockData::setCounterIsImage(bool isImage)
243 {
244 d->counterIsImage = isImage;
245 }
246
counterIsImage() const247 bool KoTextBlockData::counterIsImage() const
248 {
249 return d->counterIsImage;
250 }
251
setCounterIndex(int index)252 void KoTextBlockData::setCounterIndex(int index)
253 {
254 d->counterIndex = index;
255 }
256
counterIndex() const257 int KoTextBlockData::counterIndex() const
258 {
259 return d->counterIndex;
260 }
261
setCounterPosition(const QPointF & position)262 void KoTextBlockData::setCounterPosition(const QPointF &position)
263 {
264 d->counterPos = position;
265 }
266
counterPosition() const267 QPointF KoTextBlockData::counterPosition() const
268 {
269 return d->counterPos;
270 }
271
setLabelFormat(const QTextCharFormat & format)272 void KoTextBlockData::setLabelFormat(const QTextCharFormat &format)
273 {
274 d->labelFormat = format;
275 }
276
labelFormat() const277 QTextCharFormat KoTextBlockData::labelFormat() const
278 {
279 return d->labelFormat;
280 }
281
border() const282 KoTextBlockBorderData *KoTextBlockData::border() const
283 {
284 return d->border;
285 }
286
setPaintStrategy(KoTextBlockPaintStrategyBase * paintStrategy)287 void KoTextBlockData::setPaintStrategy(KoTextBlockPaintStrategyBase *paintStrategy)
288 {
289 delete d->paintStrategy;
290 d->paintStrategy = paintStrategy;
291 }
292
paintStrategy() const293 KoTextBlockPaintStrategyBase *KoTextBlockData::paintStrategy() const
294 {
295 return d->paintStrategy;
296 }
297
saveXmlID() const298 bool KoTextBlockData::saveXmlID() const
299 {
300 // as suggested by boemann, https://marc.info/?l=calligra-devel&m=132396354701553&w=2
301 return d->paintStrategy != 0;
302 }
303