update dev300-m58
[ooovba.git] / sw / source / core / txtnode / ndhints.cxx
blob883251c90509630798d22e65af3d4091c9196693
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndhints.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
36 #include "txatbase.hxx"
37 #include "ndhints.hxx"
38 #include <txtatr.hxx>
40 _SV_IMPL_SORTAR_ALG( SwpHtStart, SwTxtAttr* )
41 _SV_IMPL_SORTAR_ALG( SwpHtEnd, SwTxtAttr* )
43 #ifdef NIE
45 void DumpHints( const SwpHtStart &rHtStart,
46 const SwpHtEnd &rHtEnd )
48 #ifndef PRODUCT
49 aDbstream << "DumpHints:" << endl;
50 (aDbstream << "\tStarts:" ).WriteNumber(rHtStart.Count()) << endl;
51 for( USHORT i = 0; i < rHtStart.Count(); ++i )
53 const SwTxtAttr *pHt = rHtStart[i];
54 ((((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
55 << ']' << '\t').WriteNumber( long( pHt ) )
56 << '\t').WriteNumber( *pHt->GetStart() );
57 if( pHt->GetEnd() )
58 (aDbstream << " -> " ).WriteNumber( *pHt->GetEnd() );
59 aDbstream << endl;
61 (aDbstream << "\tEnds:").WriteNumber( rHtEnd.Count() )<< endl;
62 for( i = 0; i < rHtEnd.Count(); ++i )
64 const SwTxtAttr *pHt = rHtEnd[i];
65 (((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
66 << ']' << '\t' ).WriteNumber( long( pHt ) );
67 if( pHt->GetEnd() )
68 (aDbstream << '\t').WriteNumber( *pHt->GetEnd() )<< " <- ";
69 aDbstream.WriteNumber( *pHt->GetStart() )<< endl;
71 aDbstream << endl;
72 #endif
74 #else
75 inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { }
76 #endif
78 /*************************************************************************
79 * inline IsEqual()
80 *************************************************************************/
82 inline BOOL IsEqual( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
84 return (long)(&rHt1) == (long)(&rHt2);
87 /*************************************************************************
88 * IsLessStart()
89 *************************************************************************/
91 // SV_IMPL_OP_PTRARR_SORT( SwpHtStart, SwTxtAttr* )
92 // kein SV_IMPL_PTRARR_SORT( name,ArrElement )
93 // unser SEEK_PTR_TO_OBJECT_NOTL( name,ArrElement )
95 // Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
96 // als letztes die Adresse selbst
98 static BOOL lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
100 if ( *rHt1.GetStart() == *rHt2.GetStart() )
102 xub_StrLen nHt1 = *rHt1.GetAnyEnd();
103 xub_StrLen nHt2 = *rHt2.GetAnyEnd();
104 if ( nHt1 == nHt2 )
106 nHt1 = rHt1.Which();
107 nHt2 = rHt2.Which();
108 if ( nHt1 == nHt2 )
110 if ( RES_TXTATR_CHARFMT == nHt1 )
112 const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
113 const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
114 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessStart trouble" )
115 if ( nS1 != nS2 ) // robust
116 return nS1 < nS2;
119 return (long)&rHt1 < (long)&rHt2;
122 return ( nHt1 > nHt2 );
124 return ( *rHt1.GetStart() < *rHt2.GetStart() );
127 /*************************************************************************
128 * inline IsLessEnd()
129 *************************************************************************/
131 // Zuerst nach Ende danach nach Ptr
132 static BOOL lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
134 xub_StrLen nHt1 = *rHt1.GetAnyEnd();
135 xub_StrLen nHt2 = *rHt2.GetAnyEnd();
136 if ( nHt1 == nHt2 )
138 if ( *rHt1.GetStart() == *rHt2.GetStart() )
140 nHt1 = rHt1.Which();
141 nHt2 = rHt2.Which();
143 if ( nHt1 == nHt2 )
145 if ( RES_TXTATR_CHARFMT == nHt1 )
147 const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
148 const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
149 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessEnd trouble" )
150 if ( nS1 != nS2 ) // robust
151 return nS1 > nS2;
154 return (long)&rHt1 > (long)&rHt2;
156 // else return nHt1 < nHt2, see below
158 else
159 return ( *rHt1.GetStart() > *rHt2.GetStart() );
161 return ( nHt1 < nHt2 );
164 /*************************************************************************
165 * SwpHtStart::Seek_Entry()
166 *************************************************************************/
168 BOOL SwpHtStart::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const
170 USHORT nOben = Count(), nMitte, nUnten = 0;
171 if( nOben > 0 )
173 nOben--;
174 while( nUnten <= nOben )
176 nMitte = nUnten + ( nOben - nUnten ) / 2;
177 const SwTxtAttr *pMitte = (*this)[nMitte];
178 if( IsEqual( *pMitte, *pElement ) )
180 *pPos = nMitte;
181 return TRUE;
183 else
184 if( lcl_IsLessStart( *pMitte, *pElement ) )
185 nUnten = nMitte + 1;
186 else
187 if( nMitte == 0 )
189 *pPos = nUnten;
190 return FALSE;
192 else
193 nOben = nMitte - 1;
196 *pPos = nUnten;
197 return FALSE;
200 /*************************************************************************
201 * SwpHtEnd::Seek_Entry()
202 *************************************************************************/
204 BOOL SwpHtEnd::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const
206 USHORT nOben = Count(), nMitte, nUnten = 0;
207 if( nOben > 0 )
209 nOben--;
210 while( nUnten <= nOben )
212 nMitte = nUnten + ( nOben - nUnten ) / 2;
213 const SwTxtAttr *pMitte = (*this)[nMitte];
214 if( IsEqual( *pMitte, *pElement ) )
216 *pPos = nMitte;
217 return TRUE;
219 else
220 if( lcl_IsLessEnd( *pMitte, *pElement ) )
221 nUnten = nMitte + 1;
222 else
223 if( nMitte == 0 )
225 *pPos = nUnten;
226 return FALSE;
228 else
229 nOben = nMitte - 1;
232 *pPos = nUnten;
233 return FALSE;
236 /*************************************************************************
237 * class SwpHintsArr
238 *************************************************************************/
240 void SwpHintsArray::Insert( const SwTxtAttr *pHt )
242 Resort();
243 #ifndef PRODUCT
244 USHORT nPos;
245 ASSERT(!m_HintStarts.Seek_Entry( pHt, &nPos ),
246 "Insert: hint already in HtStart");
247 ASSERT(!m_HintEnds.Seek_Entry( pHt, &nPos ),
248 "Insert: hint already in HtEnd");
249 #endif
250 m_HintStarts.Insert( pHt );
251 m_HintEnds.Insert( pHt );
252 #ifndef PRODUCT
253 #ifdef NIE
254 (aDbstream << "Insert: " ).WriteNumber( long( pHt ) ) << endl;
255 DumpHints( m_HintStarts, m_HintEnds );
256 #endif
257 #endif
260 void SwpHintsArray::DeleteAtPos( const USHORT nPos )
262 // optimization: nPos is the position in the Starts array
263 const SwTxtAttr *pHt = m_HintStarts[ nPos ];
264 m_HintStarts.Remove( nPos );
266 Resort();
268 USHORT nEndPos;
269 m_HintEnds.Seek_Entry( pHt, &nEndPos );
270 m_HintEnds.Remove( nEndPos );
271 #ifndef PRODUCT
272 #ifdef NIE
273 (aDbstream << "DeleteAtPos: " ).WriteNumber( long( pHt ) ) << endl;
274 DumpHints( m_HintStarts, m_HintEnds );
275 #endif
276 #endif
279 #ifndef PRODUCT
281 /*************************************************************************
282 * SwpHintsArray::Check()
283 *************************************************************************/
286 #define CHECK_ERR(cond, text) \
287 if(!(cond)) \
289 ASSERT(!this, text); \
290 DumpHints(m_HintStarts, m_HintEnds); \
291 return !(const_cast<SwpHintsArray*>(this))->Resort(); \
294 bool SwpHintsArray::Check() const
296 // 1) gleiche Anzahl in beiden Arrays
297 CHECK_ERR( m_HintStarts.Count() == m_HintEnds.Count(),
298 "HintsCheck: wrong sizes" );
299 xub_StrLen nLastStart = 0;
300 xub_StrLen nLastEnd = 0;
302 const SwTxtAttr *pLastStart = 0;
303 const SwTxtAttr *pLastEnd = 0;
305 for( USHORT i = 0; i < Count(); ++i )
307 // --- Start-Kontrolle ---
309 // 2a) gueltiger Pointer? vgl. DELETEFF
310 const SwTxtAttr *pHt = m_HintStarts[i];
311 CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
313 // 3a) Stimmt die Start-Sortierung?
314 xub_StrLen nIdx = *pHt->GetStart();
315 CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
317 // 4a) IsLessStart-Konsistenz
318 if( pLastStart )
319 CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
321 nLastStart = nIdx;
322 pLastStart = pHt;
324 // --- End-Kontrolle ---
326 // 2b) gueltiger Pointer? vgl. DELETEFF
327 const SwTxtAttr *pHtEnd = m_HintEnds[i];
328 CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
330 // 3b) Stimmt die End-Sortierung?
331 nIdx = *pHtEnd->GetAnyEnd();
332 CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
333 nLastEnd = nIdx;
335 // 4b) IsLessEnd-Konsistenz
336 if( pLastEnd )
337 CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
339 nLastEnd = nIdx;
340 pLastEnd = pHtEnd;
342 // --- Ueberkreuzungen ---
344 // 5) gleiche Pointer in beiden Arrays
345 if( !m_HintStarts.Seek_Entry( pHt, &nIdx ) )
346 nIdx = STRING_LEN;
348 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" );
350 // 6) gleiche Pointer in beiden Arrays
351 if( !m_HintEnds.Seek_Entry( pHt, &nIdx ) )
352 nIdx = STRING_LEN;
354 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" );
356 // 7a) character attributes in array?
357 USHORT nWhich = pHt->Which();
358 CHECK_ERR( !isCHRATR(nWhich),
359 "HintsCheck: Character attribute in start array" );
361 // 7b) character attributes in array?
362 nWhich = pHtEnd->Which();
363 CHECK_ERR( !isCHRATR(nWhich),
364 "HintsCheck: Character attribute in end array" );
366 // 8) portion check
367 #if OSL_DEBUG_LEVEL > 1
368 const SwTxtAttr* pHtThis = m_HintStarts[i];
369 const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
370 CHECK_ERR( 0 == i ||
371 ( RES_TXTATR_CHARFMT != pHtLast->Which() && RES_TXTATR_AUTOFMT != pHtLast->Which() ) ||
372 ( RES_TXTATR_CHARFMT != pHtThis->Which() && RES_TXTATR_AUTOFMT != pHtThis->Which() ) ||
373 ( *pHtThis->GetStart() >= *pHtLast->GetEnd() ) ||
374 ( *pHtThis->GetStart() == *pHtLast->GetStart() && *pHtThis->GetEnd() == *pHtLast->GetEnd() ) ||
375 ( *pHtThis->GetStart() == *pHtThis->GetEnd() ),
376 "HintsCheck: Portion inconsistency. "
377 "This can be temporarily ok during undo operations" );
378 #endif
380 return true;
383 #endif /* PRODUCT */
385 /*************************************************************************
386 * SwpHintsArray::Resort()
387 *************************************************************************/
389 // Resort() wird vor jedem Insert und Delete gerufen.
390 // Wenn Textmasse geloescht wird, so werden die Indizes in
391 // ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung
392 // auf gleichen Positionen.
394 bool SwpHintsArray::Resort()
396 bool bResort = false;
397 const SwTxtAttr *pLast = 0;
398 USHORT i;
400 for ( i = 0; i < m_HintStarts.Count(); ++i )
402 const SwTxtAttr *pHt = m_HintStarts[i];
403 if( pLast && !lcl_IsLessStart( *pLast, *pHt ) )
405 #ifdef NIE
406 #ifndef PRODUCT
407 // ASSERT( bResort, "!Resort/Start: correcting hints-array" );
408 aDbstream << "Resort: Starts" << endl;
409 DumpHints( m_HintStarts, m_HintEnds );
410 #endif
411 #endif
412 m_HintStarts.Remove( i );
413 m_HintStarts.Insert( pHt );
414 pHt = m_HintStarts[i];
415 if ( pHt != pLast )
416 --i;
417 bResort = true;
419 pLast = pHt;
422 pLast = 0;
423 for ( i = 0; i < m_HintEnds.Count(); ++i )
425 const SwTxtAttr *pHt = m_HintEnds[i];
426 if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) )
428 #ifdef NIE
429 #ifndef PRODUCT
430 aDbstream << "Resort: Ends" << endl;
431 DumpHints( m_HintStarts, m_HintEnds );
432 #endif
433 #endif
434 m_HintEnds.Remove( i );
435 m_HintEnds.Insert( pHt );
436 pHt = m_HintEnds[i]; // normalerweise == pLast
437 // Wenn die Unordnung etwas groesser ist (24200),
438 // muessen wir Position i erneut vergleichen.
439 if ( pLast != pHt )
440 --i;
441 bResort = true;
443 pLast = pHt;
445 #ifndef PRODUCT
446 #ifdef NIE
447 aDbstream << "Resorted:" << endl;
448 DumpHints( m_HintStarts, m_HintEnds );
449 #endif
450 #endif
451 return bResort;