Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <comphelper/string.hxx>
21 : #include <vcl/wrkwin.hxx>
22 : #include <vcl/dialog.hxx>
23 : #include <vcl/msgbox.hxx>
24 : #include <vcl/svapp.hxx>
25 :
26 : #include <editeng/tstpitem.hxx>
27 : #include <editeng/colritem.hxx>
28 : #include <editeng/fontitem.hxx>
29 : #include <editeng/crossedoutitem.hxx>
30 : #include <editeng/fhgtitem.hxx>
31 : #include <editeng/flditem.hxx>
32 : #include <editeng/postitem.hxx>
33 : #include <editeng/kernitem.hxx>
34 : #include <editeng/wrlmitem.hxx>
35 : #include <editeng/wghtitem.hxx>
36 : #include <editeng/udlnitem.hxx>
37 : #include <editeng/cmapitem.hxx>
38 : #include <editeng/contouritem.hxx>
39 : #include <editeng/escapementitem.hxx>
40 : #include <editeng/shdditem.hxx>
41 : #include <editeng/autokernitem.hxx>
42 : #include <editeng/charsetcoloritem.hxx>
43 : #include <editeng/langitem.hxx>
44 : #include <editeng/emphasismarkitem.hxx>
45 : #include <editeng/charscaleitem.hxx>
46 : #include <editeng/charreliefitem.hxx>
47 : #include <editeng/xmlcnitm.hxx>
48 : #include <editeng/editids.hrc>
49 : #include "editeng/editdata.hxx"
50 : #include "editeng/lrspitem.hxx"
51 : #include "editeng/ulspitem.hxx"
52 : #include "editeng/lspcitem.hxx"
53 :
54 : #include <editdoc.hxx>
55 : #include <editdbg.hxx>
56 : #include <editeng/eerdll.hxx>
57 : #include <eerdll2.hxx>
58 : #include <impedit.hxx>
59 :
60 : #include <rtl/ustrbuf.hxx>
61 :
62 : #include <svl/grabbagitem.hxx>
63 : #include <tools/stream.hxx>
64 : #include <tools/debug.hxx>
65 : #include <com/sun/star/i18n/ScriptType.hpp>
66 :
67 : #include <cassert>
68 : #include <limits>
69 :
70 : #include <boost/bind.hpp>
71 :
72 : using namespace ::com::sun::star;
73 :
74 :
75 :
76 :
77 5059585 : sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, short nScriptType )
78 : {
79 5059585 : sal_uInt16 nId = nItemId;
80 :
81 5059585 : if ( ( nScriptType == i18n::ScriptType::ASIAN ) ||
82 : ( nScriptType == i18n::ScriptType::COMPLEX ) )
83 : {
84 0 : switch ( nItemId )
85 : {
86 : case EE_CHAR_LANGUAGE:
87 0 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
88 0 : break;
89 : case EE_CHAR_FONTINFO:
90 0 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
91 0 : break;
92 : case EE_CHAR_FONTHEIGHT:
93 0 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
94 0 : break;
95 : case EE_CHAR_WEIGHT:
96 0 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
97 0 : break;
98 : case EE_CHAR_ITALIC:
99 0 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
100 0 : break;
101 : }
102 : }
103 :
104 5059585 : return nId;
105 : }
106 :
107 871384 : bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
108 : {
109 871384 : bool bValid = true;
110 :
111 871384 : switch ( nItemId )
112 : {
113 : case EE_CHAR_LANGUAGE:
114 21254 : bValid = nScriptType == i18n::ScriptType::LATIN;
115 21254 : break;
116 : case EE_CHAR_LANGUAGE_CJK:
117 18158 : bValid = nScriptType == i18n::ScriptType::ASIAN;
118 18158 : break;
119 : case EE_CHAR_LANGUAGE_CTL:
120 19305 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
121 19305 : break;
122 : case EE_CHAR_FONTINFO:
123 43793 : bValid = nScriptType == i18n::ScriptType::LATIN;
124 43793 : break;
125 : case EE_CHAR_FONTINFO_CJK:
126 29594 : bValid = nScriptType == i18n::ScriptType::ASIAN;
127 29594 : break;
128 : case EE_CHAR_FONTINFO_CTL:
129 31558 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
130 31558 : break;
131 : case EE_CHAR_FONTHEIGHT:
132 63965 : bValid = nScriptType == i18n::ScriptType::LATIN;
133 63965 : break;
134 : case EE_CHAR_FONTHEIGHT_CJK:
135 42049 : bValid = nScriptType == i18n::ScriptType::ASIAN;
136 42049 : break;
137 : case EE_CHAR_FONTHEIGHT_CTL:
138 42729 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
139 42729 : break;
140 : case EE_CHAR_WEIGHT:
141 36337 : bValid = nScriptType == i18n::ScriptType::LATIN;
142 36337 : break;
143 : case EE_CHAR_WEIGHT_CJK:
144 30697 : bValid = nScriptType == i18n::ScriptType::ASIAN;
145 30697 : break;
146 : case EE_CHAR_WEIGHT_CTL:
147 31506 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
148 31506 : break;
149 : case EE_CHAR_ITALIC:
150 29443 : bValid = nScriptType == i18n::ScriptType::LATIN;
151 29443 : break;
152 : case EE_CHAR_ITALIC_CJK:
153 25615 : bValid = nScriptType == i18n::ScriptType::ASIAN;
154 25615 : break;
155 : case EE_CHAR_ITALIC_CTL:
156 24449 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
157 24449 : break;
158 : }
159 :
160 871384 : return bValid;
161 : }
162 :
163 :
164 :
165 :
166 : // Should later be moved to TOOLS/STRING (Current: 303)
167 : // for Grep: WS_TARGET
168 :
169 :
170 : const SfxItemInfo aItemInfos[EDITITEMCOUNT] = {
171 : { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE }, // EE_PARA_WRITINGDIR
172 : { 0, SFX_ITEM_POOLABLE }, // EE_PARA_XMLATTRIBS
173 : { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE }, // EE_PARA_HANGINGPUNCTUATION
174 : { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE },
175 : { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ASIANCJKSPACING
176 : { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE }, // EE_PARA_NUMBULL
177 : { 0, SFX_ITEM_POOLABLE }, // EE_PARA_HYPHENATE
178 : { 0, SFX_ITEM_POOLABLE }, // EE_PARA_BULLETSTATE
179 : { 0, SFX_ITEM_POOLABLE }, // EE_PARA_OUTLLRSPACE
180 : { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE }, // EE_PARA_OUTLLEVEL
181 : { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE }, // EE_PARA_BULLET
182 : { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_LRSPACE
183 : { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ULSPACE
184 : { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE }, // EE_PARA_SBL
185 : { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE }, // EE_PARA_JUST
186 : { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE }, // EE_PARA_TABS
187 : { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, SFX_ITEM_POOLABLE }, // EE_PARA_JUST_METHOD
188 : { SID_ATTR_ALIGN_VER_JUSTIFY, SFX_ITEM_POOLABLE }, // EE_PARA_VER_JUST
189 : { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE },
190 : { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE },
191 : { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE },
192 : { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE },
193 : { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE },
194 : { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE },
195 : { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE },
196 : { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE },
197 : { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE },
198 : { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE },
199 : { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE },
200 : { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE },
201 : { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE },
202 : { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE },
203 : { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE },
204 : { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE },
205 : { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE },
206 : { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE },
207 : { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE },
208 : { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE },
209 : { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE },
210 : { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE },
211 : { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE },
212 : { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE },
213 : { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE },
214 : { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE },
215 : { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE },
216 : { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_RUBI_DUMMY
217 : { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_XMLATTRIBS
218 : { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE },
219 : { SID_ATTR_CHAR_CASEMAP, SFX_ITEM_POOLABLE }, // EE_CHAR_CASEMAP
220 : { SID_ATTR_CHAR_GRABBAG, SFX_ITEM_POOLABLE }, // EE_CHAR_GRABBAG
221 : { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_TAB
222 : { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_LINEBR
223 : { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE }, // EE_FEATURE_NOTCONV
224 : { SID_FIELD, SFX_ITEM_POOLABLE }
225 : };
226 :
227 : const sal_uInt16 aV1Map[] = {
228 : 3999, 4001, 4002, 4003, 4004, 4005, 4006,
229 : 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019?
230 : };
231 :
232 : const sal_uInt16 aV2Map[] = {
233 : 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009,
234 : 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020
235 : };
236 :
237 : const sal_uInt16 aV3Map[] = {
238 : 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
239 : 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019,
240 : 4020, 4021
241 : };
242 :
243 : const sal_uInt16 aV4Map[] = {
244 : 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
245 : 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
246 : 4014, 4015, 4016, 4017, 4018,
247 : /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */
248 : 4034, 4035, 4036, 4037
249 : };
250 :
251 : const sal_uInt16 aV5Map[] = {
252 : 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
253 : 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
254 : 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023,
255 : 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033,
256 : /* EE_CHAR_OVERLINE inserted here */
257 : 4035, 4036, 4037, 4038
258 : };
259 :
260 : const sal_uInt16 aV6Map[] = {
261 : 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
262 : 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
263 : 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023,
264 : 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033,
265 : 4035, 4036, 4037, 4038,
266 : /* EE_CHAR_GRABBAG inserted here */
267 : 4039
268 : };
269 :
270 435042 : EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_Int32 nS, sal_Int32 nE )
271 : {
272 : // Create a new attribute in the pool
273 435042 : const SfxPoolItem& rNew = rPool.Put( rAttr );
274 :
275 435042 : EditCharAttrib* pNew = 0;
276 435042 : switch( rNew.Which() )
277 : {
278 : case EE_CHAR_LANGUAGE:
279 : case EE_CHAR_LANGUAGE_CJK:
280 : case EE_CHAR_LANGUAGE_CTL:
281 : {
282 44651 : pNew = new EditCharAttribLanguage( static_cast<const SvxLanguageItem&>(rNew), nS, nE );
283 : }
284 44651 : break;
285 : case EE_CHAR_COLOR:
286 : {
287 35561 : pNew = new EditCharAttribColor( static_cast<const SvxColorItem&>(rNew), nS, nE );
288 : }
289 35561 : break;
290 : case EE_CHAR_FONTINFO:
291 : case EE_CHAR_FONTINFO_CJK:
292 : case EE_CHAR_FONTINFO_CTL:
293 : {
294 63691 : pNew = new EditCharAttribFont( static_cast<const SvxFontItem&>(rNew), nS, nE );
295 : }
296 63691 : break;
297 : case EE_CHAR_FONTHEIGHT:
298 : case EE_CHAR_FONTHEIGHT_CJK:
299 : case EE_CHAR_FONTHEIGHT_CTL:
300 : {
301 87799 : pNew = new EditCharAttribFontHeight( static_cast<const SvxFontHeightItem&>(rNew), nS, nE );
302 : }
303 87799 : break;
304 : case EE_CHAR_FONTWIDTH:
305 : {
306 2852 : pNew = new EditCharAttribFontWidth( static_cast<const SvxCharScaleWidthItem&>(rNew), nS, nE );
307 : }
308 2852 : break;
309 : case EE_CHAR_WEIGHT:
310 : case EE_CHAR_WEIGHT_CJK:
311 : case EE_CHAR_WEIGHT_CTL:
312 : {
313 57232 : pNew = new EditCharAttribWeight( static_cast<const SvxWeightItem&>(rNew), nS, nE );
314 : }
315 57232 : break;
316 : case EE_CHAR_UNDERLINE:
317 : {
318 12715 : pNew = new EditCharAttribUnderline( static_cast<const SvxUnderlineItem&>(rNew), nS, nE );
319 : }
320 12715 : break;
321 : case EE_CHAR_OVERLINE:
322 : {
323 2362 : pNew = new EditCharAttribOverline( static_cast<const SvxOverlineItem&>(rNew), nS, nE );
324 : }
325 2362 : break;
326 : case EE_CHAR_EMPHASISMARK:
327 : {
328 3408 : pNew = new EditCharAttribEmphasisMark( static_cast<const SvxEmphasisMarkItem&>(rNew), nS, nE );
329 : }
330 3408 : break;
331 : case EE_CHAR_RELIEF:
332 : {
333 3368 : pNew = new EditCharAttribRelief( static_cast<const SvxCharReliefItem&>(rNew), nS, nE );
334 : }
335 3368 : break;
336 : case EE_CHAR_STRIKEOUT:
337 : {
338 10598 : pNew = new EditCharAttribStrikeout( static_cast<const SvxCrossedOutItem&>(rNew), nS, nE );
339 : }
340 10598 : break;
341 : case EE_CHAR_ITALIC:
342 : case EE_CHAR_ITALIC_CJK:
343 : case EE_CHAR_ITALIC_CTL:
344 : {
345 30458 : pNew = new EditCharAttribItalic( static_cast<const SvxPostureItem&>(rNew), nS, nE );
346 : }
347 30458 : break;
348 : case EE_CHAR_OUTLINE:
349 : {
350 4095 : pNew = new EditCharAttribOutline( static_cast<const SvxContourItem&>(rNew), nS, nE );
351 : }
352 4095 : break;
353 : case EE_CHAR_SHADOW:
354 : {
355 4180 : pNew = new EditCharAttribShadow( static_cast<const SvxShadowedItem&>(rNew), nS, nE );
356 : }
357 4180 : break;
358 : case EE_CHAR_ESCAPEMENT:
359 : {
360 10931 : pNew = new EditCharAttribEscapement( static_cast<const SvxEscapementItem&>(rNew), nS, nE );
361 : }
362 10931 : break;
363 : case EE_CHAR_PAIRKERNING:
364 : {
365 3248 : pNew = new EditCharAttribPairKerning( static_cast<const SvxAutoKernItem&>(rNew), nS, nE );
366 : }
367 3248 : break;
368 : case EE_CHAR_KERNING:
369 : {
370 9407 : pNew = new EditCharAttribKerning( static_cast<const SvxKerningItem&>(rNew), nS, nE );
371 : }
372 9407 : break;
373 : case EE_CHAR_WLM:
374 : {
375 3273 : pNew = new EditCharAttribWordLineMode( static_cast<const SvxWordLineModeItem&>(rNew), nS, nE );
376 : }
377 3273 : break;
378 : case EE_CHAR_XMLATTRIBS:
379 : {
380 2592 : pNew = new EditCharAttrib( rNew, nS, nE ); // Attribute is only for holding XML information...
381 : }
382 2592 : break;
383 : case EE_CHAR_CASEMAP:
384 : {
385 9293 : pNew = new EditCharAttribCaseMap( static_cast<const SvxCaseMapItem&>(rNew), nS, nE );
386 : }
387 9293 : break;
388 : case EE_CHAR_GRABBAG:
389 : {
390 1954 : pNew = new EditCharAttribGrabBag( static_cast<const SfxGrabBagItem&>(rNew), nS, nE );
391 : }
392 1954 : break;
393 : case EE_FEATURE_TAB:
394 : {
395 206 : pNew = new EditCharAttribTab( static_cast<const SfxVoidItem&>(rNew), nS );
396 : }
397 206 : break;
398 : case EE_FEATURE_LINEBR:
399 : {
400 186 : pNew = new EditCharAttribLineBreak( static_cast<const SfxVoidItem&>(rNew), nS );
401 : }
402 186 : break;
403 : case EE_FEATURE_FIELD:
404 : {
405 27879 : pNew = new EditCharAttribField( static_cast<const SvxFieldItem&>(rNew), nS );
406 : }
407 27879 : break;
408 : case EE_CHAR_BKGCOLOR:
409 : {
410 3103 : pNew = new EditCharAttribBackgroundColor( static_cast<const SvxBackgroundColorItem&>(rNew), nS, nE );
411 : }
412 3103 : break;
413 : default:
414 : {
415 : OSL_FAIL( "Invalid Attribute!" );
416 : }
417 : }
418 435042 : return pNew;
419 : }
420 :
421 453067 : TextPortionList::TextPortionList()
422 : {
423 453067 : }
424 :
425 905346 : TextPortionList::~TextPortionList()
426 : {
427 452673 : Reset();
428 452673 : }
429 :
430 494662 : void TextPortionList::Reset()
431 : {
432 494662 : maPortions.clear();
433 494662 : }
434 :
435 120439 : void TextPortionList::DeleteFromPortion(sal_Int32 nDelFrom)
436 : {
437 : DBG_ASSERT( ( nDelFrom < (sal_Int32)maPortions.size() ) || ( (nDelFrom == 0) && maPortions.empty() ), "DeleteFromPortion: Out of range" );
438 120439 : PortionsType::iterator it = maPortions.begin();
439 120439 : std::advance(it, nDelFrom);
440 120439 : maPortions.erase(it, maPortions.end());
441 120439 : }
442 :
443 1351470 : sal_Int32 TextPortionList::Count() const
444 : {
445 1351470 : return (sal_Int32)maPortions.size();
446 : }
447 :
448 59949 : const TextPortion* TextPortionList::operator[](sal_Int32 nPos) const
449 : {
450 59949 : return &maPortions[nPos];
451 : }
452 :
453 1509160 : TextPortion* TextPortionList::operator[](sal_Int32 nPos)
454 : {
455 1509160 : return &maPortions[nPos];
456 : }
457 :
458 348570 : void TextPortionList::Append(TextPortion* p)
459 : {
460 348570 : maPortions.push_back(p);
461 348570 : }
462 :
463 73294 : void TextPortionList::Insert(sal_Int32 nPos, TextPortion* p)
464 : {
465 73294 : maPortions.insert(maPortions.begin()+nPos, p);
466 73294 : }
467 :
468 0 : void TextPortionList::Remove(sal_Int32 nPos)
469 : {
470 0 : maPortions.erase(maPortions.begin()+nPos);
471 0 : }
472 :
473 : namespace {
474 :
475 : class FindTextPortionByAddress : std::unary_function<TextPortion, bool>
476 : {
477 : const TextPortion* mp;
478 : public:
479 0 : FindTextPortionByAddress(const TextPortion* p) : mp(p) {}
480 0 : bool operator() (const TextPortion& v) const
481 : {
482 0 : return &v == mp;
483 : }
484 : };
485 :
486 : }
487 :
488 0 : sal_Int32 TextPortionList::GetPos(const TextPortion* p) const
489 : {
490 : PortionsType::const_iterator it =
491 0 : std::find_if(maPortions.begin(), maPortions.end(), FindTextPortionByAddress(p));
492 :
493 0 : if (it == maPortions.end())
494 0 : return std::numeric_limits<sal_Int32>::max(); // not found.
495 :
496 0 : return std::distance(maPortions.begin(), it);
497 : }
498 :
499 3925 : sal_Int32 TextPortionList::FindPortion(
500 : sal_Int32 nCharPos, sal_Int32& nPortionStart, bool bPreferStartingPortion) const
501 : {
502 : // When nCharPos at portion limit, the left portion is found
503 3925 : sal_Int32 nTmpPos = 0;
504 3925 : sal_Int32 n = maPortions.size();
505 6159 : for (sal_Int32 i = 0; i < n; ++i)
506 : {
507 6159 : const TextPortion& rPortion = maPortions[i];
508 6159 : nTmpPos = nTmpPos + rPortion.GetLen();
509 6159 : if ( nTmpPos >= nCharPos )
510 : {
511 : // take this one if we don't prefer the starting portion, or if it's the last one
512 3925 : if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( i == n-1 ) )
513 : {
514 3925 : nPortionStart = nTmpPos - rPortion.GetLen();
515 3925 : return i;
516 : }
517 : }
518 : }
519 : OSL_FAIL( "FindPortion: Not found!" );
520 0 : return n - 1;
521 : }
522 :
523 0 : sal_Int32 TextPortionList::GetStartPos(sal_Int32 nPortion)
524 : {
525 0 : sal_Int32 nPos = 0;
526 0 : for (sal_Int32 i = 0; i < nPortion; ++i)
527 : {
528 0 : const TextPortion& rPortion = maPortions[i];
529 0 : nPos = nPos + rPortion.GetLen();
530 : }
531 0 : return nPos;
532 : }
533 :
534 0 : ExtraPortionInfo::ExtraPortionInfo()
535 : : nOrgWidth(0)
536 : , nWidthFullCompression(0)
537 : , nPortionOffsetX(0)
538 : , nMaxCompression100thPercent(0)
539 : , nAsianCompressionTypes(0)
540 : , bFirstCharIsRightPunktuation(false)
541 : , bCompressed(false)
542 : , pOrgDXArray(NULL)
543 0 : , lineBreaksList()
544 : {
545 0 : }
546 :
547 0 : ExtraPortionInfo::~ExtraPortionInfo()
548 : {
549 0 : delete[] pOrgDXArray;
550 0 : }
551 :
552 0 : void ExtraPortionInfo::SaveOrgDXArray( const long* pDXArray, sal_Int32 nLen )
553 : {
554 0 : delete[] pOrgDXArray;
555 0 : if (pDXArray)
556 : {
557 0 : pOrgDXArray = new long[nLen];
558 0 : memcpy( pOrgDXArray, pDXArray, nLen * sizeof(long) );
559 : }
560 : else
561 0 : pOrgDXArray = NULL;
562 0 : }
563 :
564 453067 : ParaPortion::ParaPortion( ContentNode* pN )
565 : {
566 :
567 453067 : pNode = pN;
568 453067 : bInvalid = true;
569 453067 : bVisible = true;
570 453067 : bSimple = false;
571 453067 : bForceRepaint = false;
572 453067 : nInvalidPosStart = 0;
573 453067 : nInvalidDiff = 0;
574 453067 : nHeight = 0;
575 453067 : nFirstLineOffset = 0;
576 453067 : nBulletX = 0;
577 453067 : }
578 :
579 452673 : ParaPortion::~ParaPortion()
580 : {
581 452673 : }
582 :
583 256708 : void ParaPortion::MarkInvalid( sal_Int32 nStart, sal_Int32 nDiff )
584 : {
585 256708 : if ( bInvalid == false )
586 : {
587 : // nInvalidPosEnd = nStart; // ??? => CreateLines
588 17299 : nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
589 17299 : nInvalidDiff = nDiff;
590 : }
591 : else
592 : {
593 : // Simple tap in succession
594 242429 : if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) &&
595 3020 : ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) )
596 : {
597 3018 : nInvalidDiff = nInvalidDiff + nDiff;
598 : }
599 : // Simple delete in succession
600 236391 : else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) )
601 : {
602 0 : nInvalidPosStart = nInvalidPosStart + nDiff;
603 0 : nInvalidDiff = nInvalidDiff + nDiff;
604 : }
605 : else
606 : {
607 : // nInvalidPosEnd = pNode->Len();
608 : DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" );
609 236391 : nInvalidPosStart = std::min( nInvalidPosStart, ( nDiff < 0 ? nStart+nDiff : nDiff ) );
610 236391 : nInvalidDiff = 0;
611 236391 : bSimple = false;
612 : }
613 : }
614 256708 : bInvalid = true;
615 256708 : aScriptInfos.clear();
616 256708 : aWritingDirectionInfos.clear();
617 256708 : }
618 :
619 968776 : void ParaPortion::MarkSelectionInvalid( sal_Int32 nStart, sal_Int32 /* nEnd */ )
620 : {
621 968776 : if ( bInvalid == false )
622 : {
623 78215 : nInvalidPosStart = nStart;
624 : // nInvalidPosEnd = nEnd;
625 : }
626 : else
627 : {
628 890561 : nInvalidPosStart = std::min( nInvalidPosStart, nStart );
629 : // nInvalidPosEnd = pNode->Len();
630 : }
631 968776 : nInvalidDiff = 0;
632 968776 : bInvalid = true;
633 968776 : bSimple = false;
634 968776 : aScriptInfos.clear();
635 968776 : aWritingDirectionInfos.clear();
636 968776 : }
637 :
638 0 : sal_Int32 ParaPortion::GetLineNumber( sal_Int32 nIndex ) const
639 : {
640 : DBG_ASSERTWARNING( aLineList.Count(), "Empty ParaPortion in GetLine!" );
641 : DBG_ASSERT( bVisible, "Why GetLine() on an invisible paragraph?" );
642 :
643 0 : for ( sal_Int32 nLine = 0; nLine < aLineList.Count(); nLine++ )
644 : {
645 0 : if ( aLineList[nLine]->IsIn( nIndex ) )
646 0 : return (sal_Int32)nLine;
647 : }
648 :
649 : // Then it should be at the end of the last line!
650 : DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index dead wrong!" );
651 0 : return (aLineList.Count()-1);
652 : }
653 :
654 0 : void ParaPortion::SetVisible( bool bMakeVisible )
655 : {
656 0 : bVisible = bMakeVisible;
657 0 : }
658 :
659 4 : void ParaPortion::CorrectValuesBehindLastFormattedLine( sal_Int32 nLastFormattedLine )
660 : {
661 4 : sal_Int32 nLines = aLineList.Count();
662 : DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Empty Portion?" );
663 4 : if ( nLastFormattedLine < ( nLines - 1 ) )
664 : {
665 0 : const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ];
666 0 : const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ];
667 0 : sal_Int32 nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion();
668 0 : sal_Int32 nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd();
669 0 : nTextDiff++; // LastFormatted->GetEnd() was included => 1 deducted too much!
670 :
671 : // The first unformatted must begin exactly one Portion behind the last
672 : // of the formatted:
673 : // If the modified line was split into one portion, can
674 : // nLastEnd > nNextStart!
675 0 : int nPDiff = -( nPortionDiff-1 );
676 0 : int nTDiff = -( nTextDiff-1 );
677 0 : if ( nPDiff || nTDiff )
678 : {
679 0 : for ( sal_Int32 nL = nLastFormattedLine+1; nL < nLines; nL++ )
680 : {
681 0 : EditLine* pLine = aLineList[ nL ];
682 :
683 0 : pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff;
684 0 : pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff;
685 :
686 0 : pLine->GetStart() = pLine->GetStart() + nTDiff;
687 0 : pLine->GetEnd() = pLine->GetEnd() + nTDiff;
688 :
689 0 : pLine->SetValid();
690 : }
691 : }
692 : }
693 : DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: The end is not right!" );
694 4 : }
695 :
696 : // Shared reverse lookup acceleration pieces ...
697 :
698 : namespace {
699 :
700 : template<typename _Array, typename _Val>
701 5506539 : sal_Int32 FastGetPos(const _Array& rArray, const _Val* p, sal_Int32& rLastPos)
702 : {
703 5506539 : sal_Int32 nArrayLen = rArray.size();
704 :
705 : // Through certain filter code-paths we do a lot of appends, which in
706 : // turn call GetPos - creating some N^2 nightmares. If we have a
707 : // non-trivially large list, do a few checks from the end first.
708 5506539 : if (rLastPos > 16 && nArrayLen > 16)
709 : {
710 : sal_Int32 nEnd;
711 28042 : if (rLastPos > nArrayLen - 2)
712 13282 : nEnd = nArrayLen;
713 : else
714 14760 : nEnd = rLastPos + 2;
715 :
716 89036 : for (sal_Int32 nIdx = rLastPos - 2; nIdx < nEnd; ++nIdx)
717 : {
718 88916 : if (&rArray.at(nIdx) == p)
719 : {
720 27922 : rLastPos = nIdx;
721 27922 : return nIdx;
722 : }
723 : }
724 : }
725 : // The world's lamest linear search from svarray ...
726 6444819 : for (sal_Int32 nIdx = 0; nIdx < nArrayLen; ++nIdx)
727 6444819 : if (&rArray.at(nIdx) == p)
728 5478617 : return rLastPos = nIdx;
729 :
730 : // XXX "not found" condition for sal_Int32 indexes
731 0 : return EE_PARA_NOT_FOUND;
732 : }
733 :
734 : }
735 :
736 51673 : ParaPortionList::ParaPortionList() : nLastCache( 0 )
737 : {
738 51673 : }
739 :
740 51279 : ParaPortionList::~ParaPortionList()
741 : {
742 51279 : }
743 :
744 913383 : sal_Int32 ParaPortionList::GetPos(const ParaPortion* p) const
745 : {
746 913383 : return FastGetPos(maPortions, p, nLastCache);
747 : }
748 :
749 2542701 : ParaPortion* ParaPortionList::operator [](sal_Int32 nPos)
750 : {
751 2542701 : return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
752 : }
753 :
754 165 : const ParaPortion* ParaPortionList::operator [](sal_Int32 nPos) const
755 : {
756 165 : return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
757 : }
758 :
759 0 : ParaPortion* ParaPortionList::Release(sal_Int32 nPos)
760 : {
761 0 : if (nPos < 0 || (sal_Int32)maPortions.size() <= nPos)
762 : {
763 : SAL_WARN( "editeng", "ParaPortionList::Release - out of bounds pos " << nPos);
764 0 : return NULL;
765 : }
766 0 : return maPortions.release(maPortions.begin()+nPos).release();
767 : }
768 :
769 3578 : void ParaPortionList::Remove(sal_Int32 nPos)
770 : {
771 3578 : if (nPos < 0 || (sal_Int32)maPortions.size() <= nPos)
772 : {
773 : SAL_WARN( "editeng", "ParaPortionList::Remove - out of bounds pos " << nPos);
774 3578 : return;
775 : }
776 3578 : maPortions.erase(maPortions.begin()+nPos);
777 : }
778 :
779 453067 : void ParaPortionList::Insert(sal_Int32 nPos, ParaPortion* p)
780 : {
781 453067 : if (nPos < 0 || (sal_Int32)maPortions.size() < nPos)
782 : {
783 : SAL_WARN( "editeng", "ParaPortionList::Insert - out of bounds pos " << nPos);
784 453067 : return;
785 : }
786 453067 : maPortions.insert(maPortions.begin()+nPos, p);
787 : }
788 :
789 0 : void ParaPortionList::Append(ParaPortion* p)
790 : {
791 0 : maPortions.push_back(p);
792 0 : }
793 :
794 2238007 : sal_Int32 ParaPortionList::Count() const
795 : {
796 2238007 : size_t nSize = maPortions.size();
797 2238007 : if (nSize > SAL_MAX_INT32)
798 : {
799 : SAL_WARN( "editeng", "ParaPortionList::Count - overflow " << nSize);
800 0 : return SAL_MAX_INT32;
801 : }
802 2238007 : return nSize;
803 : }
804 :
805 430325 : void ParaPortionList::Reset()
806 : {
807 430325 : maPortions.clear();
808 430325 : }
809 :
810 268 : long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
811 : {
812 268 : long nHeight = 0;
813 268 : for (sal_Int32 i = 0, n = maPortions.size(); i < n; ++i)
814 : {
815 268 : const ParaPortion* pTmpPortion = &maPortions[i];
816 268 : if ( pTmpPortion == pPPortion )
817 268 : return nHeight;
818 0 : nHeight += pTmpPortion->GetHeight();
819 : }
820 : OSL_FAIL( "GetYOffset: Portion not found" );
821 0 : return nHeight;
822 : }
823 :
824 0 : sal_Int32 ParaPortionList::FindParagraph(long nYOffset) const
825 : {
826 0 : long nY = 0;
827 0 : for (size_t i = 0, n = maPortions.size(); i < n; ++i)
828 : {
829 0 : nY += maPortions[i].GetHeight(); // should also be correct even in bVisible!
830 0 : if ( nY > nYOffset )
831 0 : return i <= SAL_MAX_INT32 ? static_cast<sal_Int32>(i) : SAL_MAX_INT32;
832 : }
833 0 : return EE_PARA_NOT_FOUND;
834 : }
835 :
836 1118650 : const ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos) const
837 : {
838 1118650 : return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
839 : }
840 :
841 1444085 : ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos)
842 : {
843 1444085 : return 0 <= nPos && nPos < (sal_Int32)maPortions.size() ? &maPortions[nPos] : NULL;
844 : }
845 :
846 : #if OSL_DEBUG_LEVEL > 2
847 : void ParaPortionList::DbgCheck( EditDoc& rDoc)
848 : {
849 : DBG_ASSERT( Count() == rDoc.Count(), "ParaPortionList::DbgCheck() - Count() unequal!" );
850 : for ( sal_Int32 i = 0; i < Count(); i++ )
851 : {
852 : DBG_ASSERT( SafeGetObject(i), "ParaPortionList::DbgCheck() - Null-Pointer in List!" );
853 : DBG_ASSERT( GetObject(i)->GetNode(), "ParaPortionList::DbgCheck() - Null-Pointer in List(2)!" );
854 : DBG_ASSERT( GetObject(i)->GetNode() == rDoc.GetObject(i), "ParaPortionList::DbgCheck() - Entries intersect!" );
855 : }
856 : }
857 : #endif
858 :
859 10643 : ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) :
860 10643 : aPrevParaAttribs( rParaAttribs)
861 : {
862 10643 : }
863 :
864 10643 : void ContentAttribsInfo::RemoveAllCharAttribsFromPool(SfxItemPool& rPool) const
865 : {
866 10643 : CharAttribsType::const_iterator it = aPrevCharAttribs.begin(), itEnd = aPrevCharAttribs.end();
867 73637 : for (; it != itEnd; ++it)
868 62994 : rPool.Remove(*it->GetItem());
869 10643 : }
870 :
871 62994 : void ContentAttribsInfo::AppendCharAttrib(EditCharAttrib* pNew)
872 : {
873 62994 : aPrevCharAttribs.push_back(pNew);
874 62994 : }
875 :
876 8 : void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit )
877 : {
878 : DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" );
879 :
880 8 : switch ( rPoolItem.Which() )
881 : {
882 : case EE_PARA_LRSPACE:
883 : {
884 : DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: invalid Item!" );
885 0 : SvxLRSpaceItem& rItem = static_cast<SvxLRSpaceItem&>(rPoolItem);
886 0 : rItem.SetTxtFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTxtFirstLineOfst(), eSourceUnit, eDestUnit ) ) );
887 0 : rItem.SetTxtLeft( OutputDevice::LogicToLogic( rItem.GetTxtLeft(), eSourceUnit, eDestUnit ) );
888 0 : rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) );
889 : }
890 0 : break;
891 : case EE_PARA_ULSPACE:
892 : {
893 : DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Invalid Item!" );
894 0 : SvxULSpaceItem& rItem = static_cast<SvxULSpaceItem&>(rPoolItem);
895 0 : rItem.SetUpper( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) );
896 0 : rItem.SetLower( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) );
897 : }
898 0 : break;
899 : case EE_PARA_SBL:
900 : {
901 : DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Invalid Item!" );
902 0 : SvxLineSpacingItem& rItem = static_cast<SvxLineSpacingItem&>(rPoolItem);
903 : // SetLineHeight changes also eLineSpace!
904 0 : if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
905 0 : rItem.SetLineHeight( sal::static_int_cast< sal_uInt16 >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) );
906 : }
907 0 : break;
908 : case EE_PARA_TABS:
909 : {
910 : DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Invalid Item!" );
911 0 : SvxTabStopItem& rItem = static_cast<SvxTabStopItem&>(rPoolItem);
912 0 : SvxTabStopItem aNewItem( EE_PARA_TABS );
913 0 : for ( sal_uInt16 i = 0; i < rItem.Count(); i++ )
914 : {
915 0 : const SvxTabStop& rTab = rItem[i];
916 0 : SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() );
917 0 : aNewItem.Insert( aNewStop );
918 : }
919 0 : rItem = aNewItem;
920 : }
921 0 : break;
922 : case EE_CHAR_FONTHEIGHT:
923 : case EE_CHAR_FONTHEIGHT_CJK:
924 : case EE_CHAR_FONTHEIGHT_CTL:
925 : {
926 : DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Invalid Item!" );
927 0 : SvxFontHeightItem& rItem = static_cast<SvxFontHeightItem&>(rPoolItem);
928 0 : rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) );
929 : }
930 0 : break;
931 : }
932 8 : }
933 :
934 8 : void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit )
935 : {
936 8 : const SfxItemPool* pSourcePool = rSource.GetPool();
937 8 : const SfxItemPool* pDestPool = rDest.GetPool();
938 :
939 416 : for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
940 : {
941 : // If possible go through SlotID ...
942 :
943 408 : sal_uInt16 nSourceWhich = nWhich;
944 408 : sal_uInt16 nSlot = pDestPool->GetTrueSlotId( nWhich );
945 408 : if ( nSlot )
946 : {
947 352 : sal_uInt16 nW = pSourcePool->GetTrueWhich( nSlot );
948 352 : if ( nW )
949 352 : nSourceWhich = nW;
950 : }
951 :
952 408 : if ( rSource.GetItemState( nSourceWhich, false ) == SfxItemState::SET )
953 : {
954 0 : MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich );
955 0 : MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich );
956 0 : if ( eSourceUnit != eDestUnit )
957 : {
958 0 : SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone();
959 : // pItem->SetWhich( nWhich );
960 0 : ConvertItem( *pItem, eSourceUnit, eDestUnit );
961 0 : rDest.Put( *pItem, nWhich );
962 0 : delete pItem;
963 : }
964 : else
965 : {
966 0 : rDest.Put( rSource.Get( nSourceWhich ), nWhich );
967 : }
968 : }
969 : }
970 8 : }
971 :
972 403888 : EditLine::EditLine() :
973 : bHangingPunctuation(false),
974 403888 : bInvalid(true)
975 : {
976 :
977 403888 : nStart = nEnd = 0;
978 403888 : nStartPortion = 0; // to be able to tell the difference between a line
979 : // without Ptorions form one with the Portion number 0
980 403888 : nEndPortion = 0;
981 403888 : nHeight = 0;
982 403888 : nStartPosX = 0;
983 403888 : nTxtHeight = 0;
984 403888 : nTxtWidth = 0;
985 403888 : nCrsrHeight = 0;
986 403888 : nMaxAscent = 0;
987 403888 : }
988 :
989 120445 : EditLine::EditLine( const EditLine& r ) :
990 : bHangingPunctuation(r.bHangingPunctuation),
991 120445 : bInvalid(true)
992 : {
993 :
994 120445 : nEnd = r.nEnd;
995 120445 : nStart = r.nStart;
996 120445 : nStartPortion = r.nStartPortion;
997 120445 : nEndPortion = r.nEndPortion;
998 :
999 120445 : nHeight = 0;
1000 120445 : nStartPosX = 0;
1001 120445 : nTxtHeight = 0;
1002 120445 : nTxtWidth = 0;
1003 120445 : nCrsrHeight = 0;
1004 120445 : nMaxAscent = 0;
1005 120445 : }
1006 :
1007 523988 : EditLine::~EditLine()
1008 : {
1009 523988 : }
1010 :
1011 :
1012 :
1013 0 : EditLine* EditLine::Clone() const
1014 : {
1015 0 : EditLine* pL = new EditLine;
1016 0 : pL->aPositions = aPositions;
1017 0 : pL->nStartPosX = nStartPosX;
1018 0 : pL->nStart = nStart;
1019 0 : pL->nEnd = nEnd;
1020 0 : pL->nStartPortion = nStartPortion;
1021 0 : pL->nEndPortion = nEndPortion;
1022 0 : pL->nHeight = nHeight;
1023 0 : pL->nTxtWidth = nTxtWidth;
1024 0 : pL->nTxtHeight = nTxtHeight;
1025 0 : pL->nCrsrHeight = nCrsrHeight;
1026 0 : pL->nMaxAscent = nMaxAscent;
1027 :
1028 0 : return pL;
1029 : }
1030 :
1031 0 : bool operator == ( const EditLine& r1, const EditLine& r2 )
1032 : {
1033 0 : if ( r1.nStart != r2.nStart )
1034 0 : return false;
1035 :
1036 0 : if ( r1.nEnd != r2.nEnd )
1037 0 : return false;
1038 :
1039 0 : if ( r1.nStartPortion != r2.nStartPortion )
1040 0 : return false;
1041 :
1042 0 : if ( r1.nEndPortion != r2.nEndPortion )
1043 0 : return false;
1044 :
1045 0 : return true;
1046 : }
1047 :
1048 73427 : EditLine& EditLine::operator = ( const EditLine& r )
1049 : {
1050 73427 : nEnd = r.nEnd;
1051 73427 : nStart = r.nStart;
1052 73427 : nEndPortion = r.nEndPortion;
1053 73427 : nStartPortion = r.nStartPortion;
1054 73427 : return *this;
1055 : }
1056 :
1057 :
1058 0 : bool operator != ( const EditLine& r1, const EditLine& r2 )
1059 : {
1060 0 : return !( r1 == r2 );
1061 : }
1062 :
1063 449862 : void EditLine::SetHeight( sal_uInt16 nH, sal_uInt16 nTxtH, sal_uInt16 nCrsrH )
1064 : {
1065 449862 : nHeight = nH;
1066 449862 : nTxtHeight = ( nTxtH ? nTxtH : nH );
1067 449862 : nCrsrHeight = ( nCrsrH ? nCrsrH : nTxtHeight );
1068 449862 : }
1069 :
1070 410489 : void EditLine::SetStartPosX( long start )
1071 : {
1072 410489 : if (start > 0)
1073 31623 : nStartPosX = start;
1074 : else
1075 378866 : nStartPosX = 0;
1076 410489 : }
1077 :
1078 193872 : Size EditLine::CalcTextSize( ParaPortion& rParaPortion )
1079 : {
1080 193872 : Size aSz;
1081 193872 : Size aTmpSz;
1082 : TextPortion* pPortion;
1083 :
1084 : DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize before CreatePortions !" );
1085 :
1086 399145 : for ( sal_Int32 n = nStartPortion; n <= nEndPortion; n++ )
1087 : {
1088 205273 : pPortion = rParaPortion.GetTextPortions()[n];
1089 205273 : switch ( pPortion->GetKind() )
1090 : {
1091 : case PortionKind::TEXT:
1092 : case PortionKind::FIELD:
1093 : case PortionKind::HYPHENATOR:
1094 : {
1095 205084 : aTmpSz = pPortion->GetSize();
1096 205084 : aSz.Width() += aTmpSz.Width();
1097 205084 : if ( aSz.Height() < aTmpSz.Height() )
1098 193894 : aSz.Height() = aTmpSz.Height();
1099 : }
1100 205084 : break;
1101 : case PortionKind::TAB:
1102 : {
1103 22 : aSz.Width() += pPortion->GetSize().Width();
1104 : }
1105 22 : break;
1106 167 : case PortionKind::LINEBREAK: break;
1107 : }
1108 : }
1109 :
1110 193872 : SetHeight( (sal_uInt16)aSz.Height() );
1111 193872 : return aSz;
1112 : }
1113 :
1114 453067 : EditLineList::EditLineList()
1115 : {
1116 453067 : }
1117 :
1118 905346 : EditLineList::~EditLineList()
1119 : {
1120 452673 : Reset();
1121 452673 : }
1122 :
1123 494662 : void EditLineList::Reset()
1124 : {
1125 494662 : maLines.clear();
1126 494662 : }
1127 :
1128 4 : void EditLineList::DeleteFromLine(sal_Int32 nDelFrom)
1129 : {
1130 : DBG_ASSERT( nDelFrom <= ((sal_Int32)maLines.size() - 1), "DeleteFromLine: Out of range" );
1131 4 : LinesType::iterator it = maLines.begin();
1132 4 : std::advance(it, nDelFrom);
1133 4 : maLines.erase(it, maLines.end());
1134 4 : }
1135 :
1136 32 : sal_Int32 EditLineList::FindLine(sal_Int32 nChar, bool bInclEnd)
1137 : {
1138 32 : sal_Int32 n = maLines.size();
1139 32 : for (sal_Int32 i = 0; i < n; ++i)
1140 : {
1141 32 : const EditLine& rLine = maLines[i];
1142 48 : if ( (bInclEnd && (rLine.GetEnd() >= nChar)) ||
1143 16 : (rLine.GetEnd() > nChar) )
1144 : {
1145 32 : return i;
1146 : }
1147 : }
1148 :
1149 : DBG_ASSERT( !bInclEnd, "Line not found: FindLine" );
1150 0 : return n - 1;
1151 : }
1152 :
1153 3178598 : sal_Int32 EditLineList::Count() const
1154 : {
1155 3178598 : return maLines.size();
1156 : }
1157 :
1158 27024 : const EditLine* EditLineList::operator[](sal_Int32 nPos) const
1159 : {
1160 27024 : return &maLines[nPos];
1161 : }
1162 :
1163 1448453 : EditLine* EditLineList::operator[](sal_Int32 nPos)
1164 : {
1165 1448453 : return &maLines[nPos];
1166 : }
1167 :
1168 330637 : void EditLineList::Append(EditLine* p)
1169 : {
1170 330637 : maLines.push_back(p);
1171 330637 : }
1172 :
1173 73251 : void EditLineList::Insert(sal_Int32 nPos, EditLine* p)
1174 : {
1175 73251 : maLines.insert(maLines.begin()+nPos, p);
1176 73251 : }
1177 :
1178 2597960 : EditPaM::EditPaM() : pNode(NULL), nIndex(0) {}
1179 2306387 : EditPaM::EditPaM(const EditPaM& r) : pNode(r.pNode), nIndex(r.nIndex) {}
1180 2370983 : EditPaM::EditPaM(ContentNode* p, sal_Int32 n) : pNode(p), nIndex(n) {}
1181 :
1182 :
1183 :
1184 176737 : void EditPaM::SetNode(ContentNode* p)
1185 : {
1186 176737 : pNode = p;
1187 176737 : }
1188 :
1189 0 : bool EditPaM::DbgIsBuggy( EditDoc& rDoc )
1190 : {
1191 0 : return !pNode ||
1192 0 : rDoc.GetPos( pNode ) >= rDoc.Count() ||
1193 0 : nIndex > pNode->Len();
1194 : }
1195 :
1196 0 : bool EditSelection::DbgIsBuggy( EditDoc& rDoc )
1197 : {
1198 0 : return aStartPaM.DbgIsBuggy( rDoc ) || aEndPaM.DbgIsBuggy( rDoc );
1199 : }
1200 :
1201 274083 : EditSelection::EditSelection()
1202 : {
1203 274083 : }
1204 :
1205 192583 : EditSelection::EditSelection( const EditPaM& rStartAndAnd )
1206 : {
1207 : // could still be optimized!
1208 : // do no first call the Def-constructor from PaM!
1209 192583 : aStartPaM = rStartAndAnd;
1210 192583 : aEndPaM = rStartAndAnd;
1211 192583 : }
1212 :
1213 789242 : EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd )
1214 : {
1215 : // could still be optimized!
1216 789242 : aStartPaM = rStart;
1217 789242 : aEndPaM = rEnd;
1218 789242 : }
1219 :
1220 5493 : EditSelection& EditSelection::operator = ( const EditPaM& rPaM )
1221 : {
1222 5493 : aStartPaM = rPaM;
1223 5493 : aEndPaM = rPaM;
1224 5493 : return *this;
1225 : }
1226 :
1227 472195 : void EditSelection::Adjust( const EditDoc& rNodes )
1228 : {
1229 : DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in Adjust(1)" );
1230 : DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in Adjust(2)" );
1231 :
1232 472195 : const ContentNode* pStartNode = aStartPaM.GetNode();
1233 472195 : const ContentNode* pEndNode = aEndPaM.GetNode();
1234 :
1235 472195 : sal_Int32 nStartNode = rNodes.GetPos( pStartNode );
1236 472195 : sal_Int32 nEndNode = rNodes.GetPos( pEndNode );
1237 :
1238 : DBG_ASSERT( nStartNode != SAL_MAX_INT32, "Node out of range in Adjust(1)" );
1239 : DBG_ASSERT( nEndNode != SAL_MAX_INT32, "Node out of range in Adjust(2)" );
1240 :
1241 472195 : const bool bSwap = ( nStartNode > nEndNode ) ||
1242 452907 : ( ( nStartNode == nEndNode ) &&
1243 925102 : ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) );
1244 :
1245 472195 : if ( bSwap )
1246 : {
1247 0 : EditPaM aTmpPaM( aStartPaM );
1248 0 : aStartPaM = aEndPaM;
1249 0 : aEndPaM = aTmpPaM;
1250 : }
1251 472195 : }
1252 :
1253 286246 : bool operator == ( const EditPaM& r1, const EditPaM& r2 )
1254 : {
1255 566954 : return ( r1.GetNode() == r2.GetNode() ) &&
1256 566954 : ( r1.GetIndex() == r2.GetIndex() );
1257 : }
1258 :
1259 2994366 : EditPaM& EditPaM::operator = ( const EditPaM& rPaM )
1260 : {
1261 2994366 : nIndex = rPaM.nIndex;
1262 2994366 : pNode = rPaM.pNode;
1263 2994366 : return *this;
1264 : }
1265 :
1266 286246 : bool operator != ( const EditPaM& r1, const EditPaM& r2 )
1267 : {
1268 286246 : return !( r1 == r2 );
1269 : }
1270 :
1271 444243 : ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool )
1272 : {
1273 444243 : }
1274 :
1275 8824 : ContentNode::ContentNode( const OUString& rStr, const ContentAttribs& rContentAttribs ) :
1276 8824 : maString(rStr), aContentAttribs(rContentAttribs)
1277 : {
1278 8824 : }
1279 :
1280 452673 : ContentNode::~ContentNode()
1281 : {
1282 452673 : }
1283 :
1284 246842 : void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew, SfxItemPool& rItemPool )
1285 : {
1286 246842 : if ( !nNew )
1287 276172 : return;
1288 :
1289 : // Since features are treated differently than normal character attributes,
1290 : // can also the order of the start list be change!
1291 : // In every if ..., in the next (n) opportunities due to bFeature or
1292 : // an existing special case, must (n-1) opportunities be provided with
1293 : // bResort. The most likely possibility receives no bResort, so that is
1294 : // not sorted anew when all attributes are the same.
1295 217512 : bool bResort = false;
1296 217512 : bool bExpandedEmptyAtIndexNull = false;
1297 :
1298 217512 : sal_Int32 nAttr = 0;
1299 217512 : CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
1300 217512 : EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
1301 480128 : while ( pAttrib )
1302 : {
1303 45104 : if ( pAttrib->GetEnd() >= nIndex )
1304 : {
1305 : // Move all attributes behind the insertion point...
1306 43282 : if ( pAttrib->GetStart() > nIndex )
1307 : {
1308 2880 : pAttrib->MoveForward( nNew );
1309 : }
1310 : // 0: Expand empty attribute, if at insertion point
1311 40402 : else if ( pAttrib->IsEmpty() )
1312 : {
1313 : // Do not check Index, a emty one could only be there
1314 : // When later checking it anyhow:
1315 : // Special caase: Start == 0; AbsLen == 1, nNew = 1
1316 : // => Expand, because of paragraph break!
1317 : // Start <= nIndex, End >= nIndex => Start=End=nIndex!
1318 : // if ( pAttrib->GetStart() == nIndex )
1319 28296 : pAttrib->Expand( nNew );
1320 28296 : if ( pAttrib->GetStart() == 0 )
1321 28162 : bExpandedEmptyAtIndexNull = true;
1322 : }
1323 : // 1: Attribute starts before, goes to index ...
1324 12106 : else if ( pAttrib->GetEnd() == nIndex ) // Start must be before
1325 : {
1326 : // Only expand when there is no feature
1327 : // and if not in exclude list!
1328 : // Otherwise, a UL will go on until a new ULDB, expaning both
1329 : // if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) )
1330 12046 : if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
1331 : {
1332 10782 : if ( !pAttrib->IsEdge() )
1333 10782 : pAttrib->Expand( nNew );
1334 : }
1335 : else
1336 1264 : bResort = true;
1337 : }
1338 : // 2: Attribute starts before, goes past the Index...
1339 60 : else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
1340 : {
1341 : DBG_ASSERT( !pAttrib->IsFeature(), "Large Feature?!" );
1342 0 : pAttrib->Expand( nNew );
1343 : }
1344 : // 3: Attribute starts on index...
1345 60 : else if ( pAttrib->GetStart() == nIndex )
1346 : {
1347 60 : if ( pAttrib->IsFeature() )
1348 : {
1349 6 : pAttrib->MoveForward( nNew );
1350 6 : bResort = true;
1351 : }
1352 : else
1353 : {
1354 54 : bool bExpand = false;
1355 54 : if ( nIndex == 0 )
1356 : {
1357 54 : bExpand = true;
1358 54 : if( bExpandedEmptyAtIndexNull )
1359 : {
1360 : // Check if this kind of attribute was empty and expanded here...
1361 0 : sal_uInt16 nW = pAttrib->GetItem()->Which();
1362 0 : for ( sal_uInt16 nA = 0; nA < nAttr; nA++ )
1363 : {
1364 0 : const EditCharAttrib& r = aCharAttribList.GetAttribs()[nA];
1365 0 : if ( ( r.GetStart() == 0 ) && ( r.GetItem()->Which() == nW ) )
1366 : {
1367 0 : bExpand = false;
1368 0 : break;
1369 : }
1370 : }
1371 :
1372 : }
1373 : }
1374 54 : if ( bExpand )
1375 : {
1376 54 : pAttrib->Expand( nNew );
1377 54 : bResort = true;
1378 : }
1379 : else
1380 : {
1381 0 : pAttrib->MoveForward( nNew );
1382 : }
1383 : }
1384 : }
1385 : }
1386 :
1387 45104 : if ( pAttrib->IsEdge() )
1388 0 : pAttrib->SetEdge(false);
1389 :
1390 : DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
1391 :
1392 : DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribute distorted!" );
1393 : DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attribute larger than paragraph!" );
1394 45104 : if ( pAttrib->IsEmpty() )
1395 : {
1396 : OSL_FAIL( "Empty Attribute after ExpandAttribs?" );
1397 0 : bResort = true;
1398 0 : rItemPool.Remove( *pAttrib->GetItem() );
1399 0 : rAttribs.erase(rAttribs.begin()+nAttr);
1400 0 : --nAttr;
1401 : }
1402 45104 : ++nAttr;
1403 45104 : pAttrib = GetAttrib(rAttribs, nAttr);
1404 : }
1405 :
1406 217512 : if ( bResort )
1407 1230 : aCharAttribList.ResortAttribs();
1408 :
1409 217512 : if (mpWrongList)
1410 : {
1411 65154 : bool bSep = ( maString[ nIndex ] == ' ' ) || IsFeature( nIndex );
1412 65154 : mpWrongList->TextInserted( nIndex, nNew, bSep );
1413 : }
1414 :
1415 : #if OSL_DEBUG_LEVEL > 2
1416 : OSL_ENSURE( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Expand: Start List distorted" );
1417 : #endif
1418 : }
1419 :
1420 8184 : void ContentNode::CollapsAttribs( sal_Int32 nIndex, sal_Int32 nDeleted, SfxItemPool& rItemPool )
1421 : {
1422 8184 : if ( !nDeleted )
1423 15242 : return;
1424 :
1425 : // Since features are treated differently than normal character attributes,
1426 : // can also the order of the start list be change!
1427 1126 : bool bResort = false;
1428 1126 : bool bDelAttr = false;
1429 1126 : sal_Int32 nEndChanges = nIndex+nDeleted;
1430 :
1431 1126 : sal_Int32 nAttr = 0;
1432 1126 : CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
1433 1126 : EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
1434 3586 : while ( pAttrib )
1435 : {
1436 1334 : bDelAttr = false;
1437 1334 : if ( pAttrib->GetEnd() >= nIndex )
1438 : {
1439 : // Move all Attribute behind the insert point...
1440 1334 : if ( pAttrib->GetStart() >= nEndChanges )
1441 : {
1442 194 : pAttrib->MoveBackward( nDeleted );
1443 : }
1444 : // 1. Delete Internal attributes...
1445 1140 : else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
1446 : {
1447 : // Special case: Attribute covers the area exactly
1448 : // => keep as empty Attribute.
1449 882 : if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
1450 122 : pAttrib->GetEnd() = nIndex; // empty
1451 : else
1452 760 : bDelAttr = true;
1453 : }
1454 : // 2. Attribute starts earlier, ends inside or behind it ...
1455 258 : else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
1456 : {
1457 : DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
1458 192 : if ( pAttrib->GetEnd() <= nEndChanges ) // ends inside
1459 18 : pAttrib->GetEnd() = nIndex;
1460 : else
1461 174 : pAttrib->Collaps( nDeleted ); // ends behind
1462 : }
1463 : // 3. Attribute starts inside, ending behind ...
1464 66 : else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
1465 : {
1466 : // Features not allowed to expand!
1467 30 : if ( pAttrib->IsFeature() )
1468 : {
1469 0 : pAttrib->MoveBackward( nDeleted );
1470 0 : bResort = true;
1471 : }
1472 : else
1473 : {
1474 30 : pAttrib->GetStart() = nEndChanges;
1475 30 : pAttrib->MoveBackward( nDeleted );
1476 : }
1477 : }
1478 : }
1479 : DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
1480 :
1481 : DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut distorted!" );
1482 : DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attribute larger than paragraph!" );
1483 1334 : if ( bDelAttr )
1484 : {
1485 760 : bResort = true;
1486 760 : rItemPool.Remove( *pAttrib->GetItem() );
1487 760 : rAttribs.erase(rAttribs.begin()+nAttr);
1488 760 : nAttr--;
1489 : }
1490 574 : else if ( pAttrib->IsEmpty() )
1491 122 : aCharAttribList.SetHasEmptyAttribs(true);
1492 :
1493 1334 : nAttr++;
1494 1334 : pAttrib = GetAttrib(rAttribs, nAttr);
1495 : }
1496 :
1497 1126 : if ( bResort )
1498 602 : aCharAttribList.ResortAttribs();
1499 :
1500 1126 : if (mpWrongList)
1501 110 : mpWrongList->TextDeleted(nIndex, nDeleted);
1502 :
1503 : #if OSL_DEBUG_LEVEL > 2
1504 : OSL_ENSURE( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Collaps: Start list distorted" );
1505 : #endif
1506 : }
1507 :
1508 8824 : void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, bool bKeepEndingAttribs )
1509 : {
1510 : DBG_ASSERT( pPrevNode, "Copy of attributes to a null pointer?" );
1511 :
1512 8824 : sal_Int32 nCut = pPrevNode->Len();
1513 :
1514 8824 : sal_Int32 nAttr = 0;
1515 8824 : CharAttribList::AttribsType& rPrevAttribs = pPrevNode->GetCharAttribs().GetAttribs();
1516 8824 : EditCharAttrib* pAttrib = GetAttrib(rPrevAttribs, nAttr);
1517 38924 : while ( pAttrib )
1518 : {
1519 21276 : if ( pAttrib->GetEnd() < nCut )
1520 : {
1521 : // remain unchanged ....
1522 : ;
1523 : }
1524 19158 : else if ( pAttrib->GetEnd() == nCut )
1525 : {
1526 : // must be copied as an empty attributes.
1527 19156 : if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
1528 : {
1529 17634 : EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 );
1530 : DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" );
1531 17634 : aCharAttribList.InsertAttrib( pNewAttrib );
1532 : }
1533 : }
1534 2 : else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) )
1535 : {
1536 : // If cut is done right at the front then the attribute must be
1537 : // kept! Has to be copied and changed.
1538 0 : EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
1539 : DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" );
1540 0 : aCharAttribList.InsertAttrib( pNewAttrib );
1541 0 : pAttrib->GetEnd() = nCut;
1542 : }
1543 : else
1544 : {
1545 : // Move all attributes in the current node (this)
1546 2 : CharAttribList::AttribsType::iterator it = rPrevAttribs.begin() + nAttr;
1547 2 : aCharAttribList.InsertAttrib(rPrevAttribs.release(it).release());
1548 2 : pAttrib->MoveBackward( nCut );
1549 2 : nAttr--;
1550 : }
1551 21276 : nAttr++;
1552 21276 : pAttrib = GetAttrib(rPrevAttribs, nAttr);
1553 : }
1554 8824 : }
1555 :
1556 3546 : void ContentNode::AppendAttribs( ContentNode* pNextNode )
1557 : {
1558 : DBG_ASSERT( pNextNode, "Copy of attributes to a null pointer?" );
1559 :
1560 3546 : sal_Int32 nNewStart = maString.getLength();
1561 :
1562 : #if OSL_DEBUG_LEVEL > 2
1563 : OSL_ENSURE( aCharAttribList.DbgCheckAttribs(), "Attribute before AppendAttribs broken" );
1564 : #endif
1565 :
1566 3546 : sal_Int32 nAttr = 0;
1567 3546 : CharAttribList::AttribsType& rNextAttribs = pNextNode->GetCharAttribs().GetAttribs();
1568 3546 : EditCharAttrib* pAttrib = GetAttrib(rNextAttribs, nAttr);
1569 7730 : while ( pAttrib )
1570 : {
1571 : // Move all attributes in the current node (this)
1572 638 : bool bMelted = false;
1573 638 : if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
1574 : {
1575 : // Attributes can possibly be summarized as:
1576 638 : sal_Int32 nTmpAttr = 0;
1577 638 : EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
1578 2214 : while ( !bMelted && pTmpAttrib )
1579 : {
1580 938 : if ( pTmpAttrib->GetEnd() == nNewStart )
1581 : {
1582 1566 : if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
1583 628 : ( *(pTmpAttrib->GetItem()) == *(pAttrib->GetItem() ) ) )
1584 : {
1585 628 : pTmpAttrib->GetEnd() =
1586 628 : pTmpAttrib->GetEnd() + pAttrib->GetLen();
1587 628 : rNextAttribs.erase(rNextAttribs.begin()+nAttr);
1588 : // Unsubscribe from the pool?!
1589 628 : bMelted = true;
1590 : }
1591 : }
1592 938 : ++nTmpAttr;
1593 938 : pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
1594 : }
1595 : }
1596 :
1597 638 : if ( !bMelted )
1598 : {
1599 10 : pAttrib->GetStart() = pAttrib->GetStart() + nNewStart;
1600 10 : pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart;
1601 10 : CharAttribList::AttribsType::iterator it = rNextAttribs.begin() + nAttr;
1602 10 : aCharAttribList.InsertAttrib(rNextAttribs.release(it).release());
1603 : }
1604 638 : pAttrib = GetAttrib(rNextAttribs, nAttr);
1605 : }
1606 : // For the Attributes that just moved over:
1607 3546 : rNextAttribs.clear();
1608 :
1609 : #if OSL_DEBUG_LEVEL > 2
1610 : OSL_ENSURE( aCharAttribList.DbgCheckAttribs(), "Attribute after AppendAttribs broken" );
1611 : #endif
1612 3546 : }
1613 :
1614 576620 : void ContentNode::CreateDefFont()
1615 : {
1616 : // First use the information from the style ...
1617 576620 : SfxStyleSheet* pS = aContentAttribs.GetStyleSheet();
1618 576620 : if ( pS )
1619 160454 : CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
1620 :
1621 : // ... then iron out the hard paragraph formatting...
1622 576620 : CreateFont( GetCharAttribs().GetDefFont(),
1623 1153240 : GetContentAttribs().GetItems(), pS == NULL );
1624 576620 : }
1625 :
1626 0 : void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle )
1627 : {
1628 0 : aContentAttribs.SetStyleSheet( pS );
1629 :
1630 :
1631 : // First use the information from the style ...
1632 0 : GetCharAttribs().GetDefFont() = rFontFromStyle;
1633 : // ... then iron out the hard paragraph formatting...
1634 0 : CreateFont( GetCharAttribs().GetDefFont(),
1635 0 : GetContentAttribs().GetItems(), pS == NULL );
1636 0 : }
1637 :
1638 274770 : void ContentNode::SetStyleSheet( SfxStyleSheet* pS, bool bRecalcFont )
1639 : {
1640 274770 : aContentAttribs.SetStyleSheet( pS );
1641 274770 : if ( bRecalcFont )
1642 75670 : CreateDefFont();
1643 274770 : }
1644 :
1645 64916 : bool ContentNode::IsFeature( sal_Int32 nPos ) const
1646 : {
1647 64916 : return maString[nPos] == CH_FEATURE;
1648 : }
1649 :
1650 9073786 : sal_Int32 ContentNode::Len() const
1651 : {
1652 9073786 : return maString.getLength();
1653 : }
1654 :
1655 2580 : sal_uLong ContentNode::GetExpandedLen() const
1656 : {
1657 2580 : sal_uLong nLen = maString.getLength();
1658 :
1659 : // Fields can be longer than the placeholder in the Node
1660 2580 : const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
1661 34524 : for (sal_Int32 nAttr = rAttrs.size(); nAttr; )
1662 : {
1663 29364 : const EditCharAttrib& rAttr = rAttrs[--nAttr];
1664 29364 : if (rAttr.Which() == EE_FEATURE_FIELD)
1665 : {
1666 10 : nLen += static_cast<const EditCharAttribField&>(rAttr).GetFieldValue().getLength();
1667 10 : --nLen; // Standalone, to avoid corner cases when previous getLength() returns 0
1668 : }
1669 : }
1670 :
1671 2580 : return nLen;
1672 : }
1673 :
1674 35820 : OUString ContentNode::GetExpandedText(sal_Int32 nStartPos, sal_Int32 nEndPos, bool bResolveFields) const
1675 : {
1676 35820 : if ( nEndPos < 0 || nEndPos > Len() )
1677 27777 : nEndPos = Len();
1678 :
1679 : DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" );
1680 :
1681 35820 : sal_Int32 nIndex = nStartPos;
1682 35820 : OUString aStr;
1683 35820 : const EditCharAttrib* pNextFeature = GetCharAttribs().FindFeature( nIndex );
1684 83747 : while ( nIndex < nEndPos )
1685 : {
1686 12107 : sal_Int32 nEnd = nEndPos;
1687 12107 : if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
1688 1349 : nEnd = pNextFeature->GetStart();
1689 : else
1690 10758 : pNextFeature = 0; // Feature does not interest the below
1691 :
1692 : DBG_ASSERT( nEnd >= nIndex, "End in front of the index?" );
1693 : //!! beware of sub string length of -1
1694 12107 : if (nEnd > nIndex)
1695 11040 : aStr += GetString().copy(nIndex, nEnd - nIndex);
1696 :
1697 12107 : if ( pNextFeature )
1698 : {
1699 1349 : switch ( pNextFeature->GetItem()->Which() )
1700 : {
1701 0 : case EE_FEATURE_TAB: aStr += "\t";
1702 0 : break;
1703 27 : case EE_FEATURE_LINEBR: aStr += "\x0A";
1704 27 : break;
1705 : case EE_FEATURE_FIELD:
1706 1322 : if ( bResolveFields )
1707 1322 : aStr += static_cast<const EditCharAttribField*>(pNextFeature)->GetFieldValue();
1708 1322 : break;
1709 : default: OSL_FAIL( "What feature?" );
1710 : }
1711 1349 : pNextFeature = GetCharAttribs().FindFeature( ++nEnd );
1712 : }
1713 12107 : nIndex = nEnd;
1714 : }
1715 35820 : return aStr;
1716 : }
1717 :
1718 284 : void ContentNode::UnExpandPosition( sal_Int32 &rPos, bool bBiasStart )
1719 : {
1720 284 : sal_Int32 nOffset = 0;
1721 :
1722 284 : const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
1723 424 : for (size_t nAttr = 0; nAttr < rAttrs.size(); ++nAttr )
1724 : {
1725 284 : const EditCharAttrib& rAttr = rAttrs[nAttr];
1726 : assert (!(nAttr < rAttrs.size() - 1) ||
1727 : rAttrs[nAttr].GetStart() < rAttrs[nAttr + 1].GetStart());
1728 :
1729 284 : nOffset = rAttr.GetStart();
1730 :
1731 284 : if (nOffset >= rPos) // happens after the position
1732 98 : return;
1733 :
1734 186 : sal_Int32 nChunk = 0;
1735 186 : if (rAttr.Which() == EE_FEATURE_FIELD)
1736 : {
1737 186 : nChunk += static_cast<const EditCharAttribField&>(rAttr).GetFieldValue().getLength();
1738 186 : nChunk--; // Character representing the field in the string
1739 :
1740 186 : if (nOffset + nChunk >= rPos) // we're inside the field
1741 : {
1742 46 : if (bBiasStart)
1743 22 : rPos = rAttr.GetStart();
1744 : else
1745 24 : rPos = rAttr.GetEnd();
1746 46 : return;
1747 : }
1748 : // Adjust for the position
1749 140 : rPos -= nChunk;
1750 : }
1751 : }
1752 : assert (rPos <= Len());
1753 : }
1754 :
1755 : /*
1756 : * Fields are represented by a single character in the underlying string
1757 : * and/or selection, however, they can be expanded to the full value of
1758 : * the field. When we're dealing with selection / offsets however we need
1759 : * to deal in character positions inside the real (unexpanded) string.
1760 : * This method maps us back to character offsets.
1761 : */
1762 142 : void ContentNode::UnExpandPositions( sal_Int32 &rStartPos, sal_Int32 &rEndPos )
1763 : {
1764 142 : UnExpandPosition( rStartPos, true );
1765 142 : UnExpandPosition( rEndPos, false );
1766 142 : }
1767 :
1768 0 : void ContentNode::SetChar(sal_Int32 nPos, sal_Unicode c)
1769 : {
1770 0 : maString = maString.replaceAt(nPos, 1, OUString(c));
1771 0 : }
1772 :
1773 246842 : void ContentNode::Insert(const OUString& rStr, sal_Int32 nPos)
1774 : {
1775 246842 : maString = maString.replaceAt(nPos, 0, rStr);
1776 246842 : }
1777 :
1778 3546 : void ContentNode::Append(const OUString& rStr)
1779 : {
1780 3546 : maString += rStr;
1781 3546 : }
1782 :
1783 8824 : void ContentNode::Erase(sal_Int32 nPos)
1784 : {
1785 8824 : maString = maString.copy(0, nPos);
1786 8824 : }
1787 :
1788 8184 : void ContentNode::Erase(sal_Int32 nPos, sal_Int32 nCount)
1789 : {
1790 8184 : maString = maString.replaceAt(nPos, nCount, "");
1791 8184 : }
1792 :
1793 8824 : OUString ContentNode::Copy(sal_Int32 nPos) const
1794 : {
1795 8824 : return maString.copy(nPos);
1796 : }
1797 :
1798 137985 : OUString ContentNode::Copy(sal_Int32 nPos, sal_Int32 nCount) const
1799 : {
1800 137985 : return maString.copy(nPos, nCount);
1801 : }
1802 :
1803 188480 : sal_Unicode ContentNode::GetChar(sal_Int32 nPos) const
1804 : {
1805 188480 : return maString[nPos];
1806 : }
1807 :
1808 1148 : void ContentNode::EnsureWrongList()
1809 : {
1810 1148 : if (!mpWrongList)
1811 0 : CreateWrongList();
1812 1148 : }
1813 :
1814 199821 : WrongList* ContentNode::GetWrongList()
1815 : {
1816 199821 : return mpWrongList.get();
1817 : }
1818 :
1819 19 : const WrongList* ContentNode::GetWrongList() const
1820 : {
1821 19 : return mpWrongList.get();
1822 : }
1823 :
1824 55040 : void ContentNode::SetWrongList( WrongList* p )
1825 : {
1826 55040 : mpWrongList.reset(p);
1827 55040 : }
1828 :
1829 137997 : void ContentNode::CreateWrongList()
1830 : {
1831 : SAL_WARN_IF( mpWrongList && !mpWrongList->empty(), "editeng", "WrongList already exist!");
1832 137997 : if (!mpWrongList || !mpWrongList->empty())
1833 137914 : mpWrongList.reset(new WrongList);
1834 137997 : }
1835 :
1836 311 : void ContentNode::DestroyWrongList()
1837 : {
1838 311 : mpWrongList.reset();
1839 311 : }
1840 :
1841 444243 : ContentAttribs::ContentAttribs( SfxItemPool& rPool )
1842 : : pStyle(0)
1843 444243 : , aAttribSet( rPool, EE_PARA_START, EE_CHAR_END )
1844 : {
1845 444243 : }
1846 :
1847 17648 : ContentAttribs::ContentAttribs( const ContentAttribs& rRef )
1848 : : pStyle(rRef.pStyle)
1849 17648 : , aAttribSet( rRef.aAttribSet )
1850 : {
1851 17648 : }
1852 :
1853 461497 : ContentAttribs::~ContentAttribs()
1854 : {
1855 461497 : }
1856 :
1857 22 : SvxTabStop ContentAttribs::FindTabStop( sal_Int32 nCurPos, sal_uInt16 nDefTab )
1858 : {
1859 22 : const SvxTabStopItem& rTabs = static_cast<const SvxTabStopItem&>( GetItem( EE_PARA_TABS ) );
1860 38 : for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
1861 : {
1862 26 : const SvxTabStop& rTab = rTabs[i];
1863 26 : if ( rTab.GetTabPos() > nCurPos )
1864 10 : return rTab;
1865 : }
1866 :
1867 : // Determine DefTab ...
1868 12 : SvxTabStop aTabStop;
1869 12 : const sal_Int32 x = nCurPos / nDefTab + 1;
1870 12 : aTabStop.GetTabPos() = nDefTab * x;
1871 12 : return aTabStop;
1872 : }
1873 :
1874 274770 : void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
1875 : {
1876 274770 : bool bStyleChanged = ( pStyle != pS );
1877 274770 : pStyle = pS;
1878 : // Only when other style sheet, not when current style sheet modified
1879 274770 : if ( pStyle && bStyleChanged )
1880 : {
1881 : // Selectively remove the attributes from the paragraph formatting
1882 : // which are specified in the style, so that the attributes of the
1883 : // style can have an affect.
1884 75670 : const SfxItemSet& rStyleAttribs = pStyle->GetItemSet();
1885 3934840 : for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
1886 : {
1887 : // Don't change bullet on/off
1888 3859170 : if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET ) )
1889 1889308 : aAttribSet.ClearItem( nWhich );
1890 : }
1891 : }
1892 274770 : }
1893 :
1894 5923097 : const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) const
1895 : {
1896 : // Hard paragraph attributes take precedence!
1897 5923097 : const SfxItemSet* pTakeFrom = &aAttribSet;
1898 5923097 : if ( pStyle && ( aAttribSet.GetItemState( nWhich, false ) != SfxItemState::SET ) )
1899 1145062 : pTakeFrom = &pStyle->GetItemSet();
1900 :
1901 5923097 : return pTakeFrom->Get( nWhich );
1902 : }
1903 :
1904 23971 : bool ContentAttribs::HasItem( sal_uInt16 nWhich ) const
1905 : {
1906 23971 : bool bHasItem = false;
1907 23971 : if ( aAttribSet.GetItemState( nWhich, false ) == SfxItemState::SET )
1908 0 : bHasItem = true;
1909 23971 : else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SfxItemState::SET )
1910 0 : bHasItem = true;
1911 :
1912 23971 : return bHasItem;
1913 : }
1914 :
1915 :
1916 0 : ItemList::ItemList() : CurrentItem( 0 )
1917 : {
1918 0 : }
1919 :
1920 0 : const SfxPoolItem* ItemList::First()
1921 : {
1922 0 : CurrentItem = 0;
1923 0 : return aItemPool.empty() ? NULL : aItemPool[ 0 ];
1924 : }
1925 :
1926 0 : const SfxPoolItem* ItemList::Next()
1927 : {
1928 0 : if ( CurrentItem + 1 < (sal_Int32)aItemPool.size() )
1929 : {
1930 0 : ++CurrentItem;
1931 0 : return aItemPool[ CurrentItem ];
1932 : }
1933 0 : return NULL;
1934 : }
1935 :
1936 0 : void ItemList::Insert( const SfxPoolItem* pItem )
1937 : {
1938 0 : aItemPool.push_back( pItem );
1939 0 : CurrentItem = aItemPool.size() - 1;
1940 0 : }
1941 :
1942 :
1943 51673 : EditDoc::EditDoc( SfxItemPool* pPool ) :
1944 : nLastCache(0),
1945 32 : pItemPool(pPool ? pPool : new EditEngineItemPool(false)),
1946 : nDefTab(DEFTAB),
1947 : bIsVertical(false),
1948 : bIsFixedCellHeight(false),
1949 : bOwnerOfPool(pPool ? false : true),
1950 51705 : bModified(false)
1951 : {
1952 : // Don't create a empty node, Clear() will be called in EditEngine-CTOR
1953 51673 : };
1954 :
1955 102558 : EditDoc::~EditDoc()
1956 : {
1957 51279 : ImplDestroyContents();
1958 51279 : if ( bOwnerOfPool )
1959 30 : SfxItemPool::Free(pItemPool);
1960 51279 : }
1961 :
1962 : namespace {
1963 :
1964 : class RemoveEachItemFromPool : std::unary_function<ContentNode, void>
1965 : {
1966 : EditDoc& mrDoc;
1967 : public:
1968 481604 : RemoveEachItemFromPool(EditDoc& rDoc) : mrDoc(rDoc) {}
1969 449095 : void operator() (const ContentNode& rNode)
1970 : {
1971 449095 : mrDoc.RemoveItemsFromPool(rNode);
1972 449095 : }
1973 : };
1974 :
1975 : struct ClearSpellErrorsHandler : std::unary_function<ContentNode, void>
1976 : {
1977 0 : void operator() (ContentNode& rNode)
1978 : {
1979 0 : rNode.DestroyWrongList();
1980 0 : }
1981 : };
1982 :
1983 : }
1984 :
1985 481604 : void EditDoc::ImplDestroyContents()
1986 : {
1987 481604 : std::for_each(maContents.begin(), maContents.end(), RemoveEachItemFromPool(*this));
1988 481604 : maContents.clear();
1989 481604 : }
1990 :
1991 452641 : void EditDoc::RemoveItemsFromPool(const ContentNode& rNode)
1992 : {
1993 801750 : for (sal_Int32 nAttr = 0; nAttr < rNode.GetCharAttribs().Count(); ++nAttr)
1994 : {
1995 349109 : const EditCharAttrib& rAttr = rNode.GetCharAttribs().GetAttribs()[nAttr];
1996 349109 : GetItemPool().Remove(*rAttr.GetItem());
1997 : }
1998 452641 : }
1999 :
2000 971984 : void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType )
2001 : {
2002 971984 : vcl::Font aPrevFont( rFont );
2003 971984 : rFont.SetAlign( ALIGN_BASELINE );
2004 971984 : rFont.SetTransparent( true );
2005 :
2006 971984 : sal_uInt16 nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
2007 971984 : sal_uInt16 nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
2008 971984 : sal_uInt16 nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType );
2009 971984 : sal_uInt16 nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType );
2010 971984 : sal_uInt16 nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType );
2011 :
2012 971984 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SfxItemState::SET ) )
2013 : {
2014 811913 : const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSet.Get( nWhich_FontInfo ));
2015 811913 : rFont.SetName( rFontItem.GetFamilyName() );
2016 811913 : rFont.SetFamily( rFontItem.GetFamily() );
2017 811913 : rFont.SetPitch( rFontItem.GetPitch() );
2018 811913 : rFont.SetCharSet( rFontItem.GetCharSet() );
2019 : }
2020 971984 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SfxItemState::SET ) )
2021 811967 : rFont.SetLanguage( static_cast<const SvxLanguageItem&>(rSet.Get( nWhich_Language )).GetLanguage() );
2022 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SfxItemState::SET ) )
2023 811892 : rFont.SetColor( static_cast<const SvxColorItem&>(rSet.Get( EE_CHAR_COLOR )).GetValue() );
2024 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_BKGCOLOR ) == SfxItemState::SET ) )
2025 811904 : rFont.SetFillColor( static_cast<const SvxBackgroundColorItem&>(rSet.Get( EE_CHAR_BKGCOLOR )).GetValue() );
2026 971984 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SfxItemState::SET ) )
2027 824979 : rFont.SetSize( Size( rFont.GetSize().Width(), static_cast<const SvxFontHeightItem&>(rSet.Get( nWhich_FontHeight ) ).GetHeight() ) );
2028 971984 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SfxItemState::SET ) )
2029 811858 : rFont.SetWeight( static_cast<const SvxWeightItem&>(rSet.Get( nWhich_Weight )).GetWeight() );
2030 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET ) )
2031 811985 : rFont.SetUnderline( static_cast<const SvxUnderlineItem&>(rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() );
2032 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SfxItemState::SET ) )
2033 812005 : rFont.SetOverline( static_cast<const SvxOverlineItem&>(rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() );
2034 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET ) )
2035 812009 : rFont.SetStrikeout( static_cast<const SvxCrossedOutItem&>(rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() );
2036 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_CASEMAP ) == SfxItemState::SET ) )
2037 811932 : rFont.SetCaseMap( static_cast<const SvxCaseMapItem&>(rSet.Get( EE_CHAR_CASEMAP )).GetCaseMap() );
2038 971984 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SfxItemState::SET ) )
2039 811937 : rFont.SetItalic( static_cast<const SvxPostureItem&>(rSet.Get( nWhich_Italic )).GetPosture() );
2040 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SfxItemState::SET ) )
2041 811995 : rFont.SetOutline( static_cast<const SvxContourItem&>(rSet.Get( EE_CHAR_OUTLINE )).GetValue() );
2042 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SfxItemState::SET ) )
2043 811894 : rFont.SetShadow( static_cast<const SvxShadowedItem&>(rSet.Get( EE_CHAR_SHADOW )).GetValue() );
2044 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SfxItemState::SET ) )
2045 : {
2046 812019 : const SvxEscapementItem& rEsc = static_cast<const SvxEscapementItem&>( rSet.Get( EE_CHAR_ESCAPEMENT ) );
2047 :
2048 812019 : sal_uInt16 nProp = rEsc.GetProp();
2049 812019 : rFont.SetPropr( (sal_uInt8)nProp );
2050 :
2051 812019 : short nEsc = rEsc.GetEsc();
2052 812019 : if ( nEsc == DFLT_ESC_AUTO_SUPER )
2053 0 : nEsc = 100 - nProp;
2054 812019 : else if ( nEsc == DFLT_ESC_AUTO_SUB )
2055 0 : nEsc = sal::static_int_cast< short >( -( 100 - nProp ) );
2056 812019 : rFont.SetEscapement( nEsc );
2057 : }
2058 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SfxItemState::SET ) )
2059 811888 : rFont.SetKerning( static_cast<const SvxAutoKernItem&>(rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() );
2060 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SfxItemState::SET ) )
2061 811948 : rFont.SetFixKerning( static_cast<const SvxKerningItem&>(rSet.Get( EE_CHAR_KERNING )).GetValue() );
2062 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SfxItemState::SET ) )
2063 811917 : rFont.SetWordLineMode( static_cast<const SvxWordLineModeItem&>(rSet.Get( EE_CHAR_WLM )).GetValue() );
2064 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SfxItemState::SET ) )
2065 812025 : rFont.SetEmphasisMark( static_cast<const SvxEmphasisMarkItem&>(rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() );
2066 971984 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SfxItemState::SET ) )
2067 811530 : rFont.SetRelief( (FontRelief)static_cast<const SvxCharReliefItem&>(rSet.Get( EE_CHAR_RELIEF )).GetValue() );
2068 :
2069 : // If comparing the entire font, or if checking before each alteration
2070 : // whether the value changes, remains relatively the same thing.
2071 : // So possible one MakeUniqFont more in the font, but as a result a quicker
2072 : // abortion of the query, or one must each time check bChanged.
2073 971984 : if ( rFont == aPrevFont )
2074 715375 : rFont = aPrevFont; // => The same ImpPointer for IsSameInstance
2075 971984 : }
2076 :
2077 231233 : void EditDoc::CreateDefFont( bool bUseStyles )
2078 : {
2079 231233 : SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
2080 231233 : CreateFont( aDefFont, aTmpSet );
2081 231233 : aDefFont.SetVertical( IsVertical() );
2082 231233 : aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
2083 :
2084 462466 : for ( sal_Int32 nNode = 0; nNode < Count(); nNode++ )
2085 : {
2086 231233 : ContentNode* pNode = GetObject( nNode );
2087 231233 : pNode->GetCharAttribs().GetDefFont() = aDefFont;
2088 231233 : if ( bUseStyles )
2089 8 : pNode->CreateDefFont();
2090 231233 : }
2091 231233 : }
2092 :
2093 4593156 : sal_Int32 EditDoc::GetPos(const ContentNode* p) const
2094 : {
2095 4593156 : return FastGetPos(maContents, p, nLastCache);
2096 : }
2097 :
2098 3203265 : const ContentNode* EditDoc::GetObject(sal_Int32 nPos) const
2099 : {
2100 3203265 : return 0 <= nPos && nPos < (sal_Int32)maContents.size() ? &maContents[nPos] : NULL;
2101 : }
2102 :
2103 5037959 : ContentNode* EditDoc::GetObject(sal_Int32 nPos)
2104 : {
2105 5037959 : return 0 <= nPos && nPos < (sal_Int32)maContents.size() ? &maContents[nPos] : NULL;
2106 : }
2107 :
2108 0 : const ContentNode* EditDoc::operator[](sal_Int32 nPos) const
2109 : {
2110 0 : return GetObject(nPos);
2111 : }
2112 :
2113 718842 : ContentNode* EditDoc::operator[](sal_Int32 nPos)
2114 : {
2115 718842 : return GetObject(nPos);
2116 : }
2117 :
2118 453067 : void EditDoc::Insert(sal_Int32 nPos, ContentNode* p)
2119 : {
2120 453067 : if (nPos < 0 || nPos == SAL_MAX_INT32)
2121 : {
2122 : SAL_WARN( "editeng", "EditDoc::Insert - overflow pos " << nPos);
2123 453067 : return;
2124 : }
2125 453067 : maContents.insert(maContents.begin()+nPos, p);
2126 : }
2127 :
2128 3546 : void EditDoc::Remove(sal_Int32 nPos)
2129 : {
2130 3546 : if (nPos < 0 || nPos >= (sal_Int32)maContents.size())
2131 : {
2132 : SAL_WARN( "editeng", "EditDoc::Remove - out of bounds pos " << nPos);
2133 3546 : return;
2134 : }
2135 3546 : maContents.erase(maContents.begin() + nPos);
2136 : }
2137 :
2138 32 : void EditDoc::Release(sal_Int32 nPos)
2139 : {
2140 32 : if (nPos < 0 || nPos >= (sal_Int32)maContents.size())
2141 : {
2142 : SAL_WARN( "editeng", "EditDoc::Release - out of bounds pos " << nPos);
2143 32 : return;
2144 : }
2145 32 : maContents.release(maContents.begin() + nPos).release();
2146 : }
2147 :
2148 1254241 : sal_Int32 EditDoc::Count() const
2149 : {
2150 1254241 : size_t nSize = maContents.size();
2151 1254241 : if (nSize > SAL_MAX_INT32)
2152 : {
2153 : SAL_WARN( "editeng", "EditDoc::Count - overflow " << nSize);
2154 0 : return SAL_MAX_INT32;
2155 : }
2156 1254241 : return nSize;
2157 : }
2158 :
2159 9676 : OUString EditDoc::GetSepStr( LineEnd eEnd )
2160 : {
2161 9676 : if ( eEnd == LINEEND_CR )
2162 0 : return OUString("\015"); // 0x0d
2163 9676 : if ( eEnd == LINEEND_LF )
2164 9676 : return OUString("\012"); // 0x0a
2165 0 : return OUString("\015\012"); // 0x0d, 0x0a
2166 : }
2167 :
2168 2335 : OUString EditDoc::GetText( LineEnd eEnd ) const
2169 : {
2170 2335 : const sal_Int32 nNodes = Count();
2171 2335 : if (nNodes == 0)
2172 0 : return OUString();
2173 :
2174 2335 : const OUString aSep = EditDoc::GetSepStr( eEnd );
2175 2335 : const sal_Int32 nSepSize = aSep.getLength();
2176 2335 : const sal_uLong nLen = GetTextLen() + (nNodes - 1)*nSepSize;
2177 :
2178 4670 : OUStringBuffer aBuffer(nLen + 16); // leave some slack
2179 :
2180 4868 : for ( sal_Int32 nNode = 0; nNode < nNodes; nNode++ )
2181 : {
2182 2533 : if ( nSepSize && nNode>0 )
2183 : {
2184 198 : aBuffer.append(aSep);
2185 : }
2186 2533 : aBuffer.append(GetParaAsString( GetObject(nNode) ));
2187 : }
2188 :
2189 4670 : return aBuffer.makeStringAndClear();
2190 : }
2191 :
2192 25238 : OUString EditDoc::GetParaAsString( sal_Int32 nNode ) const
2193 : {
2194 25238 : return GetParaAsString( GetObject( nNode ) );
2195 : }
2196 :
2197 35814 : OUString EditDoc::GetParaAsString(
2198 : const ContentNode* pNode, sal_Int32 nStartPos, sal_Int32 nEndPos,
2199 : bool bResolveFields) const
2200 : {
2201 35814 : return pNode->GetExpandedText(nStartPos, nEndPos, bResolveFields);
2202 : }
2203 :
2204 784266 : EditPaM EditDoc::GetStartPaM() const
2205 : {
2206 784266 : ContentNode* p = const_cast<ContentNode*>(GetObject(0));
2207 784266 : return EditPaM(p, 0);
2208 : }
2209 :
2210 25850 : EditPaM EditDoc::GetEndPaM() const
2211 : {
2212 25850 : ContentNode* pLastNode = const_cast<ContentNode*>(GetObject(Count()-1));
2213 25850 : return EditPaM( pLastNode, pLastNode->Len() );
2214 : }
2215 :
2216 2376 : sal_uLong EditDoc::GetTextLen() const
2217 : {
2218 2376 : sal_uLong nLen = 0;
2219 4950 : for ( sal_Int32 nNode = 0; nNode < Count(); nNode++ )
2220 : {
2221 2574 : const ContentNode* pNode = GetObject( nNode );
2222 2574 : nLen += pNode->GetExpandedLen();
2223 : }
2224 2376 : return nLen;
2225 : }
2226 :
2227 231225 : EditPaM EditDoc::Clear()
2228 : {
2229 231225 : ImplDestroyContents();
2230 :
2231 231225 : ContentNode* pNode = new ContentNode( GetItemPool() );
2232 231225 : Insert(0, pNode);
2233 :
2234 231225 : CreateDefFont(false);
2235 :
2236 231225 : SetModified(false);
2237 :
2238 231225 : return EditPaM( pNode, 0 );
2239 : }
2240 :
2241 0 : void EditDoc::ClearSpellErrors()
2242 : {
2243 0 : std::for_each(maContents.begin(), maContents.end(), ClearSpellErrorsHandler());
2244 0 : }
2245 :
2246 1588054 : void EditDoc::SetModified( bool b )
2247 : {
2248 1588054 : bModified = b;
2249 1588054 : if ( bModified )
2250 : {
2251 1356635 : aModifyHdl.Call( NULL );
2252 : }
2253 1588054 : }
2254 :
2255 199100 : EditPaM EditDoc::RemoveText()
2256 : {
2257 : // Keep the old ItemSet, to keep the chart Font.
2258 199100 : ContentNode* pPrevFirstNode = GetObject(0);
2259 199100 : SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet();
2260 199100 : SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() );
2261 398200 : vcl::Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() );
2262 :
2263 199100 : ImplDestroyContents();
2264 :
2265 199100 : ContentNode* pNode = new ContentNode( GetItemPool() );
2266 199100 : Insert(0, pNode);
2267 :
2268 199100 : pNode->SetStyleSheet(pPrevStyle, false);
2269 199100 : pNode->GetContentAttribs().GetItems().Set( aPrevSet );
2270 199100 : pNode->GetCharAttribs().GetDefFont() = aPrevFont;
2271 :
2272 199100 : SetModified(true);
2273 :
2274 398200 : return EditPaM( pNode, 0 );
2275 : }
2276 :
2277 233448 : EditPaM EditDoc::InsertText( EditPaM aPaM, const OUString& rStr )
2278 : {
2279 : DBG_ASSERT( rStr.indexOf( 0x0A ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
2280 : DBG_ASSERT( rStr.indexOf( 0x0D ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
2281 : DBG_ASSERT( rStr.indexOf( '\t' ) == -1, "EditDoc::InsertText: Newlines prohibited in paragraph!" );
2282 : DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" );
2283 :
2284 233448 : aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() );
2285 233448 : aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.getLength(), GetItemPool() );
2286 233448 : aPaM.SetIndex( aPaM.GetIndex() + rStr.getLength() );
2287 :
2288 233448 : SetModified( true );
2289 :
2290 233448 : return aPaM;
2291 : }
2292 :
2293 8824 : EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, bool bKeepEndingAttribs )
2294 : {
2295 : DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" );
2296 8824 : ContentNode* pCurNode = aPaM.GetNode();
2297 8824 : sal_Int32 nPos = GetPos( pCurNode );
2298 8824 : OUString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() );
2299 8824 : aPaM.GetNode()->Erase( aPaM.GetIndex() );
2300 :
2301 : // the paragraph attributes...
2302 17648 : ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() );
2303 :
2304 : // for a new paragraph we like to have the bullet/numbering visible by default
2305 8824 : aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, true), EE_PARA_BULLETSTATE );
2306 :
2307 : // ContenNode constructor copies also the paragraph attributes
2308 8824 : ContentNode* pNode = new ContentNode( aStr, aContentAttribs );
2309 :
2310 : // Copy the Default Font
2311 8824 : pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont();
2312 8824 : SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet();
2313 8824 : if ( pStyle )
2314 : {
2315 5788 : OUString aFollow( pStyle->GetFollow() );
2316 5788 : if ( !aFollow.isEmpty() && ( aFollow != pStyle->GetName() ) )
2317 : {
2318 0 : SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() );
2319 0 : pNode->SetStyleSheet( static_cast<SfxStyleSheet*>(pNext) );
2320 5788 : }
2321 : }
2322 :
2323 : // Character attributes may need to be copied or trimmed:
2324 8824 : pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs );
2325 :
2326 8824 : Insert(nPos+1, pNode);
2327 :
2328 8824 : SetModified(true);
2329 :
2330 8824 : aPaM.SetNode( pNode );
2331 8824 : aPaM.SetIndex( 0 );
2332 17648 : return aPaM;
2333 : }
2334 :
2335 13394 : EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem )
2336 : {
2337 : DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" );
2338 :
2339 13394 : aPaM.GetNode()->Insert( OUString(CH_FEATURE), aPaM.GetIndex() );
2340 13394 : aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() );
2341 :
2342 : // Create a feature-attribute for the feature...
2343 13394 : EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 );
2344 : DBG_ASSERT( pAttrib, "Why can not the feature be created?" );
2345 13394 : aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib );
2346 :
2347 13394 : SetModified( true );
2348 :
2349 13394 : aPaM.SetIndex( aPaM.GetIndex() + 1 );
2350 13394 : return aPaM;
2351 : }
2352 :
2353 3546 : EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight )
2354 : {
2355 3546 : const EditPaM aPaM( pLeft, pLeft->Len() );
2356 :
2357 : // First the attributes, otherwise nLen will not be correct!
2358 3546 : pLeft->AppendAttribs( pRight );
2359 : // then the Text...
2360 3546 : pLeft->Append(pRight->GetString());
2361 :
2362 : // the one to the right disappears.
2363 3546 : RemoveItemsFromPool(*pRight);
2364 3546 : sal_Int32 nRight = GetPos( pRight );
2365 3546 : Remove( nRight );
2366 :
2367 3546 : SetModified(true);
2368 :
2369 3546 : return aPaM;
2370 : }
2371 :
2372 8184 : EditPaM EditDoc::RemoveChars( EditPaM aPaM, sal_Int32 nChars )
2373 : {
2374 : // Maybe remove Features!
2375 8184 : aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars );
2376 8184 : aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() );
2377 :
2378 8184 : SetModified( true );
2379 :
2380 8184 : return aPaM;
2381 : }
2382 :
2383 72490 : void EditDoc::InsertAttribInSelection( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, const SfxPoolItem& rPoolItem )
2384 : {
2385 : DBG_ASSERT( pNode, "What to do with the attribute?" );
2386 : DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" );
2387 :
2388 : // for Optimization:
2389 : // This ends at the beginning of the selection => can be expanded
2390 72490 : EditCharAttrib* pEndingAttrib = 0;
2391 : // This starts at the end of the selection => can be expanded
2392 72490 : EditCharAttrib* pStartingAttrib = 0;
2393 :
2394 : DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
2395 :
2396 72490 : RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
2397 :
2398 72618 : if ( pStartingAttrib && pEndingAttrib &&
2399 72494 : ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
2400 0 : ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
2401 : {
2402 : // Will become a large Attribute.
2403 0 : pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
2404 0 : GetItemPool().Remove( *(pStartingAttrib->GetItem()) );
2405 0 : pNode->GetCharAttribs().Remove(pStartingAttrib);
2406 : }
2407 72490 : else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
2408 118 : pStartingAttrib->GetStart() = nStart;
2409 72372 : else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
2410 17564 : pEndingAttrib->GetEnd() = nEnd;
2411 : else
2412 54808 : InsertAttrib( rPoolItem, pNode, nStart, nEnd );
2413 :
2414 72490 : if ( pStartingAttrib )
2415 124 : pNode->GetCharAttribs().ResortAttribs();
2416 :
2417 72490 : SetModified(true);
2418 72490 : }
2419 :
2420 1316 : bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, sal_uInt16 nWhich )
2421 : {
2422 : EditCharAttrib* pStarting;
2423 : EditCharAttrib* pEnding;
2424 1316 : return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
2425 : }
2426 :
2427 73806 : bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, sal_uInt16 nWhich )
2428 : {
2429 :
2430 : DBG_ASSERT( pNode, "What to do with the attribute?" );
2431 : DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribute to large!" );
2432 :
2433 : // This ends at the beginning of the selection => can be expanded
2434 73806 : rpEnding = 0;
2435 : // This starts at the end of the selection => can be expanded
2436 73806 : rpStarting = 0;
2437 :
2438 73806 : bool bChanged = false;
2439 :
2440 : DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
2441 :
2442 : // iterate over the attributes ...
2443 73806 : sal_Int32 nAttr = 0;
2444 73806 : CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
2445 73806 : EditCharAttrib* pAttr = GetAttrib(rAttribs, nAttr);
2446 734864 : while ( pAttr )
2447 : {
2448 587474 : bool bRemoveAttrib = false;
2449 587474 : sal_uInt16 nAttrWhich = pAttr->Which();
2450 587474 : if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) )
2451 : {
2452 : // Attribute starts in Selection
2453 28586 : if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
2454 : {
2455 3886 : bChanged = true;
2456 3886 : if ( pAttr->GetEnd() > nEnd )
2457 : {
2458 124 : pAttr->GetStart() = nEnd; // then it starts after this
2459 124 : rpStarting = pAttr;
2460 124 : if ( nWhich )
2461 124 : break; // There can be no further attributes here
2462 : }
2463 3762 : else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
2464 : {
2465 : // Delete feature only if on the exact spot
2466 3762 : bRemoveAttrib = true;
2467 : }
2468 : }
2469 :
2470 : // Attribute ends in Selection
2471 24700 : else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
2472 : {
2473 20676 : bChanged = true;
2474 20676 : if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
2475 : {
2476 20676 : pAttr->GetEnd() = nStart; // then it ends here
2477 20676 : rpEnding = pAttr;
2478 : }
2479 0 : else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
2480 : {
2481 : // Delete feature only if on the exact spot
2482 0 : bRemoveAttrib = true;
2483 : }
2484 : }
2485 : // Attribute overlaps the selection
2486 4024 : else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
2487 : {
2488 98 : bChanged = true;
2489 98 : if ( pAttr->GetStart() == nStart )
2490 : {
2491 0 : pAttr->GetStart() = nEnd;
2492 0 : rpStarting = pAttr;
2493 0 : if ( nWhich )
2494 0 : break; // There can be further attributes!
2495 : }
2496 98 : else if ( pAttr->GetEnd() == nEnd )
2497 : {
2498 0 : pAttr->GetEnd() = nStart;
2499 0 : rpEnding = pAttr;
2500 0 : if ( nWhich )
2501 0 : break; // There can be further attributes!
2502 : }
2503 : else // Attribute must be split ...
2504 : {
2505 98 : sal_Int32 nOldEnd = pAttr->GetEnd();
2506 98 : pAttr->GetEnd() = nStart;
2507 98 : rpEnding = pAttr;
2508 98 : InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
2509 98 : if ( nWhich )
2510 98 : break; // There can be further attributes!
2511 : }
2512 : }
2513 : }
2514 587252 : if ( bRemoveAttrib )
2515 : {
2516 : DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Delete and retain the same attribute?" );
2517 : DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" );
2518 3762 : GetItemPool().Remove( *pAttr->GetItem() );
2519 3762 : rAttribs.erase(rAttribs.begin()+nAttr);
2520 3762 : nAttr--;
2521 : }
2522 587252 : nAttr++;
2523 587252 : pAttr = GetAttrib(rAttribs, nAttr);
2524 : }
2525 :
2526 73806 : if ( bChanged )
2527 : {
2528 : // char attributes need to be sorted by start again
2529 24068 : pNode->GetCharAttribs().ResortAttribs();
2530 24068 : SetModified(true);
2531 : }
2532 :
2533 73806 : return bChanged;
2534 : }
2535 :
2536 99871 : void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd )
2537 : {
2538 : // This method no longer checks whether a corresponding attribute already
2539 : // exists at this place!
2540 99871 : EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd );
2541 : DBG_ASSERT( pAttrib, "MakeCharAttrib failed!" );
2542 99871 : pNode->GetCharAttribs().InsertAttrib( pAttrib );
2543 :
2544 99871 : SetModified( true );
2545 99871 : }
2546 :
2547 128471 : void EditDoc::InsertAttrib( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, const SfxPoolItem& rPoolItem )
2548 : {
2549 128471 : if ( nStart != nEnd )
2550 : {
2551 72490 : InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
2552 : }
2553 : else
2554 : {
2555 : // Check whether already a new attribute with WhichId exists at this place:
2556 55981 : CharAttribList& rAttrList = pNode->GetCharAttribs();
2557 55981 : EditCharAttrib* pAttr = rAttrList.FindEmptyAttrib( rPoolItem.Which(), nStart );
2558 55981 : if ( pAttr )
2559 : {
2560 : // Remove attribute....
2561 14389 : rAttrList.Release(pAttr);
2562 : }
2563 :
2564 : // check whether 'the same' attribute exist at this place.
2565 55981 : pAttr = rAttrList.FindAttrib( rPoolItem.Which(), nStart );
2566 55981 : if ( pAttr )
2567 : {
2568 11168 : if ( pAttr->IsInside( nStart ) ) // split
2569 : {
2570 : // check again if really splitting, or return !
2571 0 : sal_Int32 nOldEnd = pAttr->GetEnd();
2572 0 : pAttr->GetEnd() = nStart;
2573 0 : EditCharAttrib* pNew = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd );
2574 0 : rAttrList.InsertAttrib(pNew);
2575 : }
2576 11168 : else if ( pAttr->GetEnd() == nStart )
2577 : {
2578 : DBG_ASSERT( !pAttr->IsEmpty(), "Still an empty attribute?" );
2579 : // Check if exactly the same attribute
2580 11168 : if ( *(pAttr->GetItem()) == rPoolItem )
2581 139487 : return;
2582 : }
2583 : }
2584 44965 : InsertAttrib( rPoolItem, pNode, nStart, nStart );
2585 : }
2586 :
2587 117455 : SetModified( true );
2588 : }
2589 :
2590 6131 : void EditDoc::FindAttribs( ContentNode* pNode, sal_Int32 nStartPos, sal_Int32 nEndPos, SfxItemSet& rCurSet )
2591 : {
2592 : DBG_ASSERT( pNode, "Where to search?" );
2593 : DBG_ASSERT( nStartPos <= nEndPos, "Invalid region!" );
2594 :
2595 6131 : sal_uInt16 nAttr = 0;
2596 6131 : EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2597 : // No Selection...
2598 6131 : if ( nStartPos == nEndPos )
2599 : {
2600 24568 : while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
2601 : {
2602 15654 : const SfxPoolItem* pItem = 0;
2603 : // Attribute is about...
2604 15654 : if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
2605 0 : pItem = pAttr->GetItem();
2606 : // Attribute ending here is not empty
2607 15654 : else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
2608 : {
2609 0 : if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
2610 0 : pItem = pAttr->GetItem();
2611 : }
2612 : // Attribute ending here is empty
2613 15654 : else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
2614 : {
2615 9736 : pItem = pAttr->GetItem();
2616 : }
2617 : // Attribute starts here
2618 5918 : else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
2619 : {
2620 5918 : if ( nStartPos == 0 ) // special case
2621 5918 : pItem = pAttr->GetItem();
2622 : }
2623 :
2624 15654 : if ( pItem )
2625 : {
2626 15654 : sal_uInt16 nWhich = pItem->Which();
2627 15654 : if ( rCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
2628 : {
2629 7474 : rCurSet.Put( *pItem );
2630 : }
2631 8180 : else if ( rCurSet.GetItemState( nWhich ) == SfxItemState::SET )
2632 : {
2633 8180 : const SfxPoolItem& rItem = rCurSet.Get( nWhich );
2634 8180 : if ( rItem != *pItem )
2635 : {
2636 0 : rCurSet.InvalidateItem( nWhich );
2637 : }
2638 : }
2639 : }
2640 15654 : nAttr++;
2641 15654 : pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2642 : }
2643 : }
2644 : else // Selection
2645 : {
2646 37042 : while ( pAttr && ( pAttr->GetStart() < nEndPos) )
2647 : {
2648 33694 : const SfxPoolItem* pItem = 0;
2649 : // Attribut is about...
2650 33694 : if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
2651 33692 : pItem = pAttr->GetItem();
2652 : // Attribute starts right in the middle ...
2653 2 : else if ( pAttr->GetStart() >= nStartPos )
2654 : {
2655 : // !!! pItem = pAttr->GetItem();
2656 : // PItem is simply not enough, since one for example in case
2657 : // of Shadow, would never find an unequal item, since such a
2658 : // item represents its presence by absence!
2659 : // If (...)
2660 : // It needs to be examined on exactly the same attribute at the
2661 : // breaki point, which is quite expensive.
2662 : // Since optimazation is done when inserting the attributes
2663 : // this case does not appear so fast ...
2664 : // So based on the need for speed:
2665 2 : rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
2666 :
2667 : }
2668 : // Attribute ends in the middle of it ...
2669 0 : else if ( pAttr->GetEnd() > nStartPos )
2670 : {
2671 0 : rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
2672 : }
2673 :
2674 33694 : if ( pItem )
2675 : {
2676 33692 : sal_uInt16 nWhich = pItem->Which();
2677 33692 : if ( rCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
2678 : {
2679 17332 : rCurSet.Put( *pItem );
2680 : }
2681 16360 : else if ( rCurSet.GetItemState( nWhich ) == SfxItemState::SET )
2682 : {
2683 16360 : const SfxPoolItem& rItem = rCurSet.Get( nWhich );
2684 16360 : if ( rItem != *pItem )
2685 : {
2686 0 : rCurSet.InvalidateItem( nWhich );
2687 : }
2688 : }
2689 : }
2690 33694 : nAttr++;
2691 33694 : pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2692 : }
2693 : }
2694 6131 : }
2695 :
2696 : namespace {
2697 :
2698 : struct LessByStart : std::binary_function<EditCharAttrib, EditCharAttrib, bool>
2699 : {
2700 747136 : bool operator() (const EditCharAttrib& left, const EditCharAttrib& right) const
2701 : {
2702 747136 : return left.GetStart() < right.GetStart();
2703 : }
2704 : };
2705 :
2706 : }
2707 :
2708 453067 : CharAttribList::CharAttribList()
2709 : : aAttribs()
2710 : , aDefFont()
2711 453067 : , bHasEmptyAttribs(false)
2712 : {
2713 453067 : }
2714 :
2715 452673 : CharAttribList::~CharAttribList()
2716 : {
2717 452673 : }
2718 :
2719 372060 : void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
2720 : {
2721 : // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2722 : // optimize: binary search? !
2723 : // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2724 :
2725 : // Maybe just simply iterate backwards:
2726 : // The most common and critical case: Attributes are already sorted
2727 : // (InsertBinTextObject!) binary search would not be optimal here.
2728 : // => Would bring something!
2729 :
2730 372060 : const sal_Int32 nStart = pAttrib->GetStart(); // may be better for Comp.Opt.
2731 :
2732 372060 : if ( pAttrib->IsEmpty() )
2733 90500 : bHasEmptyAttribs = true;
2734 :
2735 3134126 : for (sal_Int32 i = 0, n = aAttribs.size(); i < n; ++i)
2736 : {
2737 2767606 : const EditCharAttrib& rCurAttrib = aAttribs[i];
2738 2767606 : if (rCurAttrib.GetStart() > nStart)
2739 : {
2740 5540 : aAttribs.insert(aAttribs.begin()+i, pAttrib);
2741 377600 : return;
2742 : }
2743 : }
2744 :
2745 366520 : aAttribs.push_back(pAttrib);
2746 : }
2747 :
2748 26024 : void CharAttribList::ResortAttribs()
2749 : {
2750 26024 : aAttribs.sort(LessByStart());
2751 26024 : }
2752 :
2753 42490 : void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
2754 : {
2755 319802 : for (sal_Int32 i = 0; i < (sal_Int32)aAttribs.size(); ++i)
2756 : {
2757 277312 : EditCharAttrib& rAttr = aAttribs[i];
2758 2812204 : for (sal_Int32 nNext = i+1; nNext < (sal_Int32)aAttribs.size(); ++nNext)
2759 : {
2760 2540592 : EditCharAttrib& rNext = aAttribs[nNext];
2761 2540592 : if (!rAttr.IsFeature() && rNext.GetStart() == rAttr.GetEnd() && rNext.Which() == rAttr.Which())
2762 : {
2763 1336 : if (*rNext.GetItem() == *rAttr.GetItem())
2764 : {
2765 98 : rAttr.GetEnd() = rNext.GetEnd();
2766 98 : rItemPool.Remove(*rNext.GetItem());
2767 98 : aAttribs.erase(aAttribs.begin()+nNext);
2768 : }
2769 1336 : break; // only 1 attr with same which can start here.
2770 : }
2771 2539256 : else if (rNext.GetStart() > rAttr.GetEnd())
2772 : {
2773 4364 : break;
2774 : }
2775 : }
2776 : }
2777 42490 : }
2778 :
2779 1089421 : sal_Int32 CharAttribList::Count() const
2780 : {
2781 1089421 : return aAttribs.size();
2782 : }
2783 :
2784 199665 : const EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos ) const
2785 : {
2786 : // Backwards, if one ends where the next starts.
2787 : // => The starting one is the valid one ...
2788 199665 : AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2789 594876 : for (; it != itEnd; ++it)
2790 : {
2791 409114 : const EditCharAttrib& rAttr = *it;
2792 409114 : if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
2793 13903 : return &rAttr;
2794 : }
2795 185762 : return NULL;
2796 : }
2797 :
2798 96189 : EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
2799 : {
2800 : // Backwards, if one ends where the next starts.
2801 : // => The starting one is the valid one ...
2802 96189 : AttribsType::reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2803 806192 : for (; it != itEnd; ++it)
2804 : {
2805 721885 : EditCharAttrib& rAttr = *it;
2806 721885 : if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
2807 11882 : return &rAttr;
2808 : }
2809 84307 : return NULL;
2810 : }
2811 :
2812 249787 : const EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_Int32 nFromPos ) const
2813 : {
2814 : DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
2815 249787 : AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2816 631126 : for (; it != itEnd; ++it)
2817 : {
2818 414854 : const EditCharAttrib& rAttr = *it;
2819 414854 : if (rAttr.GetStart() >= nFromPos && rAttr.Which() == nWhich)
2820 33515 : return &rAttr;
2821 : }
2822 216272 : return NULL;
2823 : }
2824 :
2825 0 : bool CharAttribList::HasAttrib( sal_Int32 nStartPos, sal_Int32 nEndPos ) const
2826 : {
2827 0 : AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2828 0 : for (; it != itEnd; ++it)
2829 : {
2830 0 : const EditCharAttrib& rAttr = *it;
2831 0 : if (rAttr.GetStart() < nEndPos && rAttr.GetEnd() > nStartPos)
2832 0 : return true;
2833 : }
2834 0 : return false;
2835 : }
2836 :
2837 :
2838 :
2839 : namespace {
2840 :
2841 : class FindByAddress : std::unary_function<EditCharAttrib, bool>
2842 : {
2843 : const EditCharAttrib* mpAttr;
2844 : public:
2845 14389 : FindByAddress(const EditCharAttrib* p) : mpAttr(p) {}
2846 19977 : bool operator() (const EditCharAttrib& r) const
2847 : {
2848 19977 : return &r == mpAttr;
2849 : }
2850 : };
2851 :
2852 : }
2853 :
2854 0 : void CharAttribList::Remove(const EditCharAttrib* p)
2855 : {
2856 0 : AttribsType::iterator it = std::find_if(aAttribs.begin(), aAttribs.end(), FindByAddress(p));
2857 0 : if (it != aAttribs.end())
2858 0 : aAttribs.erase(it);
2859 0 : }
2860 :
2861 3266 : void CharAttribList::Remove(sal_Int32 nPos)
2862 : {
2863 3266 : if (nPos >= (sal_Int32)aAttribs.size())
2864 3266 : return;
2865 :
2866 3266 : aAttribs.erase(aAttribs.begin()+nPos);
2867 : }
2868 :
2869 14389 : void CharAttribList::Release(const EditCharAttrib* p)
2870 : {
2871 14389 : AttribsType::iterator it = std::find_if(aAttribs.begin(), aAttribs.end(), FindByAddress(p));
2872 14389 : if (it != aAttribs.end())
2873 14389 : aAttribs.release(it).release();
2874 14389 : }
2875 :
2876 122 : void CharAttribList::SetHasEmptyAttribs(bool b)
2877 : {
2878 122 : bHasEmptyAttribs = b;
2879 122 : }
2880 :
2881 0 : bool CharAttribList::HasBoundingAttrib( sal_Int32 nBound ) const
2882 : {
2883 : // Backwards, if one ends where the next starts.
2884 : // => The starting one is the valid one ...
2885 0 : AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2886 0 : for (; it != itEnd; ++it)
2887 : {
2888 0 : const EditCharAttrib& rAttr = *it;
2889 0 : if (rAttr.GetEnd() < nBound)
2890 0 : return false;
2891 :
2892 0 : if (rAttr.GetStart() == nBound || rAttr.GetEnd() == nBound)
2893 0 : return true;
2894 : }
2895 0 : return false;
2896 : }
2897 :
2898 0 : const EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 nPos ) const
2899 : {
2900 0 : if ( !bHasEmptyAttribs )
2901 0 : return NULL;
2902 :
2903 0 : AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2904 0 : for (; it != itEnd; ++it)
2905 : {
2906 0 : const EditCharAttrib& rAttr = *it;
2907 0 : if (rAttr.GetStart() == nPos && rAttr.GetEnd() == nPos && rAttr.Which() == nWhich)
2908 0 : return &rAttr;
2909 : }
2910 0 : return NULL;
2911 : }
2912 :
2913 66847 : EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
2914 : {
2915 66847 : if ( !bHasEmptyAttribs )
2916 2890 : return NULL;
2917 :
2918 63957 : AttribsType::iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2919 669419 : for (; it != itEnd; ++it)
2920 : {
2921 619935 : EditCharAttrib& rAttr = *it;
2922 619935 : if (rAttr.GetStart() == nPos && rAttr.GetEnd() == nPos && rAttr.Which() == nWhich)
2923 14473 : return &rAttr;
2924 : }
2925 49484 : return NULL;
2926 : }
2927 :
2928 : namespace {
2929 :
2930 : class FindByStartPos : std::unary_function<EditCharAttrib, bool>
2931 : {
2932 : sal_Int32 mnPos;
2933 : public:
2934 247175 : FindByStartPos(sal_Int32 nPos) : mnPos(nPos) {}
2935 216575 : bool operator() (const EditCharAttrib& r) const
2936 : {
2937 216575 : return r.GetStart() >= mnPos;
2938 : }
2939 : };
2940 :
2941 : }
2942 :
2943 247175 : const EditCharAttrib* CharAttribList::FindFeature( sal_Int32 nPos ) const
2944 : {
2945 : // First, find the first attribute that starts at or after specified position.
2946 : AttribsType::const_iterator it =
2947 247175 : std::find_if(aAttribs.begin(), aAttribs.end(), FindByStartPos(nPos));
2948 :
2949 247175 : if (it == aAttribs.end())
2950 : // All attributes are before the specified position.
2951 206373 : return NULL;
2952 :
2953 : // And find the first attribute with feature.
2954 40802 : it = std::find_if(it, aAttribs.end(), boost::bind(&EditCharAttrib::IsFeature, _1) == true);
2955 40802 : return it == aAttribs.end() ? NULL : &(*it);
2956 : }
2957 :
2958 : namespace {
2959 :
2960 : class RemoveEmptyAttrItem : std::unary_function<EditCharAttrib, void>
2961 : {
2962 : SfxItemPool& mrItemPool;
2963 : public:
2964 1120 : RemoveEmptyAttrItem(SfxItemPool& rPool) : mrItemPool(rPool) {}
2965 15698 : void operator() (const EditCharAttrib& r)
2966 : {
2967 15698 : if (r.IsEmpty())
2968 32 : mrItemPool.Remove(*r.GetItem());
2969 15698 : }
2970 : };
2971 :
2972 : }
2973 :
2974 1120 : void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool )
2975 : {
2976 1120 : std::for_each(aAttribs.begin(), aAttribs.end(), RemoveEmptyAttrItem(rItemPool));
2977 1120 : aAttribs.erase_if(boost::bind(&EditCharAttrib::IsEmpty, _1) == true);
2978 1120 : bHasEmptyAttribs = false;
2979 1120 : }
2980 :
2981 : #if OSL_DEBUG_LEVEL > 2
2982 : bool CharAttribList::DbgCheckAttribs() const
2983 : {
2984 : bool bOK = true;
2985 : AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2986 : for (; it != itEnd; ++it)
2987 : {
2988 : const EditCharAttrib& rAttr = *it;
2989 : if (rAttr.GetStart() > rAttr.GetEnd())
2990 : {
2991 : bOK = false;
2992 : OSL_FAIL( "Attribute is distorted" );
2993 : }
2994 : else if (rAttr.IsFeature() && rAttr.GetLen() != 1)
2995 : {
2996 : bOK = false;
2997 : OSL_FAIL( "Feature, Len != 1" );
2998 : }
2999 : }
3000 : return bOK;
3001 : }
3002 : #endif
3003 :
3004 :
3005 88688 : EditEngineItemPool::EditEngineItemPool( bool bPersistenRefCounts )
3006 : : SfxItemPool( "EditEngineItemPool", EE_ITEMS_START, EE_ITEMS_END,
3007 88688 : aItemInfos, 0, bPersistenRefCounts )
3008 : {
3009 88688 : SetVersionMap( 1, 3999, 4015, aV1Map );
3010 88688 : SetVersionMap( 2, 3999, 4019, aV2Map );
3011 88688 : SetVersionMap( 3, 3997, 4020, aV3Map );
3012 88688 : SetVersionMap( 4, 3994, 4022, aV4Map );
3013 88688 : SetVersionMap( 5, 3994, 4037, aV5Map );
3014 88688 : SetVersionMap( 6, 3994, 4038, aV6Map );
3015 :
3016 88688 : SfxPoolItem** ppDefItems = EE_DLL().GetGlobalData()->GetDefItems();
3017 88688 : SetDefaults( ppDefItems );
3018 88688 : }
3019 :
3020 176714 : EditEngineItemPool::~EditEngineItemPool()
3021 : {
3022 176714 : }
3023 :
3024 10704 : SvStream& EditEngineItemPool::Store( SvStream& rStream ) const
3025 : {
3026 : // for a 3.1 export a hack has to be installed, as in there is a BUG in
3027 : // SfxItemSet::Load, but not subsequently after 3.1.
3028 :
3029 : // The selected range must be kept after Store, because itemsets are not
3030 : // stored until then...
3031 :
3032 10704 : long nVersion = rStream.GetVersion();
3033 : bool b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) )
3034 10704 : ? sal_True : sal_False;
3035 :
3036 10704 : EditEngineItemPool* pThis = (EditEngineItemPool*)this;
3037 10704 : if ( b31Format )
3038 0 : pThis->SetStoringRange( 3997, 4022 );
3039 : else
3040 10704 : pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END );
3041 :
3042 10704 : return SfxItemPool::Store( rStream );
3043 669 : }
3044 :
3045 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|