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