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 823824 : sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, short nScriptType )
73 : {
74 823824 : sal_uInt16 nId = nItemId;
75 :
76 823824 : if ( ( nScriptType == i18n::ScriptType::ASIAN ) ||
77 : ( nScriptType == i18n::ScriptType::COMPLEX ) )
78 : {
79 190 : switch ( nItemId )
80 : {
81 : case EE_CHAR_LANGUAGE:
82 38 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
83 38 : break;
84 : case EE_CHAR_FONTINFO:
85 38 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
86 38 : break;
87 : case EE_CHAR_FONTHEIGHT:
88 38 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
89 38 : break;
90 : case EE_CHAR_WEIGHT:
91 38 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
92 38 : break;
93 : case EE_CHAR_ITALIC:
94 38 : nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
95 38 : break;
96 : }
97 : }
98 :
99 823824 : return nId;
100 : }
101 :
102 178274 : sal_Bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
103 : {
104 178274 : sal_Bool bValid = sal_True;
105 :
106 178274 : switch ( nItemId )
107 : {
108 : case EE_CHAR_LANGUAGE:
109 15104 : bValid = nScriptType == i18n::ScriptType::LATIN;
110 15104 : break;
111 : case EE_CHAR_LANGUAGE_CJK:
112 14788 : bValid = nScriptType == i18n::ScriptType::ASIAN;
113 14788 : break;
114 : case EE_CHAR_LANGUAGE_CTL:
115 216 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
116 216 : break;
117 : case EE_CHAR_FONTINFO:
118 14016 : bValid = nScriptType == i18n::ScriptType::LATIN;
119 14016 : break;
120 : case EE_CHAR_FONTINFO_CJK:
121 14534 : bValid = nScriptType == i18n::ScriptType::ASIAN;
122 14534 : break;
123 : case EE_CHAR_FONTINFO_CTL:
124 14534 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
125 14534 : break;
126 : case EE_CHAR_FONTHEIGHT:
127 14976 : bValid = nScriptType == i18n::ScriptType::LATIN;
128 14976 : break;
129 : case EE_CHAR_FONTHEIGHT_CJK:
130 14592 : bValid = nScriptType == i18n::ScriptType::ASIAN;
131 14592 : break;
132 : case EE_CHAR_FONTHEIGHT_CTL:
133 14592 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
134 14592 : break;
135 : case EE_CHAR_WEIGHT:
136 11704 : bValid = nScriptType == i18n::ScriptType::LATIN;
137 11704 : break;
138 : case EE_CHAR_WEIGHT_CJK:
139 11648 : bValid = nScriptType == i18n::ScriptType::ASIAN;
140 11648 : break;
141 : case EE_CHAR_WEIGHT_CTL:
142 11648 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
143 11648 : break;
144 : case EE_CHAR_ITALIC:
145 862 : bValid = nScriptType == i18n::ScriptType::LATIN;
146 862 : break;
147 : case EE_CHAR_ITALIC_CJK:
148 862 : bValid = nScriptType == i18n::ScriptType::ASIAN;
149 862 : break;
150 : case EE_CHAR_ITALIC_CTL:
151 862 : bValid = nScriptType == i18n::ScriptType::COMPLEX;
152 862 : break;
153 : }
154 :
155 178274 : 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 148468 : EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_uInt16 nS, sal_uInt16 nE )
259 : {
260 : // Create a new attribute in the pool
261 148468 : const SfxPoolItem& rNew = rPool.Put( rAttr );
262 :
263 148468 : EditCharAttrib* pNew = 0;
264 148468 : switch( rNew.Which() )
265 : {
266 : case EE_CHAR_LANGUAGE:
267 : case EE_CHAR_LANGUAGE_CJK:
268 : case EE_CHAR_LANGUAGE_CTL:
269 : {
270 25596 : pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE );
271 : }
272 25596 : break;
273 : case EE_CHAR_COLOR:
274 : {
275 12896 : pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE );
276 : }
277 12896 : break;
278 : case EE_CHAR_FONTINFO:
279 : case EE_CHAR_FONTINFO_CJK:
280 : case EE_CHAR_FONTINFO_CTL:
281 : {
282 35942 : pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE );
283 : }
284 35942 : break;
285 : case EE_CHAR_FONTHEIGHT:
286 : case EE_CHAR_FONTHEIGHT_CJK:
287 : case EE_CHAR_FONTHEIGHT_CTL:
288 : {
289 36060 : pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE );
290 : }
291 36060 : break;
292 : case EE_CHAR_FONTWIDTH:
293 : {
294 12 : pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE );
295 : }
296 12 : break;
297 : case EE_CHAR_WEIGHT:
298 : case EE_CHAR_WEIGHT_CJK:
299 : case EE_CHAR_WEIGHT_CTL:
300 : {
301 27650 : pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE );
302 : }
303 27650 : break;
304 : case EE_CHAR_UNDERLINE:
305 : {
306 720 : pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE );
307 : }
308 720 : break;
309 : case EE_CHAR_OVERLINE:
310 : {
311 32 : pNew = new EditCharAttribOverline( (const SvxOverlineItem&)rNew, nS, nE );
312 : }
313 32 : break;
314 : case EE_CHAR_EMPHASISMARK:
315 : {
316 32 : pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE );
317 : }
318 32 : break;
319 : case EE_CHAR_RELIEF:
320 : {
321 60 : pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE );
322 : }
323 60 : break;
324 : case EE_CHAR_STRIKEOUT:
325 : {
326 664 : pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE );
327 : }
328 664 : break;
329 : case EE_CHAR_ITALIC:
330 : case EE_CHAR_ITALIC_CJK:
331 : case EE_CHAR_ITALIC_CTL:
332 : {
333 2130 : pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE );
334 : }
335 2130 : break;
336 : case EE_CHAR_OUTLINE:
337 : {
338 502 : pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE );
339 : }
340 502 : break;
341 : case EE_CHAR_SHADOW:
342 : {
343 538 : pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE );
344 : }
345 538 : break;
346 : case EE_CHAR_ESCAPEMENT:
347 : {
348 964 : pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE );
349 : }
350 964 : break;
351 : case EE_CHAR_PAIRKERNING:
352 : {
353 12 : pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE );
354 : }
355 12 : break;
356 : case EE_CHAR_KERNING:
357 : {
358 146 : pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE );
359 : }
360 146 : break;
361 : case EE_CHAR_WLM:
362 : {
363 32 : pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE );
364 : }
365 32 : break;
366 : case EE_CHAR_XMLATTRIBS:
367 : {
368 12 : pNew = new EditCharAttrib( rNew, nS, nE ); // Attribute is only for holding XML information...
369 : }
370 12 : break;
371 : case EE_FEATURE_TAB:
372 : {
373 216 : pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS );
374 : }
375 216 : break;
376 : case EE_FEATURE_LINEBR:
377 : {
378 12 : pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS );
379 : }
380 12 : break;
381 : case EE_FEATURE_FIELD:
382 : {
383 4240 : pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS );
384 : }
385 4240 : break;
386 : default:
387 : {
388 : OSL_FAIL( "Invalid Attribute!" );
389 : }
390 : }
391 148468 : return pNew;
392 : }
393 :
394 70147 : TextPortionList::TextPortionList()
395 : {
396 70147 : }
397 :
398 138410 : TextPortionList::~TextPortionList()
399 : {
400 69205 : Reset();
401 69205 : }
402 :
403 80380 : void TextPortionList::Reset()
404 : {
405 80380 : maPortions.clear();
406 80380 : }
407 :
408 14530 : void TextPortionList::DeleteFromPortion(size_t nDelFrom)
409 : {
410 : DBG_ASSERT( ( nDelFrom < maPortions.size() ) || ( (nDelFrom == 0) && maPortions.empty() ), "DeleteFromPortion: Out of range" );
411 14530 : PortionsType::iterator it = maPortions.begin();
412 14530 : std::advance(it, nDelFrom);
413 14530 : maPortions.erase(it, maPortions.end());
414 14530 : }
415 :
416 193694 : size_t TextPortionList::Count() const
417 : {
418 193694 : return maPortions.size();
419 : }
420 :
421 1660 : const TextPortion* TextPortionList::operator[](size_t nPos) const
422 : {
423 1660 : return &maPortions[nPos];
424 : }
425 :
426 163968 : TextPortion* TextPortionList::operator[](size_t nPos)
427 : {
428 163968 : return &maPortions[nPos];
429 : }
430 :
431 54414 : void TextPortionList::Append(TextPortion* p)
432 : {
433 54414 : maPortions.push_back(p);
434 54414 : }
435 :
436 6914 : void TextPortionList::Insert(size_t nPos, TextPortion* p)
437 : {
438 6914 : maPortions.insert(maPortions.begin()+nPos, p);
439 6914 : }
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 232 : 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 232 : sal_uInt16 nTmpPos = 0;
477 232 : size_t n = maPortions.size();
478 272 : for (size_t i = 0; i < n; ++i)
479 : {
480 272 : const TextPortion& rPortion = maPortions[i];
481 272 : nTmpPos = nTmpPos + rPortion.GetLen();
482 272 : if ( nTmpPos >= nCharPos )
483 : {
484 : // take this one if we don't prefer the starting portion, or if it's the last one
485 232 : if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( i == n-1 ) )
486 : {
487 232 : nPortionStart = nTmpPos - rPortion.GetLen();
488 232 : 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 70147 : ParaPortion::ParaPortion( ContentNode* pN )
534 : {
535 : DBG_CTOR( EE_ParaPortion, 0 );
536 :
537 70147 : pNode = pN;
538 70147 : bInvalid = sal_True;
539 70147 : bVisible = sal_True;
540 70147 : bSimple = sal_False;
541 70147 : bForceRepaint = sal_False;
542 70147 : nInvalidPosStart = 0;
543 70147 : nInvalidDiff = 0;
544 70147 : nHeight = 0;
545 70147 : nFirstLineOffset = 0;
546 70147 : nBulletX = 0;
547 70147 : }
548 :
549 69205 : ParaPortion::~ParaPortion()
550 : {
551 : DBG_DTOR( EE_ParaPortion, 0 );
552 69205 : }
553 :
554 38688 : void ParaPortion::MarkInvalid( sal_uInt16 nStart, short nDiff )
555 : {
556 38688 : if ( bInvalid == sal_False )
557 : {
558 : // nInvalidPosEnd = nStart; // ??? => CreateLines
559 2408 : nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
560 2408 : nInvalidDiff = nDiff;
561 : }
562 : else
563 : {
564 : // Simple tap in succession
565 36280 : if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) &&
566 : ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) )
567 : {
568 648 : nInvalidDiff = nInvalidDiff + nDiff;
569 : }
570 : // Simple delete in succession
571 35632 : 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 35632 : nInvalidPosStart = Min( nInvalidPosStart, (sal_uInt16) ( nDiff < 0 ? nStart+nDiff : nDiff ) );
581 35632 : nInvalidDiff = 0;
582 35632 : bSimple = sal_False;
583 : }
584 : }
585 38688 : bInvalid = sal_True;
586 38688 : aScriptInfos.clear();
587 38688 : aWritingDirectionInfos.clear();
588 38688 : }
589 :
590 149735 : void ParaPortion::MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 /* nEnd */ )
591 : {
592 149735 : if ( bInvalid == sal_False )
593 : {
594 14929 : nInvalidPosStart = nStart;
595 : // nInvalidPosEnd = nEnd;
596 : }
597 : else
598 : {
599 134806 : nInvalidPosStart = Min( nInvalidPosStart, nStart );
600 : // nInvalidPosEnd = pNode->Len();
601 : }
602 149735 : nInvalidDiff = 0;
603 149735 : bInvalid = sal_True;
604 149735 : bSimple = sal_False;
605 149735 : aScriptInfos.clear();
606 149735 : aWritingDirectionInfos.clear();
607 149735 : }
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 8 : void ParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine )
631 : {
632 8 : sal_uInt16 nLines = aLineList.Count();
633 : DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Empty Portion?" );
634 8 : 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 8 : }
670 :
671 : // Shared reverse lookup acceleration pieces ...
672 :
673 : namespace {
674 :
675 : template<typename _Array, typename _Val>
676 870963 : size_t FastGetPos(const _Array& rArray, const _Val* p, size_t& rLastPos)
677 : {
678 870963 : 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 870963 : 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 1044249 : for (size_t nIdx = 0; nIdx < nArrayLen; ++nIdx)
702 1044249 : if (&rArray.at(nIdx) == p)
703 870963 : 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 9747 : ParaPortionList::ParaPortionList() : nLastCache( 0 )
712 : {
713 9747 : }
714 :
715 8805 : ParaPortionList::~ParaPortionList()
716 : {
717 8805 : }
718 :
719 144596 : sal_uInt16 ParaPortionList::GetPos(const ParaPortion* p) const
720 : {
721 144596 : return FastGetPos(maPortions, p, nLastCache);
722 : }
723 :
724 396392 : ParaPortion* ParaPortionList::operator [](size_t nPos)
725 : {
726 396392 : 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 566 : void ParaPortionList::Remove(size_t nPos)
740 : {
741 566 : maPortions.erase(maPortions.begin()+nPos);
742 566 : }
743 :
744 70147 : void ParaPortionList::Insert(size_t nPos, ParaPortion* p)
745 : {
746 70147 : maPortions.insert(maPortions.begin()+nPos, p);
747 70147 : }
748 :
749 0 : void ParaPortionList::Append(ParaPortion* p)
750 : {
751 0 : maPortions.push_back(p);
752 0 : }
753 :
754 343552 : size_t ParaPortionList::Count() const
755 : {
756 343552 : return maPortions.size();
757 : }
758 :
759 67562 : void ParaPortionList::Reset()
760 : {
761 67562 : maPortions.clear();
762 67562 : }
763 :
764 16 : long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
765 : {
766 16 : long nHeight = 0;
767 16 : for (size_t i = 0, n = maPortions.size(); i < n; ++i)
768 : {
769 16 : const ParaPortion* pTmpPortion = &maPortions[i];
770 16 : if ( pTmpPortion == pPPortion )
771 16 : 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 125111 : const ParaPortion* ParaPortionList::SafeGetObject(size_t nPos) const
791 : {
792 125111 : return nPos < maPortions.size() ? &maPortions[nPos] : NULL;
793 : }
794 :
795 196005 : ParaPortion* ParaPortionList::SafeGetObject(size_t nPos)
796 : {
797 196005 : 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 4252 : ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) :
814 4252 : aPrevParaAttribs( rParaAttribs)
815 : {
816 4252 : }
817 :
818 4252 : void ContentAttribsInfo::RemoveAllCharAttribsFromPool(SfxItemPool& rPool) const
819 : {
820 4252 : CharAttribsType::const_iterator it = aPrevCharAttribs.begin(), itEnd = aPrevCharAttribs.end();
821 27634 : for (; it != itEnd; ++it)
822 23382 : rPool.Remove(*it->GetItem());
823 4252 : }
824 :
825 23382 : void ContentAttribsInfo::AppendCharAttrib(EditCharAttrib* pNew)
826 : {
827 23382 : aPrevCharAttribs.push_back(pNew);
828 23382 : }
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 58866 : EditLine::EditLine() :
927 : bHangingPunctuation(false),
928 58866 : bInvalid(true)
929 : {
930 : DBG_CTOR( EE_EditLine, 0 );
931 :
932 58866 : nStart = nEnd = 0;
933 58866 : nStartPortion = 0; // to be able to tell the difference between a line
934 : // without Ptorions form one with the Portion number 0
935 58866 : nEndPortion = 0;
936 58866 : nHeight = 0;
937 58866 : nStartPosX = 0;
938 58866 : nTxtHeight = 0;
939 58866 : nTxtWidth = 0;
940 58866 : nCrsrHeight = 0;
941 58866 : nMaxAscent = 0;
942 58866 : }
943 :
944 14604 : EditLine::EditLine( const EditLine& r ) :
945 : bHangingPunctuation(r.bHangingPunctuation),
946 14604 : bInvalid(true)
947 : {
948 : DBG_CTOR( EE_EditLine, 0 );
949 :
950 14604 : nEnd = r.nEnd;
951 14604 : nStart = r.nStart;
952 14604 : nStartPortion = r.nStartPortion;
953 14604 : nEndPortion = r.nEndPortion;
954 :
955 14604 : nHeight = 0;
956 14604 : nStartPosX = 0;
957 14604 : nTxtHeight = 0;
958 14604 : nTxtWidth = 0;
959 14604 : nCrsrHeight = 0;
960 14604 : nMaxAscent = 0;
961 14604 : }
962 :
963 72636 : EditLine::~EditLine()
964 : {
965 : DBG_DTOR( EE_EditLine, 0 );
966 72636 : }
967 :
968 88154 : EditLine::CharPosArrayType& EditLine::GetCharPosArray()
969 : {
970 88154 : return aPositions;
971 : }
972 :
973 944 : const EditLine::CharPosArrayType& EditLine::GetCharPosArray() const
974 : {
975 944 : 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 6996 : EditLine& EditLine::operator = ( const EditLine& r )
1014 : {
1015 6996 : nEnd = r.nEnd;
1016 6996 : nStart = r.nStart;
1017 6996 : nEndPortion = r.nEndPortion;
1018 6996 : nStartPortion = r.nStartPortion;
1019 6996 : 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 66898 : void EditLine::SetHeight( sal_uInt16 nH, sal_uInt16 nTxtH, sal_uInt16 nCrsrH )
1029 : {
1030 66898 : nHeight = nH;
1031 66898 : nTxtHeight = ( nTxtH ? nTxtH : nH );
1032 66898 : nCrsrHeight = ( nCrsrH ? nCrsrH : nTxtHeight );
1033 66898 : }
1034 :
1035 59444 : void EditLine::SetStartPosX( long start )
1036 : {
1037 59444 : if (start > 0)
1038 5342 : nStartPosX = start;
1039 : else
1040 54102 : nStartPosX = 0;
1041 59444 : }
1042 :
1043 21600 : Size EditLine::CalcTextSize( ParaPortion& rParaPortion )
1044 : {
1045 21600 : Size aSz;
1046 21600 : Size aTmpSz;
1047 : TextPortion* pPortion;
1048 :
1049 21600 : sal_uInt16 nIndex = GetStart();
1050 :
1051 : DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize before CreatePortions !" );
1052 :
1053 45166 : for ( sal_uInt16 n = nStartPortion; n <= nEndPortion; n++ )
1054 : {
1055 23566 : pPortion = rParaPortion.GetTextPortions()[n];
1056 23566 : switch ( pPortion->GetKind() )
1057 : {
1058 : case PORTIONKIND_TEXT:
1059 : case PORTIONKIND_FIELD:
1060 : case PORTIONKIND_HYPHENATOR:
1061 : {
1062 23524 : aTmpSz = pPortion->GetSize();
1063 23524 : aSz.Width() += aTmpSz.Width();
1064 23524 : if ( aSz.Height() < aTmpSz.Height() )
1065 21606 : aSz.Height() = aTmpSz.Height();
1066 : }
1067 23524 : break;
1068 : case PORTIONKIND_TAB:
1069 : {
1070 36 : aSz.Width() += pPortion->GetSize().Width();
1071 : }
1072 36 : break;
1073 : }
1074 23566 : nIndex = nIndex + pPortion->GetLen();
1075 : }
1076 :
1077 21600 : SetHeight( (sal_uInt16)aSz.Height() );
1078 21600 : return aSz;
1079 : }
1080 :
1081 70147 : EditLineList::EditLineList()
1082 : {
1083 70147 : }
1084 :
1085 138410 : EditLineList::~EditLineList()
1086 : {
1087 69205 : Reset();
1088 69205 : }
1089 :
1090 80380 : void EditLineList::Reset()
1091 : {
1092 80380 : maLines.clear();
1093 80380 : }
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 32 : size_t EditLineList::FindLine(sal_uInt16 nChar, bool bInclEnd)
1104 : {
1105 32 : size_t n = maLines.size();
1106 32 : for (size_t i = 0; i < n; ++i)
1107 : {
1108 32 : const EditLine& rLine = maLines[i];
1109 48 : if ( (bInclEnd && (rLine.GetEnd() >= nChar)) ||
1110 16 : (rLine.GetEnd() > nChar) )
1111 : {
1112 32 : return i;
1113 : }
1114 : }
1115 :
1116 : DBG_ASSERT( !bInclEnd, "Line not found: FindLine" );
1117 0 : return n - 1;
1118 : }
1119 :
1120 468755 : size_t EditLineList::Count() const
1121 : {
1122 468755 : return maLines.size();
1123 : }
1124 :
1125 594 : const EditLine* EditLineList::operator[](size_t nPos) const
1126 : {
1127 594 : return &maLines[nPos];
1128 : }
1129 :
1130 203380 : EditLine* EditLineList::operator[](size_t nPos)
1131 : {
1132 203380 : return &maLines[nPos];
1133 : }
1134 :
1135 51874 : void EditLineList::Append(EditLine* p)
1136 : {
1137 51874 : maLines.push_back(p);
1138 51874 : }
1139 :
1140 6992 : void EditLineList::Insert(size_t nPos, EditLine* p)
1141 : {
1142 6992 : maLines.insert(maLines.begin()+nPos, p);
1143 6992 : }
1144 :
1145 420111 : EditPaM::EditPaM() : pNode(NULL), nIndex(0) {}
1146 396442 : EditPaM::EditPaM(const EditPaM& r) : pNode(r.pNode), nIndex(r.nIndex) {}
1147 344806 : EditPaM::EditPaM(ContentNode* p, sal_uInt16 n) : pNode(p), nIndex(n) {}
1148 :
1149 306323 : const ContentNode* EditPaM::GetNode() const
1150 : {
1151 306323 : return pNode;
1152 : }
1153 :
1154 854445 : ContentNode* EditPaM::GetNode()
1155 : {
1156 854445 : return pNode;
1157 : }
1158 :
1159 31671 : void EditPaM::SetNode(ContentNode* p)
1160 : {
1161 31671 : pNode = p;
1162 31671 : }
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 50212 : EditSelection::EditSelection()
1187 : {
1188 50212 : }
1189 :
1190 30862 : EditSelection::EditSelection( const EditPaM& rStartAndAnd )
1191 : {
1192 : // could still be optimized!
1193 : // do no first call the Def-constructor from PaM!
1194 30862 : aStartPaM = rStartAndAnd;
1195 30862 : aEndPaM = rStartAndAnd;
1196 30862 : }
1197 :
1198 121994 : EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd )
1199 : {
1200 : // could still be optimized!
1201 121994 : aStartPaM = rStart;
1202 121994 : aEndPaM = rEnd;
1203 121994 : }
1204 :
1205 124 : EditSelection& EditSelection::operator = ( const EditPaM& rPaM )
1206 : {
1207 124 : aStartPaM = rPaM;
1208 124 : aEndPaM = rPaM;
1209 124 : 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 88005 : 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 88005 : const ContentNode* pStartNode = aStartPaM.GetNode();
1231 88005 : const ContentNode* pEndNode = aEndPaM.GetNode();
1232 :
1233 88005 : sal_uInt16 nStartNode = rNodes.GetPos( pStartNode );
1234 88005 : 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 88005 : sal_Bool bSwap = sal_False;
1240 88005 : if ( nStartNode > nEndNode )
1241 0 : bSwap = sal_True;
1242 88005 : else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) )
1243 0 : bSwap = sal_True;
1244 :
1245 88005 : if ( bSwap )
1246 : {
1247 0 : EditPaM aTmpPaM( aStartPaM );
1248 0 : aStartPaM = aEndPaM;
1249 0 : aEndPaM = aTmpPaM;
1250 : }
1251 :
1252 88005 : return bSwap;
1253 : }
1254 :
1255 42763 : sal_Bool operator == ( const EditPaM& r1, const EditPaM& r2 )
1256 : {
1257 42763 : if ( r1.GetNode() != r2.GetNode() )
1258 924 : return sal_False;
1259 :
1260 41839 : if ( r1.GetIndex() != r2.GetIndex() )
1261 416 : return sal_False;
1262 :
1263 41423 : return sal_True;
1264 : }
1265 :
1266 474088 : EditPaM& EditPaM::operator = ( const EditPaM& rPaM )
1267 : {
1268 474088 : nIndex = rPaM.nIndex;
1269 474088 : pNode = rPaM.pNode;
1270 474088 : return *this;
1271 : }
1272 :
1273 42763 : sal_Bool operator != ( const EditPaM& r1, const EditPaM& r2 )
1274 : {
1275 42763 : return !( r1 == r2 );
1276 : }
1277 :
1278 68843 : ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool )
1279 : {
1280 : DBG_CTOR( EE_ContentNode, 0 );
1281 68843 : pWrongList = NULL;
1282 68843 : }
1283 :
1284 1304 : ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) :
1285 1304 : maString(rStr), aContentAttribs(rContentAttribs)
1286 : {
1287 : DBG_CTOR( EE_ContentNode, 0 );
1288 1304 : pWrongList = NULL;
1289 1304 : }
1290 :
1291 138410 : ContentNode::~ContentNode()
1292 : {
1293 : DBG_DTOR( EE_ContentNode, 0 );
1294 69205 : delete pWrongList;
1295 69205 : }
1296 :
1297 37252 : void ContentNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew, SfxItemPool& rItemPool )
1298 : {
1299 37252 : if ( !nNew )
1300 46278 : 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 28226 : bool bResort = false;
1309 28226 : bool bExpandedEmptyAtIndexNull = false;
1310 :
1311 28226 : size_t nAttr = 0;
1312 28226 : CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
1313 28226 : EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
1314 58842 : while ( pAttrib )
1315 : {
1316 2390 : if ( pAttrib->GetEnd() >= nIndex )
1317 : {
1318 : // Move all attributes behind the insertion point...
1319 2102 : if ( pAttrib->GetStart() > nIndex )
1320 : {
1321 516 : pAttrib->MoveForward( nNew );
1322 : }
1323 : // 0: Expand empty attribute, if at insertion point
1324 1586 : 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 980 : pAttrib->Expand( nNew );
1333 980 : if ( pAttrib->GetStart() == 0 )
1334 962 : bExpandedEmptyAtIndexNull = sal_True;
1335 : }
1336 : // 1: Attribute starts before, goes to index ...
1337 606 : 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 606 : if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
1344 : {
1345 294 : if ( !pAttrib->IsEdge() )
1346 294 : pAttrib->Expand( nNew );
1347 : }
1348 : else
1349 312 : 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 2390 : 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 2390 : 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 2390 : ++nAttr;
1416 2390 : pAttrib = GetAttrib(rAttribs, nAttr);
1417 : }
1418 :
1419 28226 : if ( bResort )
1420 302 : aCharAttribList.ResortAttribs();
1421 :
1422 28226 : if ( pWrongList )
1423 : {
1424 12864 : bool bSep = ( maString.GetChar( nIndex ) == ' ' ) || IsFeature( nIndex );
1425 12864 : 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 1310 : void ContentNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted, SfxItemPool& rItemPool )
1434 : {
1435 1310 : if ( !nDeleted )
1436 2442 : return;
1437 :
1438 : // Since features are treated differently than normal character attributes,
1439 : // can also the order of the start list be change!
1440 178 : bool bResort = false;
1441 178 : bool bDelAttr = false;
1442 178 : sal_uInt16 nEndChanges = nIndex+nDeleted;
1443 :
1444 178 : size_t nAttr = 0;
1445 178 : CharAttribList::AttribsType& rAttribs = aCharAttribList.GetAttribs();
1446 178 : EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
1447 448 : while ( pAttrib )
1448 : {
1449 92 : bDelAttr = false;
1450 92 : if ( pAttrib->GetEnd() >= nIndex )
1451 : {
1452 : // Move all Attribute behind the insert point...
1453 92 : if ( pAttrib->GetStart() >= nEndChanges )
1454 : {
1455 0 : pAttrib->MoveBackward( nDeleted );
1456 : }
1457 : // 1. Delete Internal attributes...
1458 92 : else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
1459 : {
1460 : // Special case: Attribute covers the area exactly
1461 : // => keep as empty Attribute.
1462 60 : if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
1463 0 : pAttrib->GetEnd() = nIndex; // empty
1464 : else
1465 60 : bDelAttr = sal_True;
1466 : }
1467 : // 2. Attribute starts earlier, ends inside or behind it ...
1468 32 : 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 32 : 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 92 : if ( bDelAttr )
1497 : {
1498 60 : bResort = true;
1499 60 : rItemPool.Remove( *pAttrib->GetItem() );
1500 60 : rAttribs.erase(rAttribs.begin()+nAttr);
1501 60 : nAttr--;
1502 : }
1503 32 : else if ( pAttrib->IsEmpty() )
1504 0 : aCharAttribList.SetHasEmptyAttribs(true);
1505 :
1506 92 : nAttr++;
1507 92 : pAttrib = GetAttrib(rAttribs, nAttr);
1508 : }
1509 :
1510 178 : if ( bResort )
1511 60 : aCharAttribList.ResortAttribs();
1512 :
1513 178 : if ( pWrongList )
1514 70 : 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 1304 : void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, sal_Bool bKeepEndingAttribs )
1522 : {
1523 : DBG_ASSERT( pPrevNode, "Copy of attributes to a null pointer?" );
1524 :
1525 1304 : sal_uInt16 nCut = pPrevNode->Len();
1526 :
1527 1304 : size_t nAttr = 0;
1528 1304 : CharAttribList::AttribsType& rPrevAttribs = pPrevNode->GetCharAttribs().GetAttribs();
1529 1304 : EditCharAttrib* pAttrib = GetAttrib(rPrevAttribs, nAttr);
1530 6526 : while ( pAttrib )
1531 : {
1532 3918 : if ( pAttrib->GetEnd() < nCut )
1533 : {
1534 : // remain unchanged ....
1535 : ;
1536 : }
1537 3040 : else if ( pAttrib->GetEnd() == nCut )
1538 : {
1539 : // must be copied as an empty attributes.
1540 3040 : if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
1541 : {
1542 2722 : EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 );
1543 : DBG_ASSERT( pNewAttrib, "MakeCharAttrib failed!" );
1544 2722 : 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 3918 : nAttr++;
1569 3918 : pAttrib = GetAttrib(rPrevAttribs, nAttr);
1570 : }
1571 1304 : }
1572 :
1573 566 : void ContentNode::AppendAttribs( ContentNode* pNextNode )
1574 : {
1575 : DBG_ASSERT( pNextNode, "Copy of attributes to a null pointer?" );
1576 :
1577 566 : 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 566 : size_t nAttr = 0;
1584 566 : CharAttribList::AttribsType& rNextAttribs = pNextNode->GetCharAttribs().GetAttribs();
1585 566 : EditCharAttrib* pAttrib = GetAttrib(rNextAttribs, nAttr);
1586 1132 : 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 566 : rNextAttribs.clear();
1625 :
1626 : #if OSL_DEBUG_LEVEL > 2
1627 : OSL_ENSURE( aCharAttribList.DbgCheckAttribs(), "Attribute after AppendAttribs broken" );
1628 : #endif
1629 566 : }
1630 :
1631 91607 : void ContentNode::CreateDefFont()
1632 : {
1633 : // First use the information from the style ...
1634 91607 : SfxStyleSheet* pS = aContentAttribs.GetStyleSheet();
1635 91607 : if ( pS )
1636 31752 : CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
1637 :
1638 : // ... then iron out the hard paragraph formatting...
1639 91607 : CreateFont( GetCharAttribs().GetDefFont(),
1640 183214 : GetContentAttribs().GetItems(), pS == NULL );
1641 91607 : }
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 45685 : void ContentNode::SetStyleSheet( SfxStyleSheet* pS, sal_Bool bRecalcFont )
1656 : {
1657 45685 : aContentAttribs.SetStyleSheet( pS );
1658 45685 : if ( bRecalcFont )
1659 14856 : CreateDefFont();
1660 45685 : }
1661 :
1662 16118 : void ContentNode::DestroyWrongList()
1663 : {
1664 16118 : delete pWrongList;
1665 16118 : pWrongList = NULL;
1666 16118 : }
1667 :
1668 12698 : bool ContentNode::IsFeature( sal_uInt16 nPos ) const
1669 : {
1670 12698 : return maString.GetChar(nPos) == CH_FEATURE;
1671 : }
1672 :
1673 1248648 : sal_uInt16 ContentNode::Len() const
1674 : {
1675 1248648 : return maString.Len();
1676 : }
1677 :
1678 81898 : const XubString& ContentNode::GetString() const
1679 : {
1680 81898 : 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 37252 : void ContentNode::Insert(const XubString& rStr, sal_uInt16 nPos)
1689 : {
1690 37252 : maString.Insert(rStr, nPos);
1691 37252 : }
1692 :
1693 566 : void ContentNode::Append(const XubString& rStr)
1694 : {
1695 566 : maString.Append(rStr);
1696 566 : }
1697 :
1698 1304 : void ContentNode::Erase(sal_uInt16 nPos)
1699 : {
1700 1304 : maString.Erase(nPos);
1701 1304 : }
1702 :
1703 1310 : void ContentNode::Erase(sal_uInt16 nPos, sal_uInt16 nCount)
1704 : {
1705 1310 : maString.Erase(nPos, nCount);
1706 1310 : }
1707 :
1708 1304 : XubString ContentNode::Copy(sal_uInt16 nPos) const
1709 : {
1710 1304 : return maString.Copy(nPos);
1711 : }
1712 :
1713 25972 : XubString ContentNode::Copy(sal_uInt16 nPos, sal_uInt16 nCount) const
1714 : {
1715 25972 : return maString.Copy(nPos, nCount);
1716 : }
1717 :
1718 18126 : sal_Unicode ContentNode::GetChar(sal_uInt16 nPos) const
1719 : {
1720 18126 : return maString.GetChar(nPos);
1721 : }
1722 :
1723 35961 : void ContentNode::CreateWrongList()
1724 : {
1725 : DBG_ASSERT( !pWrongList, "WrongList already exist!" );
1726 35961 : pWrongList = new WrongList;
1727 35961 : }
1728 :
1729 16106 : void ContentNode::SetWrongList( WrongList* p )
1730 : {
1731 : DBG_ASSERT( !pWrongList, "WrongList already exist!" );
1732 16106 : pWrongList = p;
1733 16106 : }
1734 :
1735 68843 : ContentAttribs::ContentAttribs( SfxItemPool& rPool ) :
1736 68843 : aAttribSet( rPool, EE_PARA_START, EE_CHAR_END )
1737 : {
1738 68843 : pStyle = 0;
1739 68843 : }
1740 :
1741 2608 : ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) :
1742 2608 : aAttribSet( rRef.aAttribSet )
1743 : {
1744 2608 : pStyle = rRef.pStyle;
1745 2608 : }
1746 :
1747 70509 : ContentAttribs::~ContentAttribs()
1748 : {
1749 70509 : }
1750 :
1751 36 : SvxTabStop ContentAttribs::FindTabStop( long nCurPos, sal_uInt16 nDefTab )
1752 : {
1753 36 : const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS );
1754 144 : for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
1755 : {
1756 140 : const SvxTabStop& rTab = rTabs[i];
1757 140 : if ( rTab.GetTabPos() > nCurPos )
1758 32 : return rTab;
1759 : }
1760 :
1761 : // Determine DefTab ...
1762 4 : SvxTabStop aTabStop;
1763 4 : long x = nCurPos / nDefTab + 1;
1764 4 : aTabStop.GetTabPos() = nDefTab * x;
1765 4 : return aTabStop;
1766 : }
1767 :
1768 45685 : void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
1769 : {
1770 45685 : sal_Bool bStyleChanged = ( pStyle != pS );
1771 45685 : pStyle = pS;
1772 : // Only when other style sheet, not when current style sheet modified
1773 45685 : 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 14856 : const SfxItemSet& rStyleAttribs = pStyle->GetItemSet();
1779 727944 : for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
1780 : {
1781 : // Don't change bullet on/off
1782 713088 : if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) )
1783 407286 : aAttribSet.ClearItem( nWhich );
1784 : }
1785 : }
1786 45685 : }
1787 :
1788 817680 : const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) const
1789 : {
1790 : // Hard paragraph attributes take precedence!
1791 817680 : const SfxItemSet* pTakeFrom = &aAttribSet;
1792 817680 : if ( pStyle && ( aAttribSet.GetItemState( nWhich, sal_False ) != SFX_ITEM_ON ) )
1793 172884 : pTakeFrom = &pStyle->GetItemSet();
1794 :
1795 817680 : return pTakeFrom->Get( nWhich );
1796 : }
1797 :
1798 5008 : bool ContentAttribs::HasItem( sal_uInt16 nWhich ) const
1799 : {
1800 5008 : bool bHasItem = false;
1801 5008 : if ( aAttribSet.GetItemState( nWhich, sal_False ) == SFX_ITEM_ON )
1802 0 : bHasItem = true;
1803 5008 : else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON )
1804 0 : bHasItem = true;
1805 :
1806 5008 : 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 9747 : EditDoc::EditDoc( SfxItemPool* pPool ) :
1838 : nLastCache(0),
1839 8 : pItemPool(pPool ? pPool : new EditEngineItemPool(false)),
1840 : nDefTab(DEFTAB),
1841 : bIsVertical(false),
1842 : bIsFixedCellHeight(false),
1843 : bOwnerOfPool(pPool ? false : true),
1844 9755 : bModified(false)
1845 : {
1846 : // Don't create a empty node, Clear() will be called in EditEngine-CTOR
1847 9747 : };
1848 :
1849 17610 : EditDoc::~EditDoc()
1850 : {
1851 8805 : ImplDestroyContents();
1852 8805 : if ( bOwnerOfPool )
1853 8 : SfxItemPool::Free(pItemPool);
1854 8805 : }
1855 :
1856 : namespace {
1857 :
1858 : class RemoveEachItemFromPool : std::unary_function<ContentNode, void>
1859 : {
1860 : EditDoc& mrDoc;
1861 : public:
1862 76367 : RemoveEachItemFromPool(EditDoc& rDoc) : mrDoc(rDoc) {}
1863 68639 : void operator() (const ContentNode& rNode)
1864 : {
1865 68639 : mrDoc.RemoveItemsFromPool(rNode);
1866 68639 : }
1867 : };
1868 :
1869 : }
1870 :
1871 76367 : void EditDoc::ImplDestroyContents()
1872 : {
1873 76367 : std::for_each(maContents.begin(), maContents.end(), RemoveEachItemFromPool(*this));
1874 76367 : maContents.clear();
1875 76367 : }
1876 :
1877 69205 : void EditDoc::RemoveItemsFromPool(const ContentNode& rNode)
1878 : {
1879 190169 : for (size_t nAttr = 0; nAttr < rNode.GetCharAttribs().Count(); ++nAttr)
1880 : {
1881 120964 : const EditCharAttrib& rAttr = rNode.GetCharAttribs().GetAttribs()[nAttr];
1882 120964 : GetItemPool().Remove(*rAttr.GetItem());
1883 : }
1884 69205 : }
1885 :
1886 161042 : void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType )
1887 : {
1888 161042 : Font aPrevFont( rFont );
1889 161042 : rFont.SetAlign( ALIGN_BASELINE );
1890 161042 : rFont.SetTransparent( sal_True );
1891 :
1892 161042 : sal_uInt16 nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
1893 161042 : sal_uInt16 nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
1894 161042 : sal_uInt16 nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType );
1895 161042 : sal_uInt16 nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType );
1896 161042 : sal_uInt16 nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType );
1897 :
1898 161042 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) )
1899 : {
1900 129290 : const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo );
1901 129290 : rFont.SetName( rFontItem.GetFamilyName() );
1902 129290 : rFont.SetFamily( rFontItem.GetFamily() );
1903 129290 : rFont.SetPitch( rFontItem.GetPitch() );
1904 129290 : rFont.SetCharSet( rFontItem.GetCharSet() );
1905 : }
1906 161042 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) )
1907 129290 : rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() );
1908 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) )
1909 129290 : rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() );
1910 161042 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) )
1911 130114 : rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) );
1912 161042 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) )
1913 129290 : rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() );
1914 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) )
1915 129290 : rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() );
1916 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SFX_ITEM_ON ) )
1917 129290 : rFont.SetOverline( ((const SvxOverlineItem&)rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() );
1918 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) )
1919 129290 : rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() );
1920 161042 : if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) )
1921 129290 : rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() );
1922 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) )
1923 129290 : rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() );
1924 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) )
1925 129290 : rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() );
1926 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) )
1927 : {
1928 129290 : const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT );
1929 :
1930 129290 : sal_uInt16 nProp = rEsc.GetProp();
1931 129290 : rFont.SetPropr( (sal_uInt8)nProp );
1932 :
1933 129290 : short nEsc = rEsc.GetEsc();
1934 129290 : if ( nEsc == DFLT_ESC_AUTO_SUPER )
1935 0 : nEsc = 100 - nProp;
1936 129290 : else if ( nEsc == DFLT_ESC_AUTO_SUB )
1937 0 : nEsc = sal::static_int_cast< short >( -( 100 - nProp ) );
1938 129290 : rFont.SetEscapement( nEsc );
1939 : }
1940 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) )
1941 129290 : rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() );
1942 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) )
1943 129290 : rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() );
1944 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) )
1945 129290 : rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() );
1946 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) )
1947 129290 : rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() );
1948 161042 : if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) )
1949 129290 : 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 161042 : if ( rFont == aPrevFont )
1956 122175 : rFont = aPrevFont; // => The same ImpPointer for IsSameInstance
1957 161042 : }
1958 :
1959 36733 : void EditDoc::CreateDefFont( sal_Bool bUseStyles )
1960 : {
1961 36733 : SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
1962 36733 : CreateFont( aDefFont, aTmpSet );
1963 36733 : aDefFont.SetVertical( IsVertical() );
1964 36733 : aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
1965 :
1966 73466 : for ( sal_uInt16 nNode = 0; nNode < Count(); nNode++ )
1967 : {
1968 36733 : ContentNode* pNode = GetObject( nNode );
1969 36733 : pNode->GetCharAttribs().GetDefFont() = aDefFont;
1970 36733 : if ( bUseStyles )
1971 0 : pNode->CreateDefFont();
1972 36733 : }
1973 36733 : }
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 726367 : size_t EditDoc::GetPos(const ContentNode* p) const
1980 : {
1981 726367 : return FastGetPos(maContents, p, nLastCache);
1982 : }
1983 :
1984 477915 : const ContentNode* EditDoc::GetObject(size_t nPos) const
1985 : {
1986 477915 : return nPos < maContents.size() ? &maContents[nPos] : NULL;
1987 : }
1988 :
1989 660410 : ContentNode* EditDoc::GetObject(size_t nPos)
1990 : {
1991 660410 : 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 113292 : ContentNode* EditDoc::operator[](size_t nPos)
2000 : {
2001 113292 : return GetObject(nPos);
2002 : }
2003 :
2004 70147 : void EditDoc::Insert(size_t nPos, ContentNode* p)
2005 : {
2006 70147 : maContents.insert(maContents.begin()+nPos, p);
2007 70147 : }
2008 :
2009 566 : void EditDoc::Remove(size_t nPos)
2010 : {
2011 566 : if (nPos >= maContents.size())
2012 566 : return;
2013 :
2014 566 : 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 227698 : size_t EditDoc::Count() const
2026 : {
2027 227698 : return maContents.size();
2028 : }
2029 :
2030 176 : rtl::OUString EditDoc::GetSepStr( LineEnd eEnd )
2031 : {
2032 176 : rtl::OUString aSep;
2033 176 : if ( eEnd == LINEEND_CR )
2034 0 : aSep = aCR;
2035 176 : else if ( eEnd == LINEEND_LF )
2036 176 : aSep = aLF;
2037 : else
2038 0 : aSep = aCRLF;
2039 176 : return aSep;
2040 : }
2041 :
2042 88 : XubString EditDoc::GetText( LineEnd eEnd ) const
2043 : {
2044 88 : sal_uLong nLen = GetTextLen();
2045 88 : size_t nNodes = Count();
2046 88 : if (nNodes == 0)
2047 0 : return rtl::OUString();
2048 :
2049 88 : rtl::OUString aSep = EditDoc::GetSepStr( eEnd );
2050 88 : sal_Int32 nSepSize = aSep.getLength();
2051 :
2052 88 : if ( nSepSize )
2053 88 : nLen += (nNodes - 1) * nSepSize;
2054 :
2055 88 : rtl_uString* newStr = rtl_uString_alloc(nLen);
2056 88 : sal_Unicode* pCur = newStr->buffer;
2057 88 : size_t nLastNode = nNodes-1;
2058 176 : for ( sal_uInt16 nNode = 0; nNode < nNodes; nNode++ )
2059 : {
2060 88 : String aTmp( GetParaAsString( GetObject(nNode) ) );
2061 88 : memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) );
2062 88 : pCur += aTmp.Len();
2063 88 : if ( nSepSize && ( nNode != nLastNode ) )
2064 : {
2065 0 : memcpy( pCur, aSep.getStr(), nSepSize*sizeof(sal_Unicode ) );
2066 0 : pCur += nSepSize;
2067 : }
2068 88 : }
2069 : assert(pCur - newStr->buffer == newStr->length);
2070 88 : return rtl::OUString(newStr, SAL_NO_ACQUIRE);
2071 : }
2072 :
2073 2520 : XubString EditDoc::GetParaAsString( sal_uInt16 nNode ) const
2074 : {
2075 2520 : return GetParaAsString( GetObject( nNode ) );
2076 : }
2077 :
2078 2696 : XubString EditDoc::GetParaAsString(
2079 : const ContentNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, bool bResolveFields) const
2080 : {
2081 2696 : if ( nEndPos > pNode->Len() )
2082 2608 : nEndPos = pNode->Len();
2083 :
2084 : DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" );
2085 :
2086 2696 : sal_uInt16 nIndex = nStartPos;
2087 2696 : XubString aStr;
2088 2696 : const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex );
2089 5776 : while ( nIndex < nEndPos )
2090 : {
2091 384 : sal_uInt16 nEnd = nEndPos;
2092 384 : if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
2093 126 : nEnd = pNextFeature->GetStart();
2094 : else
2095 258 : 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 384 : if (nEnd > nIndex)
2101 278 : aStr += XubString(pNode->GetString(), nIndex, nEnd - nIndex);
2102 :
2103 384 : if ( pNextFeature )
2104 : {
2105 126 : 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 126 : if ( bResolveFields )
2113 126 : aStr += static_cast<const EditCharAttribField*>(pNextFeature)->GetFieldValue();
2114 126 : break;
2115 : default: OSL_FAIL( "What feature?" );
2116 : }
2117 126 : pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd );
2118 : }
2119 384 : nIndex = nEnd;
2120 : }
2121 2696 : return aStr;
2122 : }
2123 :
2124 122171 : EditPaM EditDoc::GetStartPaM() const
2125 : {
2126 122171 : ContentNode* p = const_cast<ContentNode*>(GetObject(0));
2127 122171 : return EditPaM(p, 0);
2128 : }
2129 :
2130 5694 : EditPaM EditDoc::GetEndPaM() const
2131 : {
2132 5694 : ContentNode* pLastNode = const_cast<ContentNode*>(GetObject(Count()-1));
2133 5694 : return EditPaM( pLastNode, pLastNode->Len() );
2134 : }
2135 :
2136 88 : sal_uLong EditDoc::GetTextLen() const
2137 : {
2138 88 : sal_uLong nLen = 0;
2139 176 : for ( sal_uInt16 nNode = 0; nNode < Count(); nNode++ )
2140 : {
2141 88 : const ContentNode* pNode = GetObject( nNode );
2142 88 : nLen += pNode->Len();
2143 : // Fields can be longer than the placeholder in the Node
2144 88 : const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
2145 524 : for (size_t nAttr = rAttrs.size(); nAttr; )
2146 : {
2147 348 : const EditCharAttrib& rAttr = rAttrs[--nAttr];
2148 348 : 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 88 : return nLen;
2159 : }
2160 :
2161 36733 : EditPaM EditDoc::Clear()
2162 : {
2163 36733 : ImplDestroyContents();
2164 :
2165 36733 : ContentNode* pNode = new ContentNode( GetItemPool() );
2166 36733 : Insert(0, pNode);
2167 :
2168 36733 : CreateDefFont(false);
2169 :
2170 36733 : SetModified(false);
2171 :
2172 36733 : EditPaM aPaM( pNode, 0 );
2173 36733 : return aPaM;
2174 : }
2175 :
2176 293556 : void EditDoc::SetModified( bool b )
2177 : {
2178 293556 : bModified = b;
2179 293556 : if ( bModified )
2180 : {
2181 256787 : aModifyHdl.Call( NULL );
2182 : }
2183 293556 : }
2184 :
2185 30829 : EditPaM EditDoc::RemoveText()
2186 : {
2187 : // Keep the old ItemSet, to keep the chart Font.
2188 30829 : ContentNode* pPrevFirstNode = GetObject(0);
2189 30829 : SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet();
2190 30829 : SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() );
2191 30829 : Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() );
2192 :
2193 30829 : ImplDestroyContents();
2194 :
2195 30829 : ContentNode* pNode = new ContentNode( GetItemPool() );
2196 30829 : Insert(0, pNode);
2197 :
2198 30829 : pNode->SetStyleSheet(pPrevStyle, false);
2199 30829 : pNode->GetContentAttribs().GetItems().Set( aPrevSet );
2200 30829 : pNode->GetCharAttribs().GetDefFont() = aPrevFont;
2201 :
2202 30829 : SetModified(true);
2203 :
2204 30829 : EditPaM aPaM( pNode, 0 );
2205 30829 : return aPaM;
2206 : }
2207 :
2208 34792 : 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 34792 : aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() );
2216 34792 : aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() );
2217 34792 : aPaM.GetIndex() = aPaM.GetIndex() + rStr.Len();
2218 :
2219 34792 : SetModified( sal_True );
2220 :
2221 34792 : return aPaM;
2222 : }
2223 :
2224 1304 : EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, sal_Bool bKeepEndingAttribs )
2225 : {
2226 : DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" );
2227 1304 : ContentNode* pCurNode = aPaM.GetNode();
2228 1304 : sal_uInt16 nPos = GetPos( pCurNode );
2229 1304 : XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() );
2230 1304 : aPaM.GetNode()->Erase( aPaM.GetIndex() );
2231 :
2232 : // the paragraph attributes...
2233 1304 : ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() );
2234 :
2235 : // for a new paragraph we like to have the bullet/numbering visible by default
2236 1304 : aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, sal_True), EE_PARA_BULLETSTATE );
2237 :
2238 : // ContenNode constructor copies also the paragraph attributes
2239 1304 : ContentNode* pNode = new ContentNode( aStr, aContentAttribs );
2240 :
2241 : // Copy the Default Font
2242 1304 : pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont();
2243 1304 : SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet();
2244 1304 : if ( pStyle )
2245 : {
2246 824 : XubString aFollow( pStyle->GetFollow() );
2247 824 : if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) )
2248 : {
2249 0 : SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() );
2250 0 : pNode->SetStyleSheet( (SfxStyleSheet*)pNext );
2251 824 : }
2252 : }
2253 :
2254 : // Character attributes may need to be copied or trimmed:
2255 1304 : pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs );
2256 :
2257 1304 : Insert(nPos+1, pNode);
2258 :
2259 1304 : SetModified(true);
2260 :
2261 1304 : aPaM.SetNode( pNode );
2262 1304 : aPaM.SetIndex( 0 );
2263 1304 : return aPaM;
2264 : }
2265 :
2266 2460 : EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem )
2267 : {
2268 : DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" );
2269 :
2270 2460 : aPaM.GetNode()->Insert( rtl::OUString(CH_FEATURE), aPaM.GetIndex() );
2271 2460 : aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() );
2272 :
2273 : // Create a feature-attribute for the feature...
2274 2460 : EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 );
2275 : DBG_ASSERT( pAttrib, "Why can not the feature be created?" );
2276 2460 : aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib );
2277 :
2278 2460 : SetModified( sal_True );
2279 :
2280 2460 : aPaM.GetIndex()++;
2281 2460 : return aPaM;
2282 : }
2283 :
2284 566 : EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight )
2285 : {
2286 566 : const EditPaM aPaM( pLeft, pLeft->Len() );
2287 :
2288 : // First the attributes, otherwise nLen will not be correct!
2289 566 : pLeft->AppendAttribs( pRight );
2290 : // then the Text...
2291 566 : pLeft->Append(pRight->GetString());
2292 :
2293 : // the one to the right disappears.
2294 566 : RemoveItemsFromPool(*pRight);
2295 566 : sal_uInt16 nRight = GetPos( pRight );
2296 566 : Remove( nRight );
2297 :
2298 566 : SetModified(true);
2299 :
2300 566 : return aPaM;
2301 : }
2302 :
2303 1310 : EditPaM EditDoc::RemoveChars( EditPaM aPaM, sal_uInt16 nChars )
2304 : {
2305 : // Maybe remove Features!
2306 1310 : aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars );
2307 1310 : aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() );
2308 :
2309 1310 : SetModified( sal_True );
2310 :
2311 1310 : return aPaM;
2312 : }
2313 :
2314 28098 : 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 28098 : EditCharAttrib* pEndingAttrib = 0;
2322 : // This starts at the end of the selection => can be expanded
2323 28098 : EditCharAttrib* pStartingAttrib = 0;
2324 :
2325 : DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
2326 :
2327 28098 : RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
2328 :
2329 28098 : 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 28098 : else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
2339 78 : pStartingAttrib->GetStart() = nStart;
2340 28020 : else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
2341 7684 : pEndingAttrib->GetEnd() = nEnd;
2342 : else
2343 20336 : InsertAttrib( rPoolItem, pNode, nStart, nEnd );
2344 :
2345 28098 : if ( pStartingAttrib )
2346 78 : pNode->GetCharAttribs().ResortAttribs();
2347 :
2348 28098 : SetModified(true);
2349 28098 : }
2350 :
2351 38 : sal_Bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt16 nWhich )
2352 : {
2353 : EditCharAttrib* pStarting;
2354 : EditCharAttrib* pEnding;
2355 38 : return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
2356 : }
2357 :
2358 28136 : 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 28136 : rpEnding = 0;
2366 : // This starts at the end of the selection => can be expanded
2367 28136 : rpStarting = 0;
2368 :
2369 28136 : bool bChanged = false;
2370 :
2371 : DBG_ASSERT( nStart <= nEnd, "Small miscalculations in InsertAttribInSelection" );
2372 :
2373 : // iterate over the attributes ...
2374 28136 : size_t nAttr = 0;
2375 28136 : CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
2376 28136 : EditCharAttrib* pAttr = GetAttrib(rAttribs, nAttr);
2377 287928 : while ( pAttr )
2378 : {
2379 231752 : bool bRemoveAttrib = false;
2380 231752 : sal_uInt16 nAttrWhich = pAttr->Which();
2381 231752 : if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) )
2382 : {
2383 : // Attribute starts in Selection
2384 10680 : if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
2385 : {
2386 1160 : bChanged = sal_True;
2387 1160 : if ( pAttr->GetEnd() > nEnd )
2388 : {
2389 78 : pAttr->GetStart() = nEnd; // then it starts after this
2390 78 : rpStarting = pAttr;
2391 78 : if ( nWhich )
2392 78 : break; // There can be no further attributes here
2393 : }
2394 1082 : else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
2395 : {
2396 : // Delete feature only if on the exact spot
2397 1082 : bRemoveAttrib = sal_True;
2398 : }
2399 : }
2400 :
2401 : // Attribute ends in Selection
2402 9520 : else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
2403 : {
2404 8114 : bChanged = sal_True;
2405 8114 : if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
2406 : {
2407 8114 : pAttr->GetEnd() = nStart; // then it ends here
2408 8114 : 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 1406 : else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
2418 : {
2419 18 : bChanged = sal_True;
2420 18 : 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 18 : 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 18 : sal_uInt16 nOldEnd = pAttr->GetEnd();
2437 18 : pAttr->GetEnd() = nStart;
2438 18 : rpEnding = pAttr;
2439 18 : InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
2440 18 : if ( nWhich )
2441 18 : break; // There can be further attributes!
2442 : }
2443 : }
2444 : }
2445 231656 : 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 1082 : GetItemPool().Remove( *pAttr->GetItem() );
2450 1082 : rAttribs.erase(rAttribs.begin()+nAttr);
2451 1082 : nAttr--;
2452 : }
2453 231656 : nAttr++;
2454 231656 : pAttr = GetAttrib(rAttribs, nAttr);
2455 : }
2456 :
2457 28136 : if ( bChanged )
2458 : {
2459 : // char attributes need to be sorted by start again
2460 9292 : pNode->GetCharAttribs().ResortAttribs();
2461 9292 : SetModified(true);
2462 : }
2463 :
2464 28136 : return bChanged;
2465 : }
2466 :
2467 23968 : 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 23968 : EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd );
2472 : DBG_ASSERT( pAttrib, "MakeCharAttrib failed!" );
2473 23968 : pNode->GetCharAttribs().InsertAttrib( pAttrib );
2474 :
2475 23968 : SetModified( sal_True );
2476 23968 : }
2477 :
2478 32078 : void EditDoc::InsertAttrib( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem )
2479 : {
2480 32078 : if ( nStart != nEnd )
2481 : {
2482 28098 : InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
2483 : }
2484 : else
2485 : {
2486 : // Check whether already a new attribute with WhichId exists at this place:
2487 3980 : CharAttribList& rAttrList = pNode->GetCharAttribs();
2488 3980 : EditCharAttrib* pAttr = rAttrList.FindEmptyAttrib( rPoolItem.Which(), nStart );
2489 3980 : if ( pAttr )
2490 : {
2491 : // Remove attribute....
2492 554 : rAttrList.Release(pAttr);
2493 : }
2494 :
2495 : // check whether 'the same' attribute exist at this place.
2496 3980 : pAttr = rAttrList.FindAttrib( rPoolItem.Which(), nStart );
2497 3980 : if ( pAttr )
2498 : {
2499 384 : 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 384 : else if ( pAttr->GetEnd() == nStart )
2508 : {
2509 : DBG_ASSERT( !pAttr->IsEmpty(), "Still an empty attribute?" );
2510 : // Check if exactly the same attribute
2511 384 : if ( *(pAttr->GetItem()) == rPoolItem )
2512 32444 : return;
2513 : }
2514 : }
2515 3614 : InsertAttrib( rPoolItem, pNode, nStart, nStart );
2516 : }
2517 :
2518 31712 : SetModified( sal_True );
2519 : }
2520 :
2521 1040 : 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 1040 : sal_uInt16 nAttr = 0;
2527 1040 : EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2528 : // No Selection...
2529 1040 : if ( nStartPos == nEndPos )
2530 : {
2531 3924 : while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
2532 : {
2533 1984 : const SfxPoolItem* pItem = 0;
2534 : // Attribute is about...
2535 1984 : if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
2536 0 : pItem = pAttr->GetItem();
2537 : // Attribute ending here is not empty
2538 1984 : 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 1984 : else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
2545 : {
2546 106 : pItem = pAttr->GetItem();
2547 : }
2548 : // Attribute starts here
2549 1878 : else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
2550 : {
2551 1878 : if ( nStartPos == 0 ) // special case
2552 1878 : pItem = pAttr->GetItem();
2553 : }
2554 :
2555 1984 : if ( pItem )
2556 : {
2557 1984 : sal_uInt16 nWhich = pItem->Which();
2558 1984 : if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
2559 : {
2560 1984 : 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 1984 : nAttr++;
2572 1984 : pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2573 : }
2574 : }
2575 : else // Selection
2576 : {
2577 202 : while ( pAttr && ( pAttr->GetStart() < nEndPos) )
2578 : {
2579 62 : const SfxPoolItem* pItem = 0;
2580 : // Attribut is about...
2581 62 : if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
2582 28 : pItem = pAttr->GetItem();
2583 : // Attribute starts right in the middle ...
2584 34 : 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 34 : 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 62 : if ( pItem )
2606 : {
2607 28 : sal_uInt16 nWhich = pItem->Which();
2608 28 : if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
2609 : {
2610 28 : 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 62 : nAttr++;
2622 62 : pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2623 : }
2624 : }
2625 1040 : }
2626 :
2627 : namespace {
2628 :
2629 : struct LessByStart : std::binary_function<EditCharAttrib, EditCharAttrib, bool>
2630 : {
2631 270050 : bool operator() (const EditCharAttrib& left, const EditCharAttrib& right) const
2632 : {
2633 270050 : return left.GetStart() < right.GetStart();
2634 : }
2635 : };
2636 :
2637 : }
2638 :
2639 70147 : CharAttribList::CharAttribList()
2640 : {
2641 : DBG_CTOR( EE_CharAttribList, 0 );
2642 70147 : bHasEmptyAttribs = sal_False;
2643 70147 : }
2644 :
2645 69205 : CharAttribList::~CharAttribList()
2646 : {
2647 : DBG_DTOR( EE_CharAttribList, 0 );
2648 69205 : }
2649 :
2650 125086 : 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 125086 : const sal_uInt16 nStart = pAttrib->GetStart(); // may be better for Comp.Opt.
2662 :
2663 125086 : if ( pAttrib->IsEmpty() )
2664 15136 : bHasEmptyAttribs = true;
2665 :
2666 792546 : for (size_t i = 0, n = aAttribs.size(); i < n; ++i)
2667 : {
2668 669386 : const EditCharAttrib& rCurAttrib = aAttribs[i];
2669 669386 : if (rCurAttrib.GetStart() > nStart)
2670 : {
2671 1926 : aAttribs.insert(aAttribs.begin()+i, pAttrib);
2672 127012 : return;
2673 : }
2674 : }
2675 :
2676 123160 : aAttribs.push_back(pAttrib);
2677 : }
2678 :
2679 9732 : void CharAttribList::ResortAttribs()
2680 : {
2681 9732 : aAttribs.sort(LessByStart());
2682 9732 : }
2683 :
2684 2014 : void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
2685 : {
2686 7470 : for (size_t i = 0; i < aAttribs.size(); ++i)
2687 : {
2688 5456 : EditCharAttrib& rAttr = aAttribs[i];
2689 31688 : for (size_t nNext = i+1; nNext < aAttribs.size(); ++nNext)
2690 : {
2691 26726 : EditCharAttrib& rNext = aAttribs[nNext];
2692 26726 : if (!rAttr.IsFeature() && rNext.GetStart() == rAttr.GetEnd() && rNext.Which() == rAttr.Which())
2693 : {
2694 68 : if (*rNext.GetItem() == *rAttr.GetItem())
2695 : {
2696 18 : rAttr.GetEnd() = rNext.GetEnd();
2697 18 : rItemPool.Remove(*rNext.GetItem());
2698 18 : aAttribs.erase(aAttribs.begin()+nNext);
2699 : }
2700 68 : break; // only 1 attr with same which can start here.
2701 : }
2702 26658 : else if (rNext.GetStart() > rAttr.GetEnd())
2703 : {
2704 426 : break;
2705 : }
2706 : }
2707 : }
2708 2014 : }
2709 :
2710 249197 : size_t CharAttribList::Count() const
2711 : {
2712 249197 : return aAttribs.size();
2713 : }
2714 :
2715 18474 : 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 18474 : AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2720 37826 : for (; it != itEnd; ++it)
2721 : {
2722 22186 : const EditCharAttrib& rAttr = *it;
2723 22186 : if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
2724 2834 : return &rAttr;
2725 : }
2726 15640 : return NULL;
2727 : }
2728 :
2729 10202 : 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 10202 : AttribsType::reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2734 57698 : for (; it != itEnd; ++it)
2735 : {
2736 48264 : EditCharAttrib& rAttr = *it;
2737 48264 : if (rAttr.Which() == nWhich && rAttr.IsIn(nPos))
2738 768 : return &rAttr;
2739 : }
2740 9434 : return NULL;
2741 : }
2742 :
2743 33320 : const EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos ) const
2744 : {
2745 : DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
2746 33320 : AttribsType::const_iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2747 150636 : for (; it != itEnd; ++it)
2748 : {
2749 123106 : const EditCharAttrib& rAttr = *it;
2750 123106 : if (rAttr.GetStart() >= nFromPos && rAttr.Which() == nWhich)
2751 5790 : return &rAttr;
2752 : }
2753 27530 : 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 359382 : CharAttribList::AttribsType& CharAttribList::GetAttribs()
2769 : {
2770 359382 : return aAttribs;
2771 : }
2772 :
2773 121194 : const CharAttribList::AttribsType& CharAttribList::GetAttribs() const
2774 : {
2775 121194 : return aAttribs;
2776 : }
2777 :
2778 : namespace {
2779 :
2780 : class FindByAddress : std::unary_function<EditCharAttrib, bool>
2781 : {
2782 : const EditCharAttrib* mpAttr;
2783 : public:
2784 554 : FindByAddress(const EditCharAttrib* p) : mpAttr(p) {}
2785 820 : bool operator() (const EditCharAttrib& r) const
2786 : {
2787 820 : 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 2350 : void CharAttribList::Remove(size_t nPos)
2801 : {
2802 2350 : if (nPos >= aAttribs.size())
2803 2350 : return;
2804 :
2805 2350 : aAttribs.erase(aAttribs.begin()+nPos);
2806 : }
2807 :
2808 554 : void CharAttribList::Release(const EditCharAttrib* p)
2809 : {
2810 554 : AttribsType::iterator it = std::find_if(aAttribs.begin(), aAttribs.end(), FindByAddress(p));
2811 554 : if (it != aAttribs.end())
2812 554 : aAttribs.release(it).release();
2813 554 : }
2814 :
2815 0 : void CharAttribList::SetHasEmptyAttribs(bool b)
2816 : {
2817 0 : bHasEmptyAttribs = b;
2818 0 : }
2819 :
2820 68 : 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 68 : AttribsType::const_reverse_iterator it = aAttribs.rbegin(), itEnd = aAttribs.rend();
2825 68 : for (; it != itEnd; ++it)
2826 : {
2827 4 : const EditCharAttrib& rAttr = *it;
2828 4 : if (rAttr.GetEnd() < nBound)
2829 0 : return false;
2830 :
2831 4 : if (rAttr.GetStart() == nBound || rAttr.GetEnd() == nBound)
2832 4 : return true;
2833 : }
2834 64 : 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 4292 : EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
2853 : {
2854 4292 : if ( !bHasEmptyAttribs )
2855 424 : return NULL;
2856 :
2857 3868 : AttribsType::iterator it = aAttribs.begin(), itEnd = aAttribs.end();
2858 29266 : for (; it != itEnd; ++it)
2859 : {
2860 25970 : EditCharAttrib& rAttr = *it;
2861 25970 : if (rAttr.GetStart() == nPos && rAttr.GetEnd() == nPos && rAttr.Which() == nWhich)
2862 572 : return &rAttr;
2863 : }
2864 3296 : return NULL;
2865 : }
2866 :
2867 : namespace {
2868 :
2869 : class FindByStartPos : std::unary_function<EditCharAttrib, bool>
2870 : {
2871 : sal_uInt16 mnPos;
2872 : public:
2873 26434 : FindByStartPos(sal_uInt16 nPos) : mnPos(nPos) {}
2874 36952 : bool operator() (const EditCharAttrib& r) const
2875 : {
2876 36952 : return r.GetStart() >= mnPos;
2877 : }
2878 : };
2879 :
2880 : }
2881 :
2882 26434 : 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 26434 : std::find_if(aAttribs.begin(), aAttribs.end(), FindByStartPos(nPos));
2887 :
2888 26434 : if (it == aAttribs.end())
2889 : // All attributes are before the specified position.
2890 19784 : return NULL;
2891 :
2892 : // And find the first attribute with feature.
2893 6650 : it = std::find_if(it, aAttribs.end(), boost::bind(&EditCharAttrib::IsFeature, _1) == true);
2894 6650 : 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 296 : RemoveEmptyAttrItem(SfxItemPool& rPool) : mrItemPool(rPool) {}
2904 2482 : void operator() (const EditCharAttrib& r)
2905 : {
2906 2482 : if (r.IsEmpty())
2907 0 : mrItemPool.Remove(*r.GetItem());
2908 2482 : }
2909 : };
2910 :
2911 : }
2912 :
2913 296 : void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool )
2914 : {
2915 296 : std::for_each(aAttribs.begin(), aAttribs.end(), RemoveEmptyAttrItem(rItemPool));
2916 296 : aAttribs.erase_if(boost::bind(&EditCharAttrib::IsEmpty, _1) == true);
2917 296 : bHasEmptyAttribs = false;
2918 296 : }
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 16881 : EditEngineItemPool::EditEngineItemPool( sal_Bool bPersistenRefCounts )
2984 : : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END,
2985 16881 : aItemInfos, 0, bPersistenRefCounts )
2986 : {
2987 16881 : SetVersionMap( 1, 3999, 4015, aV1Map );
2988 16881 : SetVersionMap( 2, 3999, 4019, aV2Map );
2989 16881 : SetVersionMap( 3, 3997, 4020, aV3Map );
2990 16881 : SetVersionMap( 4, 3994, 4022, aV4Map );
2991 16881 : SetVersionMap( 5, 3994, 4037, aV5Map );
2992 :
2993 16881 : SfxPoolItem** ppDefItems = EE_DLL().GetGlobalData()->GetDefItems();
2994 16881 : SetDefaults( ppDefItems );
2995 16881 : }
2996 :
2997 28342 : EditEngineItemPool::~EditEngineItemPool()
2998 : {
2999 28342 : }
3000 :
3001 2368 : 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 2368 : long nVersion = rStream.GetVersion();
3010 : sal_Bool b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) )
3011 2368 : ? sal_True : sal_False;
3012 :
3013 2368 : EditEngineItemPool* pThis = (EditEngineItemPool*)this;
3014 2368 : if ( b31Format )
3015 0 : pThis->SetStoringRange( 3997, 4022 );
3016 : else
3017 2368 : pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END );
3018 :
3019 2368 : return SfxItemPool::Store( rStream );
3020 234 : }
3021 :
3022 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|