xref: /AOO42X/main/editeng/source/editeng/editdoc.cxx (revision b1c5455db1639c48e26c568e4fa7ee78ca5d60ee)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_editeng.hxx"
26 
27 #include <vcl/wrkwin.hxx>
28 #include <vcl/dialog.hxx>
29 #include <vcl/msgbox.hxx>
30 #include <vcl/svapp.hxx>
31 
32 #include <editeng/tstpitem.hxx>
33 #include <editeng/colritem.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/crsditem.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <editeng/postitem.hxx>
38 #include <editeng/kernitem.hxx>
39 #include <editeng/wrlmitem.hxx>
40 #include <editeng/wghtitem.hxx>
41 #include <editeng/udlnitem.hxx>
42 #include <editeng/cntritem.hxx>
43 #include <editeng/escpitem.hxx>
44 #include <editeng/shdditem.hxx>
45 #include <editeng/akrnitem.hxx>
46 #include <editeng/cscoitem.hxx>
47 #include <editeng/langitem.hxx>
48 #include <editeng/emphitem.hxx>
49 #include <editeng/charscaleitem.hxx>
50 #include <editeng/charreliefitem.hxx>
51 #include <editeng/xmlcnitm.hxx>
52 #include <editeng/editids.hrc>
53 
54 #include <editdoc.hxx>
55 #include <editdbg.hxx>
56 #include <editeng/eerdll.hxx>
57 #include <eerdll2.hxx>
58 #include <tools/stream.hxx>
59 #include <tools/debug.hxx>
60 #include <tools/shl.hxx>
61 #include <vcl/svapp.hxx>
62 #include <com/sun/star/i18n/ScriptType.hpp>
63 #include <stdlib.h> // qsort
64 
65 using namespace ::com::sun::star;
66 
67 
68 // ------------------------------------------------------------
69 
GetScriptItemId(sal_uInt16 nItemId,short nScriptType)70 sal_uInt16 GetScriptItemId( sal_uInt16 nItemId, short nScriptType )
71 {
72     sal_uInt16 nId = nItemId;
73 
74     if ( ( nScriptType == i18n::ScriptType::ASIAN ) ||
75          ( nScriptType == i18n::ScriptType::COMPLEX ) )
76     {
77         switch ( nItemId )
78         {
79             case EE_CHAR_LANGUAGE:
80                 nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL;
81             break;
82             case EE_CHAR_FONTINFO:
83                 nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL;
84             break;
85             case EE_CHAR_FONTHEIGHT:
86                 nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL;
87             break;
88             case EE_CHAR_WEIGHT:
89                 nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL;
90             break;
91             case EE_CHAR_ITALIC:
92                 nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL;
93             break;
94         }
95     }
96 
97     return nId;
98 }
99 
IsScriptItemValid(sal_uInt16 nItemId,short nScriptType)100 sal_Bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
101 {
102     sal_Bool bValid = sal_True;
103 
104     switch ( nItemId )
105     {
106         case EE_CHAR_LANGUAGE:
107             bValid = nScriptType == i18n::ScriptType::LATIN;
108         break;
109         case EE_CHAR_LANGUAGE_CJK:
110             bValid = nScriptType == i18n::ScriptType::ASIAN;
111         break;
112         case EE_CHAR_LANGUAGE_CTL:
113             bValid = nScriptType == i18n::ScriptType::COMPLEX;
114         break;
115         case EE_CHAR_FONTINFO:
116             bValid = nScriptType == i18n::ScriptType::LATIN;
117         break;
118         case EE_CHAR_FONTINFO_CJK:
119             bValid = nScriptType == i18n::ScriptType::ASIAN;
120         break;
121         case EE_CHAR_FONTINFO_CTL:
122             bValid = nScriptType == i18n::ScriptType::COMPLEX;
123         break;
124         case EE_CHAR_FONTHEIGHT:
125             bValid = nScriptType == i18n::ScriptType::LATIN;
126         break;
127         case EE_CHAR_FONTHEIGHT_CJK:
128             bValid = nScriptType == i18n::ScriptType::ASIAN;
129         break;
130         case EE_CHAR_FONTHEIGHT_CTL:
131             bValid = nScriptType == i18n::ScriptType::COMPLEX;
132         break;
133         case EE_CHAR_WEIGHT:
134             bValid = nScriptType == i18n::ScriptType::LATIN;
135         break;
136         case EE_CHAR_WEIGHT_CJK:
137             bValid = nScriptType == i18n::ScriptType::ASIAN;
138         break;
139         case EE_CHAR_WEIGHT_CTL:
140             bValid = nScriptType == i18n::ScriptType::COMPLEX;
141         break;
142         case EE_CHAR_ITALIC:
143             bValid = nScriptType == i18n::ScriptType::LATIN;
144         break;
145         case EE_CHAR_ITALIC_CJK:
146             bValid = nScriptType == i18n::ScriptType::ASIAN;
147         break;
148         case EE_CHAR_ITALIC_CTL:
149             bValid = nScriptType == i18n::ScriptType::COMPLEX;
150         break;
151     }
152 
153     return bValid;
154 }
155 
156 
157 // ------------------------------------------------------------
158 
159 // Sollte spaeter zentral nach TOOLS/STRING (Aktuell: 303)
160 // fuer Grep: WS_TARGET
161 
162 DBG_NAME( EE_TextPortion );
163 DBG_NAME( EE_EditLine );
164 DBG_NAME( EE_ContentNode );
165 DBG_NAME( EE_CharAttribList );
166 
167 SfxItemInfo aItemInfos[EDITITEMCOUNT] = {
168         { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE },         // EE_PARA_WRITINGDIR
169         { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_XMLATTRIBS
170         { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE },   // EE_PARA_HANGINGPUNCTUATION
171         { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE },
172         { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE },       // EE_PARA_ASIANCJKSPACING
173         { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE },         // EE_PARA_NUMBULL
174         { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_HYPHENATE
175         { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_BULLETSTATE
176         { 0, SFX_ITEM_POOLABLE },                               // EE_PARA_OUTLLRSPACE
177         { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE },
178         { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE },
179         { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE },
180         { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE },
181         { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE },
182         { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE },
183         { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE },
184         { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE },
185         { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE },
186         { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE },
187         { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE },
188         { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE },
189         { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE },
190         { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE },
191         { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE },
192         { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE },
193         { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE },
194         { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE },
195         { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE },
196         { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE },
197         { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE },
198         { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE },
199         { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE },
200         { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE },
201         { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE },
202         { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE },
203         { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE },
204         { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE },
205         { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE },
206         { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE },
207         { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE },
208         { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE },
209         { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE },
210         { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE },
211         { 0, SFX_ITEM_POOLABLE },                           // EE_CHAR_RUBI_DUMMY
212         { 0, SFX_ITEM_POOLABLE },                           // EE_CHAR_XMLATTRIBS
213         { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE },
214         { 0, SFX_ITEM_POOLABLE },                           // EE_FEATURE_TAB
215         { 0, SFX_ITEM_POOLABLE },                           // EE_FEATURE_LINEBR
216         { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE },  // EE_FEATURE_NOTCONV
217         { SID_FIELD, SFX_ITEM_POOLABLE }
218 };
219 
220 sal_uInt16 aV1Map[] = {
221     3999, 4001, 4002, 4003, 4004, 4005, 4006,
222     4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019?
223 };
224 
225 sal_uInt16 aV2Map[] = {
226     3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009,
227     4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020
228 };
229 
230 sal_uInt16 aV3Map[] = {
231     3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007,
232     4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019,
233     4020, 4021
234 };
235 
236 sal_uInt16 aV4Map[] = {
237     3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
238     4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
239     4014, 4015, 4016, 4017, 4018,
240     /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */
241     4034, 4035, 4036, 4037
242 };
243 
244 sal_uInt16 aV5Map[] = {
245     3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003,
246     4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013,
247     4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023,
248     4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033,
249     /* EE_CHAR_OVERLINE inserted here */
250     4035, 4036, 4037, 4038
251 };
252 
CompareStart(const void * pFirst,const void * pSecond)253 int SAL_CALL CompareStart( const void* pFirst, const void* pSecond )
254 {
255     if ( (*((EditCharAttrib**)pFirst))->GetStart() < (*((EditCharAttrib**)pSecond))->GetStart() )
256         return (-1);
257     else if ( (*((EditCharAttrib**)pFirst))->GetStart() > (*((EditCharAttrib**)pSecond))->GetStart() )
258         return (1);
259     return 0;
260 }
261 
MakeCharAttrib(SfxItemPool & rPool,const SfxPoolItem & rAttr,sal_uInt16 nS,sal_uInt16 nE)262 EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_uInt16 nS, sal_uInt16 nE )
263 {
264     // das neue Attribut im Pool anlegen
265     const SfxPoolItem& rNew = rPool.Put( rAttr );
266 
267     EditCharAttrib* pNew = 0;
268     switch( rNew.Which() )
269     {
270         case EE_CHAR_LANGUAGE:
271         case EE_CHAR_LANGUAGE_CJK:
272         case EE_CHAR_LANGUAGE_CTL:
273         {
274             pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE );
275         }
276         break;
277         case EE_CHAR_COLOR:
278         {
279             pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE );
280         }
281         break;
282         case EE_CHAR_FONTINFO:
283         case EE_CHAR_FONTINFO_CJK:
284         case EE_CHAR_FONTINFO_CTL:
285         {
286             pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE );
287         }
288         break;
289         case EE_CHAR_FONTHEIGHT:
290         case EE_CHAR_FONTHEIGHT_CJK:
291         case EE_CHAR_FONTHEIGHT_CTL:
292         {
293             pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE );
294         }
295         break;
296         case EE_CHAR_FONTWIDTH:
297         {
298             pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE );
299         }
300         break;
301         case EE_CHAR_WEIGHT:
302         case EE_CHAR_WEIGHT_CJK:
303         case EE_CHAR_WEIGHT_CTL:
304         {
305             pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE );
306         }
307         break;
308         case EE_CHAR_UNDERLINE:
309         {
310             pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE );
311         }
312         break;
313         case EE_CHAR_OVERLINE:
314         {
315             pNew = new EditCharAttribOverline( (const SvxOverlineItem&)rNew, nS, nE );
316         }
317         break;
318         case EE_CHAR_EMPHASISMARK:
319         {
320             pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE );
321         }
322         break;
323         case EE_CHAR_RELIEF:
324         {
325             pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE );
326         }
327         break;
328         case EE_CHAR_STRIKEOUT:
329         {
330             pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE );
331         }
332         break;
333         case EE_CHAR_ITALIC:
334         case EE_CHAR_ITALIC_CJK:
335         case EE_CHAR_ITALIC_CTL:
336         {
337             pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE );
338         }
339         break;
340         case EE_CHAR_OUTLINE:
341         {
342             pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE );
343         }
344         break;
345         case EE_CHAR_SHADOW:
346         {
347             pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE );
348         }
349         break;
350         case EE_CHAR_ESCAPEMENT:
351         {
352             pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE );
353         }
354         break;
355         case EE_CHAR_PAIRKERNING:
356         {
357             pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE );
358         }
359         break;
360         case EE_CHAR_KERNING:
361         {
362             pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE );
363         }
364         break;
365         case EE_CHAR_WLM:
366         {
367             pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE );
368         }
369         break;
370         case EE_CHAR_XMLATTRIBS:
371         {
372             pNew = new EditCharAttrib( rNew, nS, nE );  // Attrib is only for holding XML information...
373         }
374         break;
375         case EE_FEATURE_TAB:
376         {
377             pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS );
378         }
379         break;
380         case EE_FEATURE_LINEBR:
381         {
382             pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS );
383         }
384         break;
385         case EE_FEATURE_FIELD:
386         {
387             pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS );
388         }
389         break;
390         default:
391         {
392             DBG_ERROR( "Ungueltiges Attribut!" );
393         }
394     }
395     return pNew;
396 }
397 
398 // -------------------------------------------------------------------------
399 // class EditLine
400 // -------------------------------------------------------------------------
401 
EditLine()402 EditLine::EditLine()
403 {
404     DBG_CTOR( EE_EditLine, 0 );
405 
406     nStart = nEnd = 0;
407     nStartPortion = 0;              // damit in ungueltiger Zeile ohne Portions von einer gueltigen Zeile mit der Portion Nr0 unterscieden werden kann.
408     nEndPortion = 0;
409     nHeight = 0;
410     nStartPosX = 0;
411     nTxtHeight = 0;
412     nTxtWidth = 0;
413     nCrsrHeight = 0;
414     nMaxAscent = 0;
415     bHangingPunctuation = sal_False;
416     bInvalid = sal_True;
417 }
418 
EditLine(const EditLine & r)419 EditLine::EditLine( const EditLine& r )
420 {
421     DBG_CTOR( EE_EditLine, 0 );
422 
423     nEnd = r.nEnd;
424     nStart = r.nStart;
425     nStartPortion = r.nStartPortion;
426     nEndPortion = r.nEndPortion;
427     bHangingPunctuation = r.bHangingPunctuation;
428 
429     nHeight = 0;
430     nStartPosX = 0;
431     nTxtHeight = 0;
432     nTxtWidth = 0;
433     nCrsrHeight = 0;
434     nMaxAscent = 0;
435     bInvalid = sal_True;
436 }
437 
~EditLine()438 EditLine::~EditLine()
439 {
440     DBG_DTOR( EE_EditLine, 0 );
441 }
442 
Clone() const443 EditLine* EditLine::Clone() const
444 {
445     EditLine* pL = new EditLine;
446     if ( aPositions.Count() )
447     {
448         pL->aPositions.Insert (aPositions.GetData(), aPositions.Count(), 0);
449     }
450     pL->nStartPosX      = nStartPosX;
451     pL->nStart          = nStart;
452     pL->nEnd            = nEnd;
453     pL->nStartPortion   = nStartPortion;
454     pL->nEndPortion     = nEndPortion;
455     pL->nHeight         = nHeight;
456     pL->nTxtWidth       = nTxtWidth;
457     pL->nTxtHeight      = nTxtHeight;
458     pL->nCrsrHeight     = nCrsrHeight;
459     pL->nMaxAscent      = nMaxAscent;
460 
461     return pL;
462 }
463 
operator ==(const EditLine & r1,const EditLine & r2)464 sal_Bool operator == ( const EditLine& r1,  const EditLine& r2  )
465 {
466     if ( r1.nStart != r2.nStart )
467         return sal_False;
468 
469     if ( r1.nEnd != r2.nEnd )
470         return sal_False;
471 
472     if ( r1.nStartPortion != r2.nStartPortion )
473         return sal_False;
474 
475     if ( r1.nEndPortion != r2.nEndPortion )
476         return sal_False;
477 
478     return sal_True;
479 }
480 
operator =(const EditLine & r)481 EditLine& EditLine::operator = ( const EditLine& r )
482 {
483     nEnd = r.nEnd;
484     nStart = r.nStart;
485     nEndPortion = r.nEndPortion;
486     nStartPortion = r.nStartPortion;
487     return *this;
488 }
489 
490 
operator !=(const EditLine & r1,const EditLine & r2)491 sal_Bool operator != ( const EditLine& r1,  const EditLine& r2  )
492 {
493     return !( r1 == r2 );
494 }
495 
CalcTextSize(ParaPortion & rParaPortion)496 Size EditLine::CalcTextSize( ParaPortion& rParaPortion )
497 {
498     Size aSz;
499     Size aTmpSz;
500     TextPortion* pPortion;
501 
502     sal_uInt16 nIndex = GetStart();
503 
504     DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize vor CreatePortions !" );
505 
506     for ( sal_uInt16 n = nStartPortion; n <= nEndPortion; n++ )
507     {
508         pPortion = rParaPortion.GetTextPortions().GetObject(n);
509         switch ( pPortion->GetKind() )
510         {
511             case PORTIONKIND_TEXT:
512             case PORTIONKIND_FIELD:
513             case PORTIONKIND_HYPHENATOR:
514             {
515                 aTmpSz = pPortion->GetSize();
516                 aSz.Width() += aTmpSz.Width();
517                 if ( aSz.Height() < aTmpSz.Height() )
518                     aSz.Height() = aTmpSz.Height();
519             }
520             break;
521             case PORTIONKIND_TAB:
522 //          case PORTIONKIND_EXTRASPACE:
523             {
524                 aSz.Width() += pPortion->GetSize().Width();
525             }
526             break;
527         }
528         nIndex = nIndex + pPortion->GetLen();
529     }
530 
531     SetHeight( (sal_uInt16)aSz.Height() );
532     return aSz;
533 }
534 
535 // -------------------------------------------------------------------------
536 // class EditLineList
537 // -------------------------------------------------------------------------
EditLineList()538 EditLineList::EditLineList()
539 {
540 }
541 
~EditLineList()542 EditLineList::~EditLineList()
543 {
544     Reset();
545 }
546 
Reset()547 void EditLineList::Reset()
548 {
549     for ( sal_uInt16 nLine = 0; nLine < Count(); nLine++ )
550         delete GetObject(nLine);
551     Remove( 0, Count() );
552 }
553 
DeleteFromLine(sal_uInt16 nDelFrom)554 void EditLineList::DeleteFromLine( sal_uInt16 nDelFrom )
555 {
556     DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" );
557     for ( sal_uInt16 nL = nDelFrom; nL < Count(); nL++ )
558         delete GetObject(nL);
559     Remove( nDelFrom, Count()-nDelFrom );
560 }
561 
FindLine(sal_uInt16 nChar,sal_Bool bInclEnd)562 sal_uInt16 EditLineList::FindLine( sal_uInt16 nChar, sal_Bool bInclEnd )
563 {
564     for ( sal_uInt16 nLine = 0; nLine < Count(); nLine++ )
565     {
566         EditLine* pLine = GetObject( nLine );
567         if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) ||
568              ( pLine->GetEnd() > nChar ) )
569         {
570             return nLine;
571         }
572     }
573 
574     DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" );
575     return ( Count() - 1 );
576 }
577 
578 // -------------------------------------------------------------------------
579 // class EditSelection
580 // -------------------------------------------------------------------------
DbgIsBuggy(EditDoc & rDoc)581 sal_Bool EditPaM::DbgIsBuggy( EditDoc& rDoc )
582 {
583     if ( !pNode )
584         return sal_True;
585     if ( rDoc.GetPos( pNode ) >= rDoc.Count() )
586         return sal_True;
587     if ( nIndex > pNode->Len() )
588         return sal_True;
589 
590     return sal_False;
591 }
592 
DbgIsBuggy(EditDoc & rDoc)593 sal_Bool EditSelection::DbgIsBuggy( EditDoc& rDoc )
594 {
595     if ( aStartPaM.DbgIsBuggy( rDoc ) )
596         return sal_True;
597     if ( aEndPaM.DbgIsBuggy( rDoc ) )
598         return sal_True;
599 
600     return sal_False;
601 }
602 
EditSelection()603 EditSelection::EditSelection()
604 {
605 }
606 
EditSelection(const EditPaM & rStartAndAnd)607 EditSelection::EditSelection( const EditPaM& rStartAndAnd )
608 {
609     // koennte noch optimiert werden!
610     // nicht erst Def-CTOR vom PaM rufen!
611     aStartPaM = rStartAndAnd;
612     aEndPaM = rStartAndAnd;
613 }
614 
EditSelection(const EditPaM & rStart,const EditPaM & rEnd)615 EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd )
616 {
617     // koennte noch optimiert werden!
618     aStartPaM = rStart;
619     aEndPaM = rEnd;
620 }
621 
operator =(const EditPaM & rPaM)622 EditSelection& EditSelection::operator = ( const EditPaM& rPaM )
623 {
624     aStartPaM = rPaM;
625     aEndPaM = rPaM;
626     return *this;
627 }
628 
IsInvalid() const629 sal_Bool EditSelection::IsInvalid() const
630 {
631     EditPaM aEmptyPaM;
632 
633     if ( aStartPaM == aEmptyPaM )
634         return sal_True;
635 
636     if ( aEndPaM == aEmptyPaM )
637         return sal_True;
638 
639     return sal_False;
640 }
641 
Adjust(const ContentList & rNodes)642 sal_Bool EditSelection::Adjust( const ContentList& rNodes )
643 {
644     DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in Adjust(1)" );
645     DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in Adjust(2)" );
646 
647     ContentNode* pStartNode = aStartPaM.GetNode();
648     ContentNode* pEndNode = aEndPaM.GetNode();
649 
650     sal_uInt32 nStartNode = rNodes.GetPos( pStartNode );
651     sal_uInt32 nEndNode = rNodes.GetPos( pEndNode );
652 
653     DBG_ASSERT( nStartNode != USHRT_MAX, "Node im Wald in Adjust(1)" );
654     DBG_ASSERT( nEndNode != USHRT_MAX, "Node im Wald in Adjust(2)" );
655 
656     sal_Bool bSwap = sal_False;
657     if ( nStartNode > nEndNode )
658         bSwap = sal_True;
659     else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) )
660         bSwap = sal_True;
661 
662     if ( bSwap )
663     {
664         EditPaM aTmpPaM( aStartPaM );
665         aStartPaM = aEndPaM;
666         aEndPaM = aTmpPaM;
667     }
668 
669     return bSwap;
670 }
671 
672 
673 // -------------------------------------------------------------------------
674 // class EditPaM
675 // -------------------------------------------------------------------------
operator ==(const EditPaM & r1,const EditPaM & r2)676 sal_Bool operator == ( const EditPaM& r1,  const EditPaM& r2  )
677 {
678     if ( r1.GetNode() != r2.GetNode() )
679         return sal_False;
680 
681     if ( r1.GetIndex() != r2.GetIndex() )
682         return sal_False;
683 
684     return sal_True;
685 }
686 
operator =(const EditPaM & rPaM)687 EditPaM& EditPaM::operator = ( const EditPaM& rPaM )
688 {
689     nIndex = rPaM.nIndex;
690     pNode = rPaM.pNode;
691     return *this;
692 }
693 
operator !=(const EditPaM & r1,const EditPaM & r2)694 sal_Bool operator != ( const EditPaM& r1,  const EditPaM& r2  )
695 {
696     return !( r1 == r2 );
697 }
698 
699 
700 // -------------------------------------------------------------------------
701 // class ContentNode
702 // -------------------------------------------------------------------------
ContentNode(SfxItemPool & rPool)703 ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool )
704 {
705     DBG_CTOR( EE_ContentNode, 0 );
706     pWrongList = NULL;
707 }
708 
ContentNode(const XubString & rStr,const ContentAttribs & rContentAttribs)709 ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) :
710     XubString( rStr ), aContentAttribs( rContentAttribs )
711 {
712     DBG_CTOR( EE_ContentNode, 0 );
713     pWrongList = NULL;
714 }
715 
~ContentNode()716 ContentNode::~ContentNode()
717 {
718     DBG_DTOR( EE_ContentNode, 0 );
719 #ifndef SVX_LIGHT
720     delete pWrongList;
721 #endif
722 }
723 
ExpandAttribs(sal_uInt16 nIndex,sal_uInt16 nNew,SfxItemPool & rItemPool)724 void ContentNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew, SfxItemPool& rItemPool )
725 {
726     if ( !nNew )
727         return;
728 
729     // Da Features anders behandelt werden als normale Zeichenattribute,
730     // kann sich hier auch die Sortierung der Start-Liste aendern!
731     // In jedem if..., in dem weiter (n) Moeglichkeiten aufgrund von
732     // bFeature oder Spezialfall existieren,
733     // muessen (n-1) Moeglichkeiten mit bResort versehen werden.
734     // Die wahrscheinlichste Moeglichkeit erhaelt kein bResort,
735     // so dass nicht neu sortiert wird, wenn sich alle Attribute
736     // gleich verhalten.
737     sal_Bool bResort = sal_False;
738     sal_Bool bExpandedEmptyAtIndexNull = sal_False;
739 
740     sal_uInt16 nAttr = 0;
741     EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
742     while ( pAttrib )
743     {
744         if ( pAttrib->GetEnd() >= nIndex )
745         {
746             // Alle Attribute hinter der Einfuegeposition verschieben...
747             if ( pAttrib->GetStart() > nIndex )
748             {
749                 pAttrib->MoveForward( nNew );
750             }
751             // 0: Leeres Attribut expandieren, wenn an Einfuegestelle
752             else if ( pAttrib->IsEmpty() )
753             {
754                 // Index nicht pruefen, leeres durfte nur dort liegen.
755                 // Wenn spaeter doch Ueberpruefung:
756                 //   Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
757                 // Start <= nIndex, End >= nIndex => Start=End=nIndex!
758 //              if ( pAttrib->GetStart() == nIndex )
759                 pAttrib->Expand( nNew );
760                 if ( pAttrib->GetStart() == 0 )
761                     bExpandedEmptyAtIndexNull = sal_True;
762             }
763             // 1: Attribut startet davor, geht bis Index...
764             else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
765             {
766                 // Nur expandieren, wenn kein Feature,
767                 // und wenn nicht in ExcludeListe!
768                 // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
769 //              if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) )
770                 if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
771                 {
772                     if ( !pAttrib->IsEdge() )
773                         pAttrib->Expand( nNew );
774                 }
775                 else
776                     bResort = sal_True;
777             }
778             // 2: Attribut startet davor, geht hinter Index...
779             else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
780             {
781                 DBG_ASSERT( !pAttrib->IsFeature(), "Grosses Feature?!" );
782                 pAttrib->Expand( nNew );
783             }
784             // 3: Attribut startet auf Index...
785             else if ( pAttrib->GetStart() == nIndex )
786             {
787                 if ( pAttrib->IsFeature() )
788                 {
789                     pAttrib->MoveForward( nNew );
790                     bResort = sal_True;
791                 }
792                 else
793                 {
794                     sal_Bool bExpand = sal_False;
795                     if ( nIndex == 0 )
796                     {
797                         bExpand = sal_True;
798                         if( bExpandedEmptyAtIndexNull )
799                         {
800                             // Check if this kind of attribut was empty and expanded here...
801                             sal_uInt16 nW = pAttrib->GetItem()->Which();
802                             for ( sal_uInt16 nA = 0; nA < nAttr; nA++ )
803                             {
804                                 EditCharAttrib* pA = aCharAttribList.GetAttribs()[nA];
805                                 if ( ( pA->GetStart() == 0 ) && ( pA->GetItem()->Which() == nW ) )
806                                 {
807                                     bExpand = sal_False;
808                                     break;
809                                 }
810                             }
811 
812                         }
813                     }
814                     if ( bExpand )
815                     {
816                         pAttrib->Expand( nNew );
817                         bResort = sal_True;
818                     }
819                     else
820                     {
821                         pAttrib->MoveForward( nNew );
822                     }
823                 }
824             }
825         }
826 
827         if ( pAttrib->IsEdge() )
828             pAttrib->SetEdge( sal_False );
829 
830         DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
831 
832         DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
833         DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attrib groesser als Absatz!" );
834         if ( pAttrib->IsEmpty() )
835         {
836             DBG_ERROR( "Leeres Attribut nach ExpandAttribs?" );
837             bResort = sal_True;
838             aCharAttribList.GetAttribs().Remove( nAttr );
839             rItemPool.Remove( *pAttrib->GetItem() );
840             delete pAttrib;
841             nAttr--;
842         }
843         nAttr++;
844         pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
845     }
846 
847     if ( bResort )
848         aCharAttribList.ResortAttribs();
849 
850 #ifndef SVX_LIGHT
851     if ( pWrongList )
852     {
853         sal_Bool bSep = ( GetChar( nIndex ) == ' ' ) || IsFeature( nIndex );
854         pWrongList->TextInserted( nIndex, nNew, bSep );
855     }
856 #endif // !SVX_LIGHT
857 
858 #ifdef EDITDEBUG
859     DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Expand: Start-Liste verdreht" );
860 #endif
861 }
862 
CollapsAttribs(sal_uInt16 nIndex,sal_uInt16 nDeleted,SfxItemPool & rItemPool)863 void ContentNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted, SfxItemPool& rItemPool )
864 {
865     if ( !nDeleted )
866         return;
867 
868     // Da Features anders behandelt werden als normale Zeichenattribute,
869     // kann sich hier auch die Sortierung der Start-Liste aendern!
870     sal_Bool bResort = sal_False;
871     sal_Bool bDelAttr = sal_False;
872     sal_uInt16 nEndChanges = nIndex+nDeleted;
873 
874     sal_uInt16 nAttr = 0;
875     EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
876     while ( pAttrib )
877     {
878         bDelAttr = sal_False;
879         if ( pAttrib->GetEnd() >= nIndex )
880         {
881             // Alles Attribute hinter der Einfuegeposition verschieben...
882             if ( pAttrib->GetStart() >= nEndChanges )
883             {
884                 pAttrib->MoveBackward( nDeleted );
885             }
886             // 1. Innenliegende Attribute loeschen...
887             else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
888             {
889                 // Spezialfall: Attrubt deckt genau den Bereich ab
890                 // => als leeres Attribut behalten.
891                 if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
892                     pAttrib->GetEnd() = nIndex; // leer
893                 else
894                     bDelAttr = sal_True;
895             }
896             // 2. Attribut beginnt davor, endet drinnen oder dahinter...
897             else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
898             {
899                 DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
900                 if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen
901                     pAttrib->GetEnd() = nIndex;
902                 else
903                     pAttrib->Collaps( nDeleted );       // endet dahinter
904             }
905             // 3. Attribut beginnt drinnen, endet dahinter...
906             else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
907             {
908                 // Features duerfen nicht expandieren!
909                 if ( pAttrib->IsFeature() )
910                 {
911                     pAttrib->MoveBackward( nDeleted );
912                     bResort = sal_True;
913                 }
914                 else
915                 {
916                     pAttrib->GetStart() = nEndChanges;
917                     pAttrib->MoveBackward( nDeleted );
918                 }
919             }
920         }
921         DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" );
922 
923         DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
924         DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
925         if ( bDelAttr /* || pAttrib->IsEmpty() */ )
926         {
927             bResort = sal_True;
928             aCharAttribList.GetAttribs().Remove( nAttr );
929             rItemPool.Remove( *pAttrib->GetItem() );
930             delete pAttrib;
931             nAttr--;
932         }
933         else if ( pAttrib->IsEmpty() )
934             aCharAttribList.HasEmptyAttribs() = sal_True;
935 
936         nAttr++;
937         pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr );
938     }
939 
940     if ( bResort )
941         aCharAttribList.ResortAttribs();
942 
943 #ifndef SVX_LIGHT
944     if ( pWrongList )
945         pWrongList->TextDeleted( nIndex, nDeleted );
946 #endif // !SVX_LIGHT
947 
948 #ifdef EDITDEBUG
949     DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), sal_True ), "Collaps: Start-Liste verdreht" );
950 #endif
951 }
952 
CopyAndCutAttribs(ContentNode * pPrevNode,SfxItemPool & rPool,sal_Bool bKeepEndingAttribs)953 void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, sal_Bool bKeepEndingAttribs )
954 {
955     DBG_ASSERT( pPrevNode, "kopieren von Attributen auf einen NULL-Pointer ?" );
956 
957     xub_StrLen nCut = pPrevNode->Len();
958 
959     sal_uInt16 nAttr = 0;
960     EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr );
961     while ( pAttrib )
962     {
963         if ( pAttrib->GetEnd() < nCut )
964         {
965             // bleiben unveraendert....
966             ;
967         }
968         else if ( pAttrib->GetEnd() == nCut )
969         {
970             // muessen als leeres Attribut kopiert werden.
971             if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
972             {
973                 EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 );
974                 DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" );
975                 aCharAttribList.InsertAttrib( pNewAttrib );
976             }
977         }
978         else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) )
979         {
980             // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
981             // muessen kopiert und geaendert werden
982             EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
983             DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" );
984             aCharAttribList.InsertAttrib( pNewAttrib );
985             // stutzen:
986             pAttrib->GetEnd() = nCut;
987         }
988         else
989         {
990             // alle dahinter verschieben in den neuen Node (this)
991 //          pPrevNode->GetCharAttribs().RemoveAttrib( pAttrib );
992             pPrevNode->GetCharAttribs().GetAttribs().Remove( nAttr );
993             aCharAttribList.InsertAttrib( pAttrib );
994             DBG_ASSERT( pAttrib->GetStart() >= nCut, "Start < nCut!" );
995             DBG_ASSERT( pAttrib->GetEnd() >= nCut, "End < nCut!" );
996             pAttrib->GetStart() = pAttrib->GetStart() - nCut;
997             pAttrib->GetEnd() = pAttrib->GetEnd() - nCut;
998             nAttr--;
999         }
1000         nAttr++;
1001         pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr );
1002     }
1003 }
1004 
AppendAttribs(ContentNode * pNextNode)1005 void ContentNode::AppendAttribs( ContentNode* pNextNode )
1006 {
1007     DBG_ASSERT( pNextNode, "kopieren von Attributen von einen NULL-Pointer ?" );
1008 
1009     sal_uInt16 nNewStart = Len();
1010 
1011 #ifdef EDITDEBUG
1012     DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" );
1013 #endif
1014 
1015     sal_uInt16 nAttr = 0;
1016     EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr );
1017     while ( pAttrib )
1018     {
1019         // alle Attribute verschieben in den aktuellen Node (this)
1020         sal_Bool bMelted = sal_False;
1021         if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
1022         {
1023             // Evtl koennen Attribute zusammengefasst werden:
1024             sal_uInt16 nTmpAttr = 0;
1025             EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
1026             while ( !bMelted && pTmpAttrib )
1027             {
1028                 if ( pTmpAttrib->GetEnd() == nNewStart )
1029                 {
1030                     if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
1031                          ( *(pTmpAttrib->GetItem()) == *(pAttrib->GetItem() ) ) )
1032                     {
1033                         pTmpAttrib->GetEnd() =
1034                             pTmpAttrib->GetEnd() + pAttrib->GetLen();
1035                         pNextNode->GetCharAttribs().GetAttribs().Remove( nAttr );
1036                         // Vom Pool abmelden ?!
1037                         delete pAttrib;
1038                         bMelted = sal_True;
1039                     }
1040                 }
1041                 ++nTmpAttr;
1042                 pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr );
1043             }
1044         }
1045 
1046         if ( !bMelted )
1047         {
1048             pAttrib->GetStart() = pAttrib->GetStart() + nNewStart;
1049             pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart;
1050             aCharAttribList.InsertAttrib( pAttrib );
1051             ++nAttr;
1052         }
1053         pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr );
1054     }
1055     // Fuer die Attribute, die nur ruebergewandert sind:
1056     pNextNode->GetCharAttribs().Clear();
1057 
1058 #ifdef EDITDEBUG
1059     DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" );
1060 #endif
1061 }
1062 
CreateDefFont()1063 void ContentNode::CreateDefFont()
1064 {
1065     // Erst alle Informationen aus dem Style verwenden...
1066     SfxStyleSheet* pS = aContentAttribs.GetStyleSheet();
1067     if ( pS )
1068         CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
1069 
1070     // ... dann die harte Absatzformatierung rueberbuegeln...
1071     CreateFont( GetCharAttribs().GetDefFont(),
1072         GetContentAttribs().GetItems(), pS == NULL );
1073 }
1074 
SetStyleSheet(SfxStyleSheet * pS,const SvxFont & rFontFromStyle)1075 void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle )
1076 {
1077     aContentAttribs.SetStyleSheet( pS );
1078 
1079     // Erst alle Informationen aus dem Style verwenden...
1080     GetCharAttribs().GetDefFont() = rFontFromStyle;
1081     // ... dann die harte Absatzformatierung rueberbuegeln...
1082     CreateFont( GetCharAttribs().GetDefFont(),
1083         GetContentAttribs().GetItems(), pS == NULL );
1084 }
1085 
SetStyleSheet(SfxStyleSheet * pS,sal_Bool bRecalcFont)1086 void ContentNode::SetStyleSheet( SfxStyleSheet* pS, sal_Bool bRecalcFont )
1087 {
1088     aContentAttribs.SetStyleSheet( pS );
1089     if ( bRecalcFont )
1090         CreateDefFont();
1091 }
1092 
DestroyWrongList()1093 void ContentNode::DestroyWrongList()
1094 {
1095 #ifndef SVX_LIGHT
1096     delete pWrongList;
1097 #endif
1098     pWrongList = NULL;
1099 }
1100 
CreateWrongList()1101 void ContentNode::CreateWrongList()
1102 {
1103     DBG_ASSERT( !pWrongList, "WrongList existiert schon!" );
1104 #ifndef SVX_LIGHT
1105     pWrongList = new WrongList;
1106 #endif
1107 }
1108 
SetWrongList(WrongList * p)1109 void ContentNode::SetWrongList( WrongList* p )
1110 {
1111     DBG_ASSERT( !pWrongList, "WrongList existiert schon!" );
1112     pWrongList = p;
1113 }
1114 
1115 // -------------------------------------------------------------------------
1116 // class ContentAttribs
1117 // -------------------------------------------------------------------------
ContentAttribs(SfxItemPool & rPool)1118 ContentAttribs::ContentAttribs( SfxItemPool& rPool ) :
1119                     aAttribSet( rPool, EE_PARA_START, EE_CHAR_END )
1120 {
1121     pStyle = 0;
1122 }
1123 
ContentAttribs(const ContentAttribs & rRef)1124 ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) :
1125                     aAttribSet( rRef.aAttribSet )
1126 {
1127     pStyle = rRef.pStyle;
1128 }
1129 
~ContentAttribs()1130 ContentAttribs::~ContentAttribs()
1131 {
1132 }
1133 
FindTabStop(long nCurPos,sal_uInt16 nDefTab)1134 SvxTabStop ContentAttribs::FindTabStop( long nCurPos, sal_uInt16 nDefTab )
1135 {
1136     const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS );
1137     for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
1138     {
1139         const SvxTabStop& rTab = rTabs[i];
1140         if ( rTab.GetTabPos() > nCurPos  )
1141             return rTab;
1142     }
1143 
1144     // DefTab ermitteln...
1145     SvxTabStop aTabStop;
1146     long x = nCurPos / nDefTab + 1;
1147     aTabStop.GetTabPos() = nDefTab * x;
1148     return aTabStop;
1149 }
1150 
SetStyleSheet(SfxStyleSheet * pS)1151 void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
1152 {
1153     sal_Bool bStyleChanged = ( pStyle != pS );
1154     pStyle = pS;
1155     // #104799# Only when other style sheet, not when current style sheet modified
1156     if ( pStyle && bStyleChanged )
1157     {
1158         // Gezielt die Attribute aus der Absatzformatierung entfernen, die im Style
1159         // spezifiziert sind, damit die Attribute des Styles wirken koennen.
1160         const SfxItemSet& rStyleAttribs = pStyle->GetItemSet();
1161         for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
1162         {
1163             // #99635# Don't change bullet on/off
1164             if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) )
1165                 aAttribSet.ClearItem( nWhich );
1166         }
1167     }
1168 }
1169 
GetItem(sal_uInt16 nWhich)1170 const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich )
1171 {
1172     // Harte Absatzattribute haben Vorrang!
1173     SfxItemSet* pTakeFrom = &aAttribSet;
1174     if ( pStyle && ( aAttribSet.GetItemState( nWhich, sal_False ) != SFX_ITEM_ON  ) )
1175         pTakeFrom = &pStyle->GetItemSet();
1176 
1177     return pTakeFrom->Get( nWhich );
1178 }
1179 
HasItem(sal_uInt16 nWhich)1180 sal_Bool ContentAttribs::HasItem( sal_uInt16 nWhich )
1181 {
1182     sal_Bool bHasItem = sal_False;
1183     if ( aAttribSet.GetItemState( nWhich, sal_False ) == SFX_ITEM_ON  )
1184         bHasItem = sal_True;
1185     else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON )
1186         bHasItem = sal_True;
1187 
1188     return bHasItem;
1189 }
1190 
1191 
1192 
1193 // ----------------------------------------------------------------------
1194 //  class ItemList
1195 //  ----------------------------------------------------------------------
FindAttrib(sal_uInt16 nWhich)1196 const SfxPoolItem* ItemList::FindAttrib( sal_uInt16 nWhich )
1197 {
1198     const SfxPoolItem* pItem = First();
1199     while ( pItem && ( pItem->Which() != nWhich ) )
1200         pItem = Next();
1201 
1202     return pItem;
1203 }
1204 
1205 // -------------------------------------------------------------------------
1206 // class EditDoc
1207 // -------------------------------------------------------------------------
EditDoc(SfxItemPool * pPool)1208 EditDoc::EditDoc( SfxItemPool* pPool )
1209 {
1210     if ( pPool )
1211     {
1212         pItemPool = pPool;
1213         bOwnerOfPool = sal_False;
1214     }
1215     else
1216     {
1217         pItemPool = new EditEngineItemPool( sal_False );
1218         bOwnerOfPool = sal_True;
1219     }
1220 
1221     nDefTab = DEFTAB;
1222     bIsVertical = sal_False;
1223     bIsFixedCellHeight = sal_False;
1224 
1225     // Don't create a empty node, Clear() will be called in EditEngine-CTOR
1226 
1227     SetModified( sal_False );
1228 };
1229 
~EditDoc()1230 EditDoc::~EditDoc()
1231 {
1232     ImplDestroyContents();
1233     if ( bOwnerOfPool )
1234         SfxItemPool::Free(pItemPool);
1235 }
1236 
ImplDestroyContents()1237 void EditDoc::ImplDestroyContents()
1238 {
1239     for ( sal_uInt32 nNode = Count(); nNode; )
1240         RemoveItemsFromPool( GetObject( --nNode ) );
1241     DeleteAndDestroy( 0, Count() );
1242 }
1243 
RemoveItemsFromPool(ContentNode * pNode)1244 void EditDoc::RemoveItemsFromPool( ContentNode* pNode )
1245 {
1246     for ( sal_uInt16 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
1247     {
1248         EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[nAttr];
1249         GetItemPool().Remove( *pAttr->GetItem() );
1250     }
1251 }
1252 
CreateFont(SvxFont & rFont,const SfxItemSet & rSet,bool bSearchInParent,short nScriptType)1253 void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType )
1254 {
1255     Font aPrevFont( rFont );
1256     rFont.SetAlign( ALIGN_BASELINE );
1257     rFont.SetTransparent( sal_True );
1258 
1259     sal_uInt16 nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
1260     sal_uInt16 nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType );
1261     sal_uInt16 nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType );
1262     sal_uInt16 nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType );
1263     sal_uInt16 nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType );
1264 
1265     if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) )
1266     {
1267         const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo );
1268         rFont.SetName( rFontItem.GetFamilyName() );
1269         rFont.SetFamily( rFontItem.GetFamily() );
1270         rFont.SetPitch( rFontItem.GetPitch() );
1271         rFont.SetCharSet( rFontItem.GetCharSet() );
1272     }
1273     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) )
1274         rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() );
1275     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) )
1276         rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() );
1277     if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) )
1278         rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) );
1279     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) )
1280         rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() );
1281     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) )
1282         rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() );
1283     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SFX_ITEM_ON ) )
1284         rFont.SetOverline( ((const SvxOverlineItem&)rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() );
1285     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) )
1286         rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() );
1287     if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) )
1288         rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() );
1289     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) )
1290         rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() );
1291     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) )
1292         rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() );
1293     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) )
1294     {
1295         const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT );
1296 
1297         sal_uInt16 nProp = rEsc.GetProp();
1298         rFont.SetPropr( (sal_uInt8)nProp );
1299 
1300         short nEsc = rEsc.GetEsc();
1301         if ( nEsc == DFLT_ESC_AUTO_SUPER )
1302             nEsc = 100 - nProp;
1303         else if ( nEsc == DFLT_ESC_AUTO_SUB )
1304             nEsc = sal::static_int_cast< short >( -( 100 - nProp ) );
1305         rFont.SetEscapement( nEsc );
1306     }
1307     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) )
1308         rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() );
1309     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) )
1310         rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() );
1311     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) )
1312         rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() );
1313     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) )
1314         rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() );
1315     if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) )
1316         rFont.SetRelief( (FontRelief)((const SvxCharReliefItem&)rSet.Get( EE_CHAR_RELIEF )).GetValue() );
1317 
1318     // Ob ich jetzt den ganzen Font vergleiche, oder vor jeder Aenderung
1319     // pruefe, ob der Wert sich aendert, bleibt sich relativ gleich.
1320     // So ggf ein MakeUniqFont im Font mehr, dafuer bei Aenderung schnellerer
1321     // Abbruch der Abfrage, oder ich musste noch jedesmal ein bChanged pflegen.
1322     if ( rFont == aPrevFont  )
1323         rFont = aPrevFont;  // => Gleicher ImpPointer fuer IsSameInstance
1324 }
1325 
CreateDefFont(sal_Bool bUseStyles)1326 void EditDoc::CreateDefFont( sal_Bool bUseStyles )
1327 {
1328     SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
1329     CreateFont( aDefFont, aTmpSet );
1330     aDefFont.SetVertical( IsVertical() );
1331     aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
1332 
1333     for ( sal_uInt32 nNode = 0; nNode < Count(); nNode++ )
1334     {
1335         ContentNode* pNode = GetObject( nNode );
1336         pNode->GetCharAttribs().GetDefFont() = aDefFont;
1337         if ( bUseStyles )
1338             pNode->CreateDefFont();
1339     }
1340 }
1341 
1342 static const sal_Unicode aCR[] = { 0x0d, 0x00 };
1343 static const sal_Unicode aLF[] = { 0x0a, 0x00 };
1344 static const sal_Unicode aCRLF[] = { 0x0d, 0x0a, 0x00 };
1345 
GetSepStr(LineEnd eEnd)1346 XubString EditDoc::GetSepStr( LineEnd eEnd )
1347 {
1348     XubString aSep;
1349     if ( eEnd == LINEEND_CR )
1350         aSep = aCR;
1351     else if ( eEnd == LINEEND_LF )
1352         aSep = aLF;
1353     else
1354         aSep = aCRLF;
1355     return aSep;
1356 }
1357 
GetText(LineEnd eEnd) const1358 XubString EditDoc::GetText( LineEnd eEnd ) const
1359 {
1360     sal_uLong nLen = GetTextLen();
1361     sal_uInt32 nNodes = Count();
1362 
1363     String aSep = EditDoc::GetSepStr( eEnd );
1364     sal_uInt16 nSepSize = aSep.Len();
1365 
1366     if ( nSepSize )
1367         nLen += nNodes * nSepSize;
1368     if ( nLen > 0xFFFb / sizeof(xub_Unicode) )
1369     {
1370         DBG_ERROR( "Text zu gross fuer String" );
1371         return XubString();
1372     }
1373     xub_Unicode* pStr = new xub_Unicode[nLen+1];
1374     xub_Unicode* pCur = pStr;
1375     sal_uInt32 nLastNode = nNodes-1;
1376     for ( sal_uInt32 nNode = 0; nNode < nNodes; nNode++ )
1377     {
1378         XubString aTmp( GetParaAsString( GetObject(nNode) ) );
1379         memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) );
1380         pCur += aTmp.Len();
1381         if ( nSepSize && ( nNode != nLastNode ) )
1382         {
1383             memcpy( pCur, aSep.GetBuffer(), nSepSize*sizeof(sal_Unicode ) );
1384             pCur += nSepSize;
1385         }
1386     }
1387     *pCur = '\0';
1388     XubString aASCIIText( pStr );
1389     delete[] pStr;
1390     return aASCIIText;
1391 }
1392 
GetParaAsString(sal_uInt32 nNode) const1393 XubString EditDoc::GetParaAsString( sal_uInt32 nNode ) const
1394 {
1395     return GetParaAsString( SaveGetObject( nNode ) );
1396 }
1397 
GetParaAsString(ContentNode * pNode,sal_uInt16 nStartPos,sal_uInt16 nEndPos,sal_Bool bResolveFields) const1398 XubString EditDoc::GetParaAsString( ContentNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, sal_Bool bResolveFields ) const
1399 {
1400     if ( nEndPos > pNode->Len() )
1401         nEndPos = pNode->Len();
1402 
1403     DBG_ASSERT( nStartPos <= nEndPos, "Start und Ende vertauscht?" );
1404 
1405     sal_uInt16 nIndex = nStartPos;
1406     XubString aStr;
1407     EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex );
1408     while ( nIndex < nEndPos )
1409     {
1410         sal_uInt16 nEnd = nEndPos;
1411         if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
1412             nEnd = pNextFeature->GetStart();
1413         else
1414             pNextFeature = 0;   // Feature interessiert unten nicht
1415 
1416         DBG_ASSERT( nEnd >= nIndex, "Ende vorm Index?" );
1417         //!! beware of sub string length  of -1 which is also defined as STRING_LEN and
1418         //!! thus would result in adding the whole sub string up to the end of the node !!
1419         if (nEnd > nIndex)
1420             aStr += XubString( *pNode, nIndex, nEnd - nIndex );
1421 
1422         if ( pNextFeature )
1423         {
1424             switch ( pNextFeature->GetItem()->Which() )
1425             {
1426                 case EE_FEATURE_TAB:    aStr += '\t';
1427                 break;
1428                 case EE_FEATURE_LINEBR: aStr += '\x0A';
1429                 break;
1430                 case EE_FEATURE_FIELD:  if ( bResolveFields )
1431                                             aStr += ((EditCharAttribField*)pNextFeature)->GetFieldValue();
1432                 break;
1433                 default:    DBG_ERROR( "Was fuer ein Feature ?" );
1434             }
1435             pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd );
1436         }
1437         nIndex = nEnd;
1438     }
1439     return aStr;
1440 }
1441 
GetTextLen() const1442 sal_uLong EditDoc::GetTextLen() const
1443 {
1444     sal_uLong nLen = 0;
1445     for ( sal_uInt32 nNode = 0; nNode < Count(); nNode++ )
1446     {
1447         ContentNode* pNode = GetObject( nNode );
1448         nLen += pNode->Len();
1449         // Felder k�nnen laenger sein als der Platzhalter im Node.
1450         const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs();
1451         for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; )
1452         {
1453             EditCharAttrib* pAttr = rAttrs[--nAttr];
1454             if ( pAttr->Which() == EE_FEATURE_FIELD )
1455             {
1456                 sal_uInt16 nFieldLen = ((EditCharAttribField*)pAttr)->GetFieldValue().Len();
1457                 if ( !nFieldLen )
1458                     nLen--;
1459                 else
1460                     nLen += nFieldLen-1;
1461             }
1462         }
1463     }
1464     return nLen;
1465 }
1466 
Clear()1467 EditPaM EditDoc::Clear()
1468 {
1469     ImplDestroyContents();
1470 
1471     ContentNode* pNode = new ContentNode( GetItemPool() );
1472     Insert( pNode, 0 );
1473 
1474     CreateDefFont( sal_False );
1475 
1476     SetModified( sal_False );
1477 
1478     EditPaM aPaM( pNode, 0 );
1479     return aPaM;
1480 }
1481 
SetModified(sal_Bool b)1482 void EditDoc::SetModified( sal_Bool b )
1483 {
1484     bModified = b;
1485     if ( bModified )
1486     {
1487         aModifyHdl.Call( NULL );
1488     }
1489 }
1490 
RemoveText()1491 EditPaM EditDoc::RemoveText()
1492 {
1493     // Das alte ItemSetmerken, damit z.B. im Chart Font behalten bleibt
1494     ContentNode* pPrevFirstNode = GetObject(0);
1495     SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet();
1496     SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() );
1497     Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() );
1498 
1499     ImplDestroyContents();
1500 
1501     ContentNode* pNode = new ContentNode( GetItemPool() );
1502     Insert( pNode, 0 );
1503 
1504     pNode->SetStyleSheet( pPrevStyle, sal_False );
1505     pNode->GetContentAttribs().GetItems().Set( aPrevSet );
1506     pNode->GetCharAttribs().GetDefFont() = aPrevFont;
1507 
1508     SetModified( sal_True );
1509 
1510     EditPaM aPaM( pNode, 0 );
1511     return aPaM;
1512 }
1513 
InsertText(const EditPaM & rPaM,xub_Unicode c)1514 void EditDoc::InsertText( const EditPaM& rPaM, xub_Unicode c )
1515 {
1516     DBG_ASSERT( c != 0x0A, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1517     DBG_ASSERT( c != 0x0D, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1518     DBG_ASSERT( c != '\t', "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1519 
1520     rPaM.GetNode()->Insert( c, rPaM.GetIndex() );
1521     rPaM.GetNode()->ExpandAttribs( rPaM.GetIndex(), 1, GetItemPool() );
1522 
1523     SetModified( sal_True );
1524 }
1525 
InsertText(EditPaM aPaM,const XubString & rStr)1526 EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr )
1527 {
1528     DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1529     DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1530     DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
1531     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" );
1532 
1533     aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() );
1534     aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() );
1535     aPaM.GetIndex() = aPaM.GetIndex() + rStr.Len();
1536 
1537     SetModified( sal_True );
1538 
1539     return aPaM;
1540 }
1541 
InsertParaBreak(EditPaM aPaM,sal_Bool bKeepEndingAttribs)1542 EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, sal_Bool bKeepEndingAttribs )
1543 {
1544     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" );
1545     ContentNode* pCurNode = aPaM.GetNode();
1546     sal_uInt32 nPos = GetPos( pCurNode );
1547     XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() );
1548     aPaM.GetNode()->Erase( aPaM.GetIndex() );
1549 
1550     // the paragraph attributes...
1551     ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() );
1552 
1553     // for a new paragraph we like to have the bullet/numbering visible by default
1554     aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, sal_True), EE_PARA_BULLETSTATE );
1555 
1556     // ContenNode-CTOR kopiert auch die Absatzattribute
1557     ContentNode* pNode = new ContentNode( aStr, aContentAttribs );
1558 
1559     // Den Default-Font kopieren
1560     pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont();
1561     SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet();
1562     if ( pStyle )
1563     {
1564         XubString aFollow( pStyle->GetFollow() );
1565         if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) )
1566         {
1567             SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() );
1568             pNode->SetStyleSheet( (SfxStyleSheet*)pNext );
1569         }
1570     }
1571 
1572     // Zeichenattribute muessen ggf. kopiert bzw gestutzt werden:
1573     pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs );
1574 
1575     Insert( pNode, nPos+1 );
1576 
1577     SetModified( sal_True );
1578 
1579     aPaM.SetNode( pNode );
1580     aPaM.SetIndex( 0 );
1581     return aPaM;
1582 }
1583 
InsertFeature(EditPaM aPaM,const SfxPoolItem & rItem)1584 EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem  )
1585 {
1586     DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" );
1587 
1588     aPaM.GetNode()->Insert( CH_FEATURE, aPaM.GetIndex() );
1589     aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() );
1590 
1591     // Fuer das Feature ein Feature-Attribut anlegen...
1592     EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 );
1593     DBG_ASSERT( pAttrib, "Warum kann ich kein Feature anlegen ?" );
1594     aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib );
1595 
1596     SetModified( sal_True );
1597 
1598     aPaM.GetIndex()++;
1599     return aPaM;
1600 }
1601 
ConnectParagraphs(ContentNode * pLeft,ContentNode * pRight)1602 EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight )
1603 {
1604     const EditPaM aPaM( pLeft, pLeft->Len() );
1605 
1606     // Erst die Attribute, da sonst nLen nicht stimmt!
1607     pLeft->AppendAttribs( pRight );
1608     // Dann den Text...
1609     *pLeft += *pRight;
1610 
1611     // der rechte verschwindet.
1612     RemoveItemsFromPool( pRight );
1613     sal_uInt32 nRight = GetPos( pRight );
1614     Remove( nRight );
1615     delete pRight;
1616 
1617     SetModified( sal_True );
1618 
1619     return aPaM;
1620 }
1621 
RemoveChars(EditPaM aPaM,sal_uInt16 nChars)1622 EditPaM EditDoc::RemoveChars( EditPaM aPaM, sal_uInt16 nChars )
1623 {
1624     // Evtl. Features entfernen!
1625     aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars );
1626     aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() );
1627 
1628     SetModified( sal_True );
1629 
1630     return aPaM;
1631 }
1632 
InsertAttribInSelection(ContentNode * pNode,sal_uInt16 nStart,sal_uInt16 nEnd,const SfxPoolItem & rPoolItem)1633 void EditDoc::InsertAttribInSelection( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem )
1634 {
1635     DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
1636     DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
1637 
1638     // fuer Optimierung:
1639     // dieses endet am Anfang der Selektion => kann erweitert werden
1640     EditCharAttrib* pEndingAttrib = 0;
1641     // dieses startet am Ende der Selektion => kann erweitert werden
1642     EditCharAttrib* pStartingAttrib = 0;
1643 
1644     DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
1645 
1646     RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() );
1647 
1648     if ( pStartingAttrib && pEndingAttrib &&
1649          ( *(pStartingAttrib->GetItem()) == rPoolItem ) &&
1650          ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
1651     {
1652         // wird ein groesses Attribut.
1653         pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
1654         GetItemPool().Remove( *(pStartingAttrib->GetItem()) );
1655         pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) );
1656         delete pStartingAttrib;
1657     }
1658     else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
1659         pStartingAttrib->GetStart() = nStart;
1660     else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) )
1661         pEndingAttrib->GetEnd() = nEnd;
1662     else
1663         InsertAttrib( rPoolItem, pNode, nStart, nEnd );
1664 
1665     if ( pStartingAttrib )
1666         pNode->GetCharAttribs().ResortAttribs();
1667 
1668     SetModified( sal_True );
1669 }
1670 
RemoveAttribs(ContentNode * pNode,sal_uInt16 nStart,sal_uInt16 nEnd,sal_uInt16 nWhich)1671 sal_Bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt16 nWhich )
1672 {
1673     EditCharAttrib* pStarting;
1674     EditCharAttrib* pEnding;
1675     return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich );
1676 }
1677 
RemoveAttribs(ContentNode * pNode,sal_uInt16 nStart,sal_uInt16 nEnd,EditCharAttrib * & rpStarting,EditCharAttrib * & rpEnding,sal_uInt16 nWhich)1678 sal_Bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, sal_uInt16 nWhich )
1679 {
1680     DBG_ASSERT( pNode, "Wohin mit dem Attribut?" );
1681     DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" );
1682 
1683     // dieses endet am Anfang der Selektion => kann erweitert werden
1684     rpEnding = 0;
1685     // dieses startet am Ende der Selektion => kann erweitert werden
1686     rpStarting = 0;
1687 
1688     sal_Bool bChanged = sal_False;
1689 
1690     DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" );
1691 
1692     // ueber die Attribute iterieren...
1693     sal_uInt16 nAttr = 0;
1694     EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1695     while ( pAttr )
1696     {
1697         sal_Bool bRemoveAttrib = sal_False;
1698         // MT 11.9.97:
1699         // Ich denke dass in dieser Methode generell keine Features geloescht
1700         // werden sollen.
1701         // => Dann koennen die Feature-Abfragen weiter unten entfallen
1702         sal_uInt16 nAttrWhich = pAttr->Which();
1703         if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) )
1704         {
1705             // Attribut beginnt in Selection
1706             if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) )
1707             {
1708                 bChanged = sal_True;
1709                 if ( pAttr->GetEnd() > nEnd )
1710                 {
1711                     pAttr->GetStart() = nEnd;   // dann faengt es dahinter an
1712                     rpStarting = pAttr;
1713                     if ( nWhich )
1714                         break;  // es kann kein weiteres Attrib hier liegen
1715                 }
1716                 else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
1717                 {
1718                     // Feature nur loeschen, wenn genau an der Stelle
1719                     bRemoveAttrib = sal_True;
1720                 }
1721             }
1722 
1723             // Attribut endet in Selection
1724             else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) )
1725             {
1726                 bChanged = sal_True;
1727                 if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() )
1728                 {
1729                     pAttr->GetEnd() = nStart;   // dann hoert es hier auf
1730                     rpEnding = pAttr;
1731                 }
1732                 else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) )
1733                 {
1734                     // Feature nur loeschen, wenn genau an der Stelle
1735                     bRemoveAttrib = sal_True;
1736                 }
1737             }
1738             // Attribut ueberlappt die Selektion
1739             else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
1740             {
1741                 bChanged = sal_True;
1742                 if ( pAttr->GetStart() == nStart )
1743                 {
1744                     pAttr->GetStart() = nEnd;
1745                     rpStarting = pAttr;
1746                     if ( nWhich )
1747                         break;  // es kann weitere Attribute geben!
1748                 }
1749                 else if ( pAttr->GetEnd() == nEnd )
1750                 {
1751                     pAttr->GetEnd() = nStart;
1752                     rpEnding = pAttr;
1753                     if ( nWhich )
1754                         break;  // es kann weitere Attribute geben!
1755                 }
1756                 else // Attribut muss gesplittet werden...
1757                 {
1758                     sal_uInt16 nOldEnd = pAttr->GetEnd();
1759                     pAttr->GetEnd() = nStart;
1760                     rpEnding = pAttr;
1761                     InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd );
1762                     if ( nWhich )
1763                         break;  // es kann weitere Attribute geben!
1764                 }
1765             }
1766         }
1767         if ( bRemoveAttrib )
1768         {
1769             DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" );
1770             DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" );
1771             pNode->GetCharAttribs().GetAttribs().Remove(nAttr);
1772             GetItemPool().Remove( *pAttr->GetItem() );
1773             delete pAttr;
1774             nAttr--;
1775         }
1776         nAttr++;
1777         pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1778     }
1779 
1780     if ( bChanged )
1781     {
1782         // char attributes need to be sorted by start again
1783         pNode->GetCharAttribs().ResortAttribs();
1784 
1785         SetModified( sal_True );
1786     }
1787 
1788     return bChanged;
1789 }
1790 
InsertAttrib(const SfxPoolItem & rPoolItem,ContentNode * pNode,sal_uInt16 nStart,sal_uInt16 nEnd)1791 void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd )
1792 {
1793     // Diese Methode prueft nicht mehr, ob ein entspr. Attribut
1794     // schon an der Stelle existiert!
1795 
1796     EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd );
1797     DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" );
1798     pNode->GetCharAttribs().InsertAttrib( pAttrib );
1799 
1800     SetModified( sal_True );
1801 }
1802 
InsertAttrib(ContentNode * pNode,sal_uInt16 nStart,sal_uInt16 nEnd,const SfxPoolItem & rPoolItem)1803 void EditDoc::InsertAttrib( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, const SfxPoolItem& rPoolItem )
1804 {
1805     if ( nStart != nEnd )
1806     {
1807         InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem );
1808     }
1809     else
1810     {
1811         // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle:
1812         EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart );
1813         if ( pAttr )
1814         {
1815             // Attribut entfernen....
1816             pNode->GetCharAttribs().GetAttribs().Remove(
1817                 pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) );
1818                         delete pAttr; // #i120865#, need free it explicitly
1819         }
1820 
1821         // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt.
1822         pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart );
1823         if ( pAttr )
1824         {
1825             if ( pAttr->IsInside( nStart ) )    // splitten
1826             {
1827                 // ???????????????????????????????
1828                 // eigentlich noch pruefen, ob wirklich splittet, oder return !
1829                 // ???????????????????????????????
1830                 sal_uInt16 nOldEnd = pAttr->GetEnd();
1831                 pAttr->GetEnd() = nStart;
1832                 pAttr = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd );
1833                 pNode->GetCharAttribs().InsertAttrib( pAttr );
1834             }
1835             else if ( pAttr->GetEnd() == nStart )
1836             {
1837                 DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" );
1838                 // pruefen, ob genau das gleiche Attribut
1839                 if ( *(pAttr->GetItem()) == rPoolItem )
1840                     return;
1841             }
1842         }
1843         InsertAttrib( rPoolItem, pNode, nStart, nStart );
1844     }
1845 
1846     SetModified( sal_True );
1847 }
1848 
FindAttribs(ContentNode * pNode,sal_uInt16 nStartPos,sal_uInt16 nEndPos,SfxItemSet & rCurSet)1849 void EditDoc::FindAttribs( ContentNode* pNode, sal_uInt16 nStartPos, sal_uInt16 nEndPos, SfxItemSet& rCurSet )
1850 {
1851     DBG_ASSERT( pNode, "Wo soll ich suchen ?" );
1852     DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" );
1853 
1854     sal_uInt16 nAttr = 0;
1855     EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1856     // keine Selection...
1857     if ( nStartPos == nEndPos )
1858     {
1859         while ( pAttr && ( pAttr->GetStart() <= nEndPos) )
1860         {
1861             const SfxPoolItem* pItem = 0;
1862             // Attribut liegt dadrueber...
1863             if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
1864                 pItem = pAttr->GetItem();
1865             // Attribut endet hier, ist nicht leer
1866             else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
1867             {
1868                 if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) )
1869                     pItem = pAttr->GetItem();
1870             }
1871             // Attribut endet hier, ist leer
1872             else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) )
1873             {
1874                 pItem = pAttr->GetItem();
1875             }
1876             // Attribut beginnt hier
1877             else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) )
1878             {
1879                 if ( nStartPos == 0 )   // Sonderfall
1880                     pItem = pAttr->GetItem();
1881             }
1882 
1883             if ( pItem )
1884             {
1885                 sal_uInt16 nWhich = pItem->Which();
1886                 if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
1887                 {
1888                     rCurSet.Put( *pItem );
1889                 }
1890                 else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
1891                 {
1892                     const SfxPoolItem& rItem = rCurSet.Get( nWhich );
1893                     if ( rItem != *pItem )
1894                     {
1895                         rCurSet.InvalidateItem( nWhich );
1896                     }
1897                 }
1898             }
1899             nAttr++;
1900             pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1901         }
1902     }
1903     else    // Selektion
1904     {
1905         while ( pAttr && ( pAttr->GetStart() < nEndPos) )
1906         {
1907             const SfxPoolItem* pItem = 0;
1908             // Attribut liegt dadrueber...
1909             if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) )
1910                 pItem = pAttr->GetItem();
1911             // Attribut startet mitten drin...
1912             else if ( pAttr->GetStart() >= nStartPos )
1913             {
1914                 // !!! pItem = pAttr->GetItem();
1915                 // einfach nur pItem reicht nicht, da ich z.B. bei Shadow
1916                 // niemals ein ungleiches Item finden wuerde, da ein solche
1917                 // seine Anwesenheit durch Abwesenheit repraesentiert!
1918                 // if ( ... )
1919                 // Es muesste geprueft werden, on genau das gleiche Attribut
1920                 // an der Bruchstelle aufsetzt, was recht aufwendig ist.
1921                 // Da ich beim Einfuegen von Attributen aber etwas optimiere
1922                 // tritt der Fall nicht so schnell auf...
1923                 // Also aus Geschwindigkeitsgruenden:
1924                 rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
1925 
1926             }
1927             // Attribut endet mitten drin...
1928             else if ( pAttr->GetEnd() > nStartPos )
1929             {
1930                 // pItem = pAttr->GetItem();
1931                 // s.o.
1932                 /*-----------------31.05.95 16:01-------------------
1933                  Ist falsch, wenn das gleiche Attribut sofort wieder
1934                  eingestellt wird!
1935                  => Sollte am besten nicht vorkommen, also gleich beim
1936                     Setzen von Attributen richtig machen!
1937                 --------------------------------------------------*/
1938                 rCurSet.InvalidateItem( pAttr->GetItem()->Which() );
1939             }
1940 
1941             if ( pItem )
1942             {
1943                 sal_uInt16 nWhich = pItem->Which();
1944                 if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
1945                 {
1946                     rCurSet.Put( *pItem );
1947                 }
1948                 else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
1949                 {
1950                     const SfxPoolItem& rItem = rCurSet.Get( nWhich );
1951                     if ( rItem != *pItem )
1952                     {
1953                         rCurSet.InvalidateItem( nWhich );
1954                     }
1955                 }
1956             }
1957             nAttr++;
1958             pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
1959         }
1960     }
1961 }
1962 
1963 
1964 // -------------------------------------------------------------------------
1965 // class EditCharAttribList
1966 // -------------------------------------------------------------------------
1967 
CharAttribList()1968 CharAttribList::CharAttribList()
1969 {
1970     DBG_CTOR( EE_CharAttribList, 0 );
1971     bHasEmptyAttribs = sal_False;
1972 }
1973 
~CharAttribList()1974 CharAttribList::~CharAttribList()
1975 {
1976     DBG_DTOR( EE_CharAttribList, 0 );
1977 
1978     sal_uInt16 nAttr = 0;
1979     EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
1980     while ( pAttr )
1981     {
1982         delete pAttr;
1983         ++nAttr;
1984         pAttr = GetAttrib( aAttribs, nAttr );
1985     }
1986     Clear();
1987 }
1988 
InsertAttrib(EditCharAttrib * pAttrib)1989 void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
1990 {
1991 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1992 // optimieren: binaere Suche ? !
1993 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1994 
1995     // MT: 26.11.98
1996     // Vielleicht aber auch einfach nur rueckwaerts iterieren:
1997     // Der haeufigste und kritischste Fall: Attribute kommen bereits
1998     // sortiert an (InsertBinTextObject!)
1999     // Hier waere auch binaere Suche nicht optimal.
2000     // => Wuerde einiges bringen!
2001 
2002     const sal_uInt16 nCount = Count();
2003     const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
2004 
2005     if ( pAttrib->IsEmpty() )
2006         bHasEmptyAttribs = sal_True;
2007 
2008     sal_Bool bInserted = sal_False;
2009     for ( sal_uInt16 x = 0; x < nCount; x++ )
2010     {
2011         EditCharAttribPtr pCurAttrib = aAttribs[x];
2012         if ( pCurAttrib->GetStart() > nStart )
2013         {
2014             aAttribs.Insert( pAttrib, x );
2015             bInserted = sal_True;
2016             break;
2017         }
2018     }
2019     if ( !bInserted )
2020         aAttribs.Insert( pAttrib, nCount );
2021 }
2022 
ResortAttribs()2023 void CharAttribList::ResortAttribs()
2024 {
2025     if ( Count() )
2026     {
2027 #if defined __SUNPRO_CC
2028 #pragma disable_warn
2029 #endif
2030         qsort( (void*)aAttribs.GetData(), aAttribs.Count(), sizeof( EditCharAttrib* ), CompareStart );
2031 #if defined __SUNPRO_CC
2032 #pragma enable_warn
2033 #endif
2034     }
2035 }
2036 
OptimizeRanges(SfxItemPool & rItemPool)2037 void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
2038 {
2039     for ( sal_uInt16 n = 0; n < aAttribs.Count(); n++ )
2040     {
2041         EditCharAttrib* pAttr = aAttribs.GetObject( n );
2042         for ( sal_uInt16 nNext = n+1; nNext < aAttribs.Count(); nNext++ )
2043         {
2044             EditCharAttrib* p = aAttribs.GetObject( nNext );
2045             if ( !pAttr->IsFeature() && ( p->GetStart() == pAttr->GetEnd() ) && ( p->Which() == pAttr->Which() ) )
2046             {
2047                 if ( *p->GetItem() == *pAttr->GetItem() )
2048                 {
2049                     pAttr->GetEnd() = p->GetEnd();
2050                     aAttribs.Remove( nNext );
2051                     rItemPool.Remove( *p->GetItem() );
2052                     delete p;
2053                 }
2054                 break;  // only 1 attr with same which can start here.
2055             }
2056             else if ( p->GetStart() > pAttr->GetEnd() )
2057             {
2058                 break;
2059             }
2060         }
2061     }
2062 }
2063 
FindAttrib(sal_uInt16 nWhich,sal_uInt16 nPos)2064 EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
2065 {
2066     // Rueckwaerts, falls eins dort endet, das naechste startet.
2067     // => Das startende gilt...
2068     sal_uInt16 nAttr = aAttribs.Count()-1;
2069     EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
2070     while ( pAttr )
2071     {
2072         if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
2073             return pAttr;
2074         pAttr = GetAttrib( aAttribs, --nAttr );
2075     }
2076     return 0;
2077 }
2078 
FindNextAttrib(sal_uInt16 nWhich,sal_uInt16 nFromPos) const2079 EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos ) const
2080 {
2081     DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
2082     const sal_uInt16 nAttribs = aAttribs.Count();
2083     for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
2084     {
2085         EditCharAttrib* pAttr = aAttribs[ nAttr ];
2086         if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) )
2087             return pAttr;
2088     }
2089     return 0;
2090 }
2091 
HasAttrib(sal_uInt16 nWhich) const2092 sal_Bool CharAttribList::HasAttrib( sal_uInt16 nWhich ) const
2093 {
2094     for ( sal_uInt16 nAttr = aAttribs.Count(); nAttr; )
2095     {
2096         const EditCharAttrib* pAttr = aAttribs[--nAttr];
2097         if ( pAttr->Which() == nWhich )
2098             return sal_True;
2099     }
2100     return sal_False;
2101 }
2102 
HasAttrib(sal_uInt16 nStartPos,sal_uInt16 nEndPos) const2103 sal_Bool CharAttribList::HasAttrib( sal_uInt16 nStartPos, sal_uInt16 nEndPos ) const
2104 {
2105     sal_Bool bAttr = sal_False;
2106     for ( sal_uInt16 nAttr = aAttribs.Count(); nAttr && !bAttr; )
2107     {
2108         const EditCharAttrib* pAttr = aAttribs[--nAttr];
2109         if ( ( pAttr->GetStart() < nEndPos ) && ( pAttr->GetEnd() > nStartPos ) )
2110             return bAttr = sal_True;
2111     }
2112     return bAttr;
2113 }
2114 
2115 
HasBoundingAttrib(sal_uInt16 nBound)2116 sal_Bool CharAttribList::HasBoundingAttrib( sal_uInt16 nBound )
2117 {
2118     // Rueckwaerts, falls eins dort endet, das naechste startet.
2119     // => Das startende gilt...
2120     sal_uInt16 nAttr = aAttribs.Count()-1;
2121     EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
2122     while ( pAttr && ( pAttr->GetEnd() >= nBound ) )
2123     {
2124         if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
2125             return sal_True;
2126         pAttr = GetAttrib( aAttribs, --nAttr );
2127     }
2128     return sal_False;
2129 }
2130 
FindEmptyAttrib(sal_uInt16 nWhich,sal_uInt16 nPos)2131 EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
2132 {
2133     if ( !bHasEmptyAttribs )
2134         return 0;
2135     sal_uInt16 nAttr = 0;
2136     EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr );
2137     while ( pAttr && ( pAttr->GetStart() <= nPos ) )
2138     {
2139         if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
2140             return pAttr;
2141         nAttr++;
2142         pAttr = GetAttrib( aAttribs, nAttr );
2143     }
2144     return 0;
2145 }
2146 
FindFeature(sal_uInt16 nPos) const2147 EditCharAttrib* CharAttribList::FindFeature( sal_uInt16 nPos ) const
2148 {
2149 
2150     sal_uInt16 nAttr = 0;
2151     EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr );
2152 
2153     // erstmal zur gewuenschten Position...
2154     while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) )
2155     {
2156         nAttr++;
2157         pNextAttrib = GetAttrib( aAttribs, nAttr );
2158     }
2159 
2160     // jetzt das Feature suchen...
2161     while ( pNextAttrib && !pNextAttrib->IsFeature() )
2162     {
2163         nAttr++;
2164         pNextAttrib = GetAttrib( aAttribs, nAttr );
2165     }
2166 
2167     return pNextAttrib;
2168 }
2169 
2170 
DeleteEmptyAttribs(SfxItemPool & rItemPool)2171 void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool )
2172 {
2173     for ( sal_uInt16 nAttr = 0; nAttr < aAttribs.Count(); nAttr++ )
2174     {
2175         EditCharAttrib* pAttr = aAttribs[nAttr];
2176         if ( pAttr->IsEmpty() )
2177         {
2178             rItemPool.Remove( *pAttr->GetItem() );
2179             aAttribs.Remove( nAttr );
2180             delete pAttr;
2181             nAttr--;
2182         }
2183     }
2184     bHasEmptyAttribs = sal_False;
2185 }
2186 
DbgCheckAttribs()2187 sal_Bool CharAttribList::DbgCheckAttribs()
2188 {
2189 #ifdef  DBG_UTIL
2190     sal_Bool bOK = sal_True;
2191     for ( sal_uInt16 nAttr = 0; nAttr < aAttribs.Count(); nAttr++ )
2192     {
2193         EditCharAttrib* pAttr = aAttribs[nAttr];
2194         if ( pAttr->GetStart() > pAttr->GetEnd() )
2195         {
2196             bOK = sal_False;
2197             DBG_ERROR( "Attr verdreht" );
2198         }
2199         else if ( pAttr->IsFeature() && ( pAttr->GetLen() != 1 ) )
2200         {
2201             bOK = sal_False;
2202             DBG_ERROR( "Feature, Len != 1" );
2203         }
2204     }
2205     return bOK;
2206 #else
2207     return sal_True;
2208 #endif
2209 }
2210 
2211 
2212 
SvxFontTable()2213 SvxFontTable::SvxFontTable()
2214 {
2215 }
2216 
~SvxFontTable()2217 SvxFontTable::~SvxFontTable()
2218 {
2219     SvxFontItem* pItem = First();
2220     while( pItem )
2221     {
2222         delete pItem;
2223         pItem = Next();
2224     }
2225 }
2226 
GetId(const SvxFontItem & rFontItem)2227 sal_uLong SvxFontTable::GetId( const SvxFontItem& rFontItem )
2228 {
2229     SvxFontItem* pItem = First();
2230     while ( pItem )
2231     {
2232         if ( *pItem == rFontItem )
2233             return GetCurKey();
2234         pItem = Next();
2235     }
2236     DBG_WARNING( "Font nicht gefunden: GetId()" );
2237     return 0;
2238 }
2239 
SvxColorList()2240 SvxColorList::SvxColorList()
2241 {
2242 }
2243 
~SvxColorList()2244 SvxColorList::~SvxColorList()
2245 {
2246     SvxColorItem* pItem = First();
2247     while( pItem )
2248     {
2249         delete pItem;
2250         pItem = Next();
2251     }
2252 }
2253 
GetId(const SvxColorItem & rColorItem)2254 sal_uLong SvxColorList::GetId( const SvxColorItem& rColorItem )
2255 {
2256     SvxColorItem* pItem = First();
2257     while ( pItem )
2258     {
2259         if ( *pItem == rColorItem )
2260             return GetCurPos();
2261         pItem = Next();
2262     }
2263     DBG_WARNING( "Color nicht gefunden: GetId()" );
2264     return 0;
2265 }
2266 
EditEngineItemPool(sal_Bool bPersistenRefCounts)2267 EditEngineItemPool::EditEngineItemPool( sal_Bool bPersistenRefCounts )
2268     : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END,
2269                     aItemInfos, 0, bPersistenRefCounts )
2270 {
2271     SetVersionMap( 1, 3999, 4015, aV1Map );
2272     SetVersionMap( 2, 3999, 4019, aV2Map );
2273     SetVersionMap( 3, 3997, 4020, aV3Map );
2274     SetVersionMap( 4, 3994, 4022, aV4Map );
2275     SetVersionMap( 5, 3994, 4037, aV5Map );
2276 
2277     DBG_ASSERT( EE_DLL(), "EditDLL?!" );
2278     SfxPoolItem** ppDefItems = EE_DLL()->GetGlobalData()->GetDefItems();
2279     SetDefaults( ppDefItems );
2280 }
2281 
~EditEngineItemPool()2282 EditEngineItemPool::~EditEngineItemPool()
2283 {
2284 }
2285 
Store(SvStream & rStream) const2286 SvStream& EditEngineItemPool::Store( SvStream& rStream ) const
2287 {
2288     // Bei einem 3.1-Export muess ein Hack eingebaut werden, da BUG im
2289     // SfxItemSet::Load, aber nicht nachtraeglich in 3.1 fixbar.
2290 
2291     // Der eingestellte Range muss nach Store erhalten bleiben, weil dann
2292     // erst die ItemSets gespeichert werden...
2293 
2294     long nVersion = rStream.GetVersion();
2295     sal_Bool b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) )
2296                         ? sal_True : sal_False;
2297 
2298     EditEngineItemPool* pThis = (EditEngineItemPool*)this;
2299     if ( b31Format )
2300         pThis->SetStoringRange( 3997, 4022 );
2301     else
2302         pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END );
2303 
2304     return SfxItemPool::Store( rStream );
2305 }
2306