Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <textdoc.hxx>
30 : :
31 : : #include <stdlib.h>
32 : :
33 : :
34 : :
35 : : // Vergleichmethode wird von QuickSort gerufen...
36 : :
37 : 0 : static bool CompareStart( const TextCharAttrib* pFirst, const TextCharAttrib* pSecond )
38 : : {
39 : 0 : return pFirst->GetStart() < pSecond->GetStart();
40 : : }
41 : :
42 : : // -------------------------------------------------------------------------
43 : : // (+) class TextCharAttrib
44 : : // -------------------------------------------------------------------------
45 : 0 : TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd )
46 : : {
47 : 0 : mpAttr = rAttr.Clone();
48 : : mnStart = nStart,
49 : 0 : mnEnd = nEnd;
50 : 0 : }
51 : :
52 : 0 : TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib )
53 : : {
54 : 0 : mpAttr = rTextCharAttrib.GetAttr().Clone();
55 : 0 : mnStart = rTextCharAttrib.mnStart;
56 : 0 : mnEnd = rTextCharAttrib.mnEnd;
57 : 0 : }
58 : :
59 : 0 : TextCharAttrib::~TextCharAttrib()
60 : : {
61 [ # # ]: 0 : delete mpAttr;
62 : 0 : }
63 : :
64 : : // -------------------------------------------------------------------------
65 : : // (+) class TextCharAttribList
66 : : // -------------------------------------------------------------------------
67 : :
68 : 218 : TextCharAttribList::TextCharAttribList()
69 : : {
70 : 218 : mbHasEmptyAttribs = sal_False;
71 : 218 : }
72 : :
73 : 218 : TextCharAttribList::~TextCharAttribList()
74 : : {
75 : : // PTRARR_DEL
76 : 218 : }
77 : :
78 : 0 : void TextCharAttribList::Clear( sal_Bool bDestroyAttribs )
79 : : {
80 [ # # ]: 0 : if ( bDestroyAttribs )
81 [ # # ][ # # ]: 0 : for(iterator it = begin(); it != end(); ++it)
82 [ # # ][ # # ]: 0 : delete *it;
83 : 0 : TextCharAttribs::clear();
84 : 0 : }
85 : :
86 : :
87 : 0 : void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib )
88 : : {
89 [ # # ]: 0 : if ( pAttrib->IsEmpty() )
90 : 0 : mbHasEmptyAttribs = sal_True;
91 : :
92 : 0 : const sal_uInt16 nCount = size();
93 : 0 : const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
94 : 0 : sal_Bool bInserted = sal_False;
95 [ # # ]: 0 : for ( sal_uInt16 x = 0; x < nCount; x++ )
96 : : {
97 : 0 : TextCharAttrib* pCurAttrib = GetAttrib( x );
98 [ # # ]: 0 : if ( pCurAttrib->GetStart() > nStart )
99 : : {
100 [ # # ][ # # ]: 0 : insert( begin() + x, pAttrib );
101 : 0 : bInserted = sal_True;
102 : 0 : break;
103 : : }
104 : : }
105 [ # # ]: 0 : if ( !bInserted )
106 : 0 : push_back( pAttrib );
107 : 0 : }
108 : :
109 : 0 : void TextCharAttribList::ResortAttribs()
110 : : {
111 [ # # ]: 0 : if ( !empty() )
112 : 0 : std::sort( begin(), end(), CompareStart );
113 : 0 : }
114 : :
115 : 0 : TextCharAttrib* TextCharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
116 : : {
117 : : // Rueckwaerts, falls eins dort endet, das naechste startet.
118 : : // => Das startende gilt...
119 : :
120 [ # # ]: 0 : for ( sal_uInt16 nAttr = size(); nAttr; )
121 : : {
122 : 0 : TextCharAttrib* pAttr = GetAttrib( --nAttr );
123 : :
124 [ # # ]: 0 : if ( pAttr->GetEnd() < nPos )
125 : 0 : return 0;
126 : :
127 [ # # ][ # # ]: 0 : if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
[ # # ]
128 : 0 : return pAttr;
129 : : }
130 : 0 : return NULL;
131 : : }
132 : :
133 : 0 : TextCharAttrib* TextCharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos ) const
134 : : {
135 : : DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
136 : 0 : const sal_uInt16 nAttribs = size();
137 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
138 : : {
139 : 0 : TextCharAttrib* pAttr = GetAttrib( nAttr );
140 [ # # ][ # # : 0 : if ( ( pAttr->GetStart() >= nFromPos ) &&
# # # # ]
141 : 0 : ( pAttr->GetEnd() <= nMaxPos ) &&
142 : 0 : ( pAttr->Which() == nWhich ) )
143 : 0 : return pAttr;
144 : : }
145 : 0 : return NULL;
146 : : }
147 : :
148 : 0 : sal_Bool TextCharAttribList::HasAttrib( sal_uInt16 nWhich ) const
149 : : {
150 [ # # ]: 0 : for ( sal_uInt16 nAttr = size(); nAttr; )
151 : : {
152 : 0 : const TextCharAttrib* pAttr = GetAttrib( --nAttr );
153 [ # # ]: 0 : if ( pAttr->Which() == nWhich )
154 : 0 : return sal_True;
155 : : }
156 : 0 : return sal_False;
157 : : }
158 : :
159 : 0 : sal_Bool TextCharAttribList::HasBoundingAttrib( sal_uInt16 nBound )
160 : : {
161 : : // Rueckwaerts, falls eins dort endet, das naechste startet.
162 : : // => Das startende gilt...
163 [ # # ]: 0 : for ( sal_uInt16 nAttr = size(); nAttr; )
164 : : {
165 : 0 : TextCharAttrib* pAttr = GetAttrib( --nAttr );
166 : :
167 [ # # ]: 0 : if ( pAttr->GetEnd() < nBound )
168 : 0 : return sal_False;
169 : :
170 [ # # ][ # # ]: 0 : if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
[ # # ]
171 : 0 : return sal_True;
172 : : }
173 : 0 : return sal_False;
174 : : }
175 : :
176 : 0 : TextCharAttrib* TextCharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
177 : : {
178 [ # # ]: 0 : if ( !mbHasEmptyAttribs )
179 : 0 : return 0;
180 : :
181 : 0 : const sal_uInt16 nAttribs = size();
182 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
183 : : {
184 : 0 : TextCharAttrib* pAttr = GetAttrib( nAttr );
185 [ # # ]: 0 : if ( pAttr->GetStart() > nPos )
186 : 0 : return 0;
187 : :
188 [ # # ][ # # ]: 0 : if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
[ # # ][ # # ]
189 : 0 : return pAttr;
190 : : }
191 : 0 : return 0;
192 : : }
193 : :
194 : 0 : void TextCharAttribList::DeleteEmptyAttribs()
195 : : {
196 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < size(); nAttr++ )
197 : : {
198 : 0 : TextCharAttrib* pAttr = GetAttrib( nAttr );
199 [ # # ]: 0 : if ( pAttr->IsEmpty() )
200 : : {
201 [ # # ][ # # ]: 0 : erase( begin() + nAttr );
202 [ # # ]: 0 : delete pAttr;
203 : 0 : nAttr--;
204 : : }
205 : : }
206 : 0 : mbHasEmptyAttribs = sal_False;
207 : 0 : }
208 : :
209 : : // -------------------------------------------------------------------------
210 : : // (+) class TextNode
211 : : // -------------------------------------------------------------------------
212 : :
213 : 218 : TextNode::TextNode( const String& rText ) :
214 [ + - ]: 218 : maText( rText )
215 : : {
216 : 218 : }
217 : :
218 : 52 : void TextNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew )
219 : : {
220 [ - + ]: 52 : if ( !nNew )
221 : 52 : return;
222 : :
223 : 52 : sal_Bool bResort = sal_False;
224 : 52 : sal_uInt16 nAttribs = maCharAttribs.Count();
225 [ - + ]: 52 : for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
226 : : {
227 : 0 : TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
228 [ # # ]: 0 : if ( pAttrib->GetEnd() >= nIndex )
229 : : {
230 : : // Alle Attribute hinter der Einfuegeposition verschieben...
231 [ # # ]: 0 : if ( pAttrib->GetStart() > nIndex )
232 : : {
233 : 0 : pAttrib->MoveForward( nNew );
234 : : }
235 : : // 0: Leeres Attribut expandieren, wenn an Einfuegestelle
236 [ # # ]: 0 : else if ( pAttrib->IsEmpty() )
237 : : {
238 : : // Index nicht pruefen, leeres durfte nur dort liegen.
239 : : // Wenn spaeter doch Ueberpruefung:
240 : : // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
241 : : // Start <= nIndex, End >= nIndex => Start=End=nIndex!
242 : : // if ( pAttrib->GetStart() == nIndex )
243 : 0 : pAttrib->Expand( nNew );
244 : : }
245 : : // 1: Attribut startet davor, geht bis Index...
246 [ # # ]: 0 : else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
247 : : {
248 : : // Nur expandieren, wenn kein Feature,
249 : : // und wenn nicht in ExcludeListe!
250 : : // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
251 [ # # ]: 0 : if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
252 : : {
253 : 0 : pAttrib->Expand( nNew );
254 : : }
255 : : else
256 : 0 : bResort = sal_True;
257 : : }
258 : : // 2: Attribut startet davor, geht hinter Index...
259 [ # # ][ # # ]: 0 : else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
[ # # ]
260 : : {
261 : 0 : pAttrib->Expand( nNew );
262 : : }
263 : : // 3: Attribut startet auf Index...
264 [ # # ]: 0 : else if ( pAttrib->GetStart() == nIndex )
265 : : {
266 [ # # ]: 0 : if ( nIndex == 0 )
267 : : {
268 : 0 : pAttrib->Expand( nNew );
269 : : // bResort = sal_True; // es gibt ja keine Features mehr...
270 : : }
271 : : else
272 : 0 : pAttrib->MoveForward( nNew );
273 : : }
274 : : }
275 : :
276 : : DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
277 : : DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" );
278 : : DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" );
279 : : }
280 : :
281 [ - + ]: 52 : if ( bResort )
282 : 0 : maCharAttribs.ResortAttribs();
283 : : }
284 : :
285 : 0 : void TextNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted )
286 : : {
287 [ # # ]: 0 : if ( !nDeleted )
288 : 0 : return;
289 : :
290 : 0 : sal_Bool bResort = sal_False;
291 : 0 : sal_uInt16 nEndChanges = nIndex+nDeleted;
292 : :
293 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
294 : : {
295 : 0 : TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
296 : 0 : sal_Bool bDelAttr = sal_False;
297 [ # # ]: 0 : if ( pAttrib->GetEnd() >= nIndex )
298 : : {
299 : : // Alles Attribute hinter der Einfuegeposition verschieben...
300 [ # # ]: 0 : if ( pAttrib->GetStart() >= nEndChanges )
301 : : {
302 : 0 : pAttrib->MoveBackward( nDeleted );
303 : : }
304 : : // 1. Innenliegende Attribute loeschen...
305 [ # # ][ # # ]: 0 : else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
[ # # ]
306 : : {
307 : : // Spezialfall: Attrubt deckt genau den Bereich ab
308 : : // => als leeres Attribut behalten.
309 [ # # ][ # # ]: 0 : if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
[ # # ]
310 : 0 : pAttrib->GetEnd() = nIndex; // leer
311 : : else
312 : 0 : bDelAttr = sal_True;
313 : : }
314 : : // 2. Attribut beginnt davor, endet drinnen oder dahinter...
315 [ # # ][ # # ]: 0 : else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
[ # # ]
316 : : {
317 [ # # ]: 0 : if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen
318 : 0 : pAttrib->GetEnd() = nIndex;
319 : : else
320 : 0 : pAttrib->Collaps( nDeleted ); // endet dahinter
321 : : }
322 : : // 3. Attribut beginnt drinnen, endet dahinter...
323 [ # # ][ # # ]: 0 : else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
[ # # ]
324 : : {
325 : : // Features duerfen nicht expandieren!
326 : 0 : pAttrib->GetStart() = nEndChanges;
327 : 0 : pAttrib->MoveBackward( nDeleted );
328 : : }
329 : : }
330 : :
331 : : DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
332 : : DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
333 [ # # ]: 0 : if ( bDelAttr /* || pAttrib->IsEmpty() */ )
334 : : {
335 : 0 : bResort = sal_True;
336 : 0 : maCharAttribs.RemoveAttrib( nAttr );
337 [ # # ]: 0 : delete pAttrib;
338 : 0 : nAttr--;
339 : : }
340 [ # # ]: 0 : else if ( pAttrib->IsEmpty() )
341 : 0 : maCharAttribs.HasEmptyAttribs() = sal_True;
342 : : }
343 : :
344 [ # # ]: 0 : if ( bResort )
345 : 0 : maCharAttribs.ResortAttribs();
346 : : }
347 : :
348 : 52 : void TextNode::InsertText( sal_uInt16 nPos, const String& rText )
349 : : {
350 : 52 : maText.Insert( rText, nPos );
351 : 52 : ExpandAttribs( nPos, rText.Len() );
352 : 52 : }
353 : :
354 : 0 : void TextNode::InsertText( sal_uInt16 nPos, sal_Unicode c )
355 : : {
356 : 0 : maText.Insert( c, nPos );
357 : 0 : ExpandAttribs( nPos, 1 );
358 : 0 : }
359 : :
360 : 0 : void TextNode::RemoveText( sal_uInt16 nPos, sal_uInt16 nChars )
361 : : {
362 : 0 : maText.Erase( nPos, nChars );
363 : 0 : CollapsAttribs( nPos, nChars );
364 : 0 : }
365 : :
366 : 0 : TextNode* TextNode::Split( sal_uInt16 nPos, sal_Bool bKeepEndingAttribs )
367 : : {
368 [ # # ]: 0 : String aNewText;
369 [ # # ]: 0 : if ( nPos < maText.Len() )
370 : : {
371 [ # # ][ # # ]: 0 : aNewText = maText.Copy( nPos );
[ # # ]
372 [ # # ]: 0 : maText.Erase( nPos );
373 : : }
374 [ # # ][ # # ]: 0 : TextNode* pNew = new TextNode( aNewText );
375 : :
376 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
377 : : {
378 [ # # ]: 0 : TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
379 [ # # ]: 0 : if ( pAttrib->GetEnd() < nPos )
380 : : {
381 : : // bleiben unveraendert....
382 : : ;
383 : : }
384 [ # # ]: 0 : else if ( pAttrib->GetEnd() == nPos )
385 : : {
386 : : // muessen als leeres Attribut kopiert werden.
387 : : // !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste!
388 [ # # ][ # # ]: 0 : if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) )
[ # # ][ # # ]
389 : : {
390 [ # # ][ # # ]: 0 : TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
391 : 0 : pNewAttrib->GetStart() = 0;
392 : 0 : pNewAttrib->GetEnd() = 0;
393 [ # # ]: 0 : pNew->maCharAttribs.InsertAttrib( pNewAttrib );
394 : : }
395 : : }
396 [ # # ][ # # ]: 0 : else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) )
[ # # ][ # # ]
397 : : {
398 : : // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
399 : : // muessen kopiert und geaendert werden
400 [ # # ][ # # ]: 0 : TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
401 : 0 : pNewAttrib->GetStart() = 0;
402 : 0 : pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos;
403 [ # # ]: 0 : pNew->maCharAttribs.InsertAttrib( pNewAttrib );
404 : : // stutzen:
405 : 0 : pAttrib->GetEnd() = nPos;
406 : : }
407 : : else
408 : : {
409 : : DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" );
410 : : DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" );
411 : : // alle dahinter verschieben in den neuen Node (this)
412 [ # # ]: 0 : maCharAttribs.RemoveAttrib( nAttr );
413 [ # # ]: 0 : pNew->maCharAttribs.InsertAttrib( pAttrib );
414 : 0 : pAttrib->GetStart() = pAttrib->GetStart() - nPos;
415 : 0 : pAttrib->GetEnd() = pAttrib->GetEnd() - nPos;
416 : 0 : nAttr--;
417 : : }
418 : : }
419 [ # # ]: 0 : return pNew;
420 : : }
421 : :
422 : 0 : void TextNode::Append( const TextNode& rNode )
423 : : {
424 : 0 : sal_uInt16 nOldLen = maText.Len();
425 : :
426 : 0 : maText += rNode.GetText();
427 : :
428 : 0 : const sal_uInt16 nAttribs = rNode.GetCharAttribs().Count();
429 [ # # ]: 0 : for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
430 : : {
431 : 0 : TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr );
432 : 0 : sal_Bool bMelted = sal_False;
433 [ # # ]: 0 : if ( pAttrib->GetStart() == 0 )
434 : : {
435 : : // Evtl koennen Attribute zusammengefasst werden:
436 : 0 : sal_uInt16 nTmpAttribs = maCharAttribs.Count();
437 [ # # ]: 0 : for ( sal_uInt16 nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ )
438 : : {
439 : 0 : TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr );
440 : :
441 [ # # ]: 0 : if ( pTmpAttrib->GetEnd() == nOldLen )
442 : : {
443 [ # # # # ]: 0 : if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
[ # # ]
444 : 0 : ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) )
445 : : {
446 : 0 : pTmpAttrib->GetEnd() =
447 : 0 : pTmpAttrib->GetEnd() + pAttrib->GetLen();
448 : 0 : bMelted = sal_True;
449 : 0 : break; // es kann nur eins von der Sorte an der Stelle geben
450 : : }
451 : : }
452 : : }
453 : : }
454 : :
455 [ # # ]: 0 : if ( !bMelted )
456 : : {
457 [ # # ]: 0 : TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
458 : 0 : pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen;
459 : 0 : pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen;
460 : 0 : maCharAttribs.InsertAttrib( pNewAttrib );
461 : : }
462 : : }
463 : 0 : }
464 : :
465 : : // -------------------------------------------------------------------------
466 : : // (+) class TextDoc
467 : : // -------------------------------------------------------------------------
468 : :
469 : 90 : TextDoc::TextDoc()
470 : : {
471 : 90 : mnLeftMargin = 0;
472 : 90 : };
473 : :
474 : 90 : TextDoc::~TextDoc()
475 : : {
476 [ + - ]: 90 : DestroyTextNodes();
477 : 90 : }
478 : :
479 : 128 : void TextDoc::Clear()
480 : : {
481 : 128 : DestroyTextNodes();
482 : 128 : }
483 : :
484 : 218 : void TextDoc::DestroyTextNodes()
485 : : {
486 [ + + ]: 436 : for ( sal_uLong nNode = 0; nNode < maTextNodes.Count(); nNode++ )
487 [ + - ]: 218 : delete maTextNodes.GetObject( nNode );
488 : 218 : maTextNodes.clear();
489 : 218 : }
490 : :
491 : 0 : String TextDoc::GetText( const sal_Unicode* pSep ) const
492 : : {
493 [ # # ]: 0 : sal_uLong nLen = GetTextLen( pSep );
494 : 0 : sal_uLong nNodes = maTextNodes.Count();
495 : :
496 [ # # ]: 0 : if ( nLen > STRING_MAXLEN )
497 : : {
498 : : OSL_FAIL( "Text zu gross fuer String" );
499 [ # # ]: 0 : return String();
500 : : }
501 : :
502 [ # # ]: 0 : String aASCIIText;
503 : 0 : sal_uLong nLastNode = nNodes-1;
504 [ # # ]: 0 : for ( sal_uLong nNode = 0; nNode < nNodes; nNode++ )
505 : : {
506 [ # # ]: 0 : TextNode* pNode = maTextNodes.GetObject( nNode );
507 [ # # ]: 0 : String aTmp( pNode->GetText() );
508 [ # # ]: 0 : aASCIIText += aTmp;
509 [ # # ][ # # ]: 0 : if ( pSep && ( nNode != nLastNode ) )
510 [ # # ]: 0 : aASCIIText += pSep;
511 [ # # ]: 0 : }
512 : :
513 [ # # ][ # # ]: 0 : return aASCIIText;
514 : : }
515 : :
516 : 0 : XubString TextDoc::GetText( sal_uLong nPara ) const
517 : : {
518 : 0 : XubString aText;
519 [ # # ][ # # ]: 0 : TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0;
520 [ # # ]: 0 : if ( pNode )
521 [ # # ]: 0 : aText = pNode->GetText();
522 : :
523 : 0 : return aText;
524 : : }
525 : :
526 : :
527 : 0 : sal_uLong TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const
528 : : {
529 : 0 : sal_uLong nLen = 0;
530 : 0 : sal_uLong nNodes = maTextNodes.Count();
531 [ # # ]: 0 : if ( nNodes )
532 : : {
533 : 0 : sal_uLong nStartNode = 0;
534 : 0 : sal_uLong nEndNode = nNodes-1;
535 [ # # ]: 0 : if ( pSel )
536 : : {
537 : 0 : nStartNode = pSel->GetStart().GetPara();
538 : 0 : nEndNode = pSel->GetEnd().GetPara();
539 : : }
540 : :
541 [ # # ]: 0 : for ( sal_uLong nNode = nStartNode; nNode <= nEndNode; nNode++ )
542 : : {
543 : 0 : TextNode* pNode = maTextNodes.GetObject( nNode );
544 : :
545 : 0 : sal_uInt16 nS = 0;
546 : 0 : sal_uLong nE = pNode->GetText().Len();
547 [ # # ][ # # ]: 0 : if ( pSel && ( nNode == pSel->GetStart().GetPara() ) )
[ # # ]
548 : 0 : nS = pSel->GetStart().GetIndex();
549 [ # # ][ # # ]: 0 : if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) )
[ # # ]
550 : 0 : nE = pSel->GetEnd().GetIndex();
551 : :
552 : 0 : nLen += ( nE - nS );
553 : : }
554 : :
555 [ # # ]: 0 : if ( pSep )
556 : 0 : nLen += (nEndNode-nStartNode) * rtl_ustr_getLength(pSep);
557 : : }
558 : :
559 : 0 : return nLen;
560 : : }
561 : :
562 : 0 : TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c )
563 : : {
564 : : DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
565 : : DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
566 : :
567 : 0 : TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
568 : 0 : pNode->InsertText( rPaM.GetIndex(), c );
569 : :
570 : 0 : TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 );
571 : 0 : return aPaM;
572 : : }
573 : :
574 : 52 : TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr )
575 : : {
576 : : DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
577 : : DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
578 : :
579 : 52 : TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
580 : 52 : pNode->InsertText( rPaM.GetIndex(), rStr );
581 : :
582 : 52 : TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() );
583 : 52 : return aPaM;
584 : : }
585 : :
586 : 0 : TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs )
587 : : {
588 : 0 : TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
589 : 0 : TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs );
590 : :
591 : 0 : maTextNodes.Insert( pNew, rPaM.GetPara()+1 );
592 : :
593 : 0 : TextPaM aPaM( rPaM.GetPara()+1, 0 );
594 : 0 : return aPaM;
595 : : }
596 : :
597 : 0 : TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight )
598 : : {
599 : 0 : sal_uInt16 nPrevLen = pLeft->GetText().Len();
600 : 0 : pLeft->Append( *pRight );
601 : :
602 : : // der rechte verschwindet.
603 : 0 : sal_uLong nRight = maTextNodes.GetPos( pRight );
604 : 0 : maTextNodes.Remove( nRight );
605 [ # # ]: 0 : delete pRight;
606 : :
607 : 0 : sal_uLong nLeft = maTextNodes.GetPos( pLeft );
608 : 0 : TextPaM aPaM( nLeft, nPrevLen );
609 : 0 : return aPaM;
610 : : }
611 : :
612 : 0 : TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars )
613 : : {
614 : 0 : TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
615 : 0 : pNode->RemoveText( rPaM.GetIndex(), nChars );
616 : :
617 : 0 : return rPaM;
618 : : }
619 : :
620 : 0 : sal_Bool TextDoc::IsValidPaM( const TextPaM& rPaM )
621 : : {
622 [ # # ]: 0 : if ( rPaM.GetPara() >= maTextNodes.Count() )
623 : : {
624 : : OSL_FAIL( "PaM: Para out of range" );
625 : 0 : return sal_False;
626 : : }
627 : 0 : TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() );
628 [ # # ]: 0 : if ( rPaM.GetIndex() > pNode->GetText().Len() )
629 : : {
630 : : OSL_FAIL( "PaM: Index out of range" );
631 : 0 : return sal_False;
632 : : }
633 : 0 : return sal_True;
634 : : }
635 : :
636 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|