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