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