merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / txtnode / ndhints.cxx
blobc6a2773db0010352a7e8141050c64c844321ccfe
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 #ifndef PRODUCT
41 #include <pam.hxx>
42 #endif
45 _SV_IMPL_SORTAR_ALG( SwpHtStart, SwTxtAttr* )
46 _SV_IMPL_SORTAR_ALG( SwpHtEnd, SwTxtAttr* )
48 #ifdef NIE
50 void DumpHints( const SwpHtStart &rHtStart,
51 const SwpHtEnd &rHtEnd )
53 #ifndef PRODUCT
54 aDbstream << "DumpHints:" << endl;
55 (aDbstream << "\tStarts:" ).WriteNumber(rHtStart.Count()) << endl;
56 for( USHORT i = 0; i < rHtStart.Count(); ++i )
58 const SwTxtAttr *pHt = rHtStart[i];
59 ((((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
60 << ']' << '\t').WriteNumber( long( pHt ) )
61 << '\t').WriteNumber( *pHt->GetStart() );
62 if( pHt->GetEnd() )
63 (aDbstream << " -> " ).WriteNumber( *pHt->GetEnd() );
64 aDbstream << endl;
66 (aDbstream << "\tEnds:").WriteNumber( rHtEnd.Count() )<< endl;
67 for( i = 0; i < rHtEnd.Count(); ++i )
69 const SwTxtAttr *pHt = rHtEnd[i];
70 (((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() )
71 << ']' << '\t' ).WriteNumber( long( pHt ) );
72 if( pHt->GetEnd() )
73 (aDbstream << '\t').WriteNumber( *pHt->GetEnd() )<< " <- ";
74 aDbstream.WriteNumber( *pHt->GetStart() )<< endl;
76 aDbstream << endl;
77 #endif
79 #else
80 inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { }
81 #endif
83 /*************************************************************************
84 * inline IsEqual()
85 *************************************************************************/
87 inline BOOL IsEqual( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
89 return (long)(&rHt1) == (long)(&rHt2);
92 /*************************************************************************
93 * IsLessStart()
94 *************************************************************************/
96 // SV_IMPL_OP_PTRARR_SORT( SwpHtStart, SwTxtAttr* )
97 // kein SV_IMPL_PTRARR_SORT( name,ArrElement )
98 // unser SEEK_PTR_TO_OBJECT_NOTL( name,ArrElement )
100 // Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!),
101 // als letztes die Adresse selbst
103 static BOOL lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
105 if ( *rHt1.GetStart() == *rHt2.GetStart() )
107 const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
108 const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
109 if ( nHt1 == nHt2 )
111 const USHORT nWhich1 = rHt1.Which();
112 const USHORT nWhich2 = rHt2.Which();
113 if ( nWhich1 == nWhich2 )
115 if ( RES_TXTATR_CHARFMT == nWhich1 )
117 const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
118 const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
119 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessStart trouble" )
120 if ( nS1 != nS2 ) // robust
121 return nS1 < nS2;
124 return (long)&rHt1 < (long)&rHt2;
126 // the order must ensure that META is inside RUBY!
127 return ( nWhich1 < nWhich2 );
129 return ( nHt1 > nHt2 );
131 return ( *rHt1.GetStart() < *rHt2.GetStart() );
134 /*************************************************************************
135 * inline IsLessEnd()
136 *************************************************************************/
138 // Zuerst nach Ende danach nach Ptr
139 static BOOL lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 )
141 const xub_StrLen nHt1 = *rHt1.GetAnyEnd();
142 const xub_StrLen nHt2 = *rHt2.GetAnyEnd();
143 if ( nHt1 == nHt2 )
145 if ( *rHt1.GetStart() == *rHt2.GetStart() )
147 const USHORT nWhich1 = rHt1.Which();
148 const USHORT nWhich2 = rHt2.Which();
149 if ( nWhich1 == nWhich2 )
151 if ( RES_TXTATR_CHARFMT == nWhich1 )
153 const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber();
154 const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber();
155 ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessEnd trouble" )
156 if ( nS1 != nS2 ) // robust
157 return nS1 > nS2;
160 return (long)&rHt1 > (long)&rHt2;
162 // the order must ensure that META is inside RUBY!
163 return ( nWhich1 > nWhich2 );
165 else
166 return ( *rHt1.GetStart() > *rHt2.GetStart() );
168 return ( nHt1 < nHt2 );
171 /*************************************************************************
172 * SwpHtStart::Seek_Entry()
173 *************************************************************************/
175 BOOL SwpHtStart::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const
177 USHORT nOben = Count(), nMitte, nUnten = 0;
178 if( nOben > 0 )
180 nOben--;
181 while( nUnten <= nOben )
183 nMitte = nUnten + ( nOben - nUnten ) / 2;
184 const SwTxtAttr *pMitte = (*this)[nMitte];
185 if( IsEqual( *pMitte, *pElement ) )
187 *pPos = nMitte;
188 return TRUE;
190 else
191 if( lcl_IsLessStart( *pMitte, *pElement ) )
192 nUnten = nMitte + 1;
193 else
194 if( nMitte == 0 )
196 *pPos = nUnten;
197 return FALSE;
199 else
200 nOben = nMitte - 1;
203 *pPos = nUnten;
204 return FALSE;
207 /*************************************************************************
208 * SwpHtEnd::Seek_Entry()
209 *************************************************************************/
211 BOOL SwpHtEnd::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const
213 USHORT nOben = Count(), nMitte, nUnten = 0;
214 if( nOben > 0 )
216 nOben--;
217 while( nUnten <= nOben )
219 nMitte = nUnten + ( nOben - nUnten ) / 2;
220 const SwTxtAttr *pMitte = (*this)[nMitte];
221 if( IsEqual( *pMitte, *pElement ) )
223 *pPos = nMitte;
224 return TRUE;
226 else
227 if( lcl_IsLessEnd( *pMitte, *pElement ) )
228 nUnten = nMitte + 1;
229 else
230 if( nMitte == 0 )
232 *pPos = nUnten;
233 return FALSE;
235 else
236 nOben = nMitte - 1;
239 *pPos = nUnten;
240 return FALSE;
243 /*************************************************************************
244 * class SwpHintsArr
245 *************************************************************************/
247 void SwpHintsArray::Insert( const SwTxtAttr *pHt )
249 Resort();
250 #ifndef PRODUCT
251 USHORT nPos;
252 ASSERT(!m_HintStarts.Seek_Entry( pHt, &nPos ),
253 "Insert: hint already in HtStart");
254 ASSERT(!m_HintEnds.Seek_Entry( pHt, &nPos ),
255 "Insert: hint already in HtEnd");
256 #endif
257 m_HintStarts.Insert( pHt );
258 m_HintEnds.Insert( pHt );
259 #ifndef PRODUCT
260 #ifdef NIE
261 (aDbstream << "Insert: " ).WriteNumber( long( pHt ) ) << endl;
262 DumpHints( m_HintStarts, m_HintEnds );
263 #endif
264 #endif
267 void SwpHintsArray::DeleteAtPos( const USHORT nPos )
269 // optimization: nPos is the position in the Starts array
270 const SwTxtAttr *pHt = m_HintStarts[ nPos ];
271 m_HintStarts.Remove( nPos );
273 Resort();
275 USHORT nEndPos;
276 m_HintEnds.Seek_Entry( pHt, &nEndPos );
277 m_HintEnds.Remove( nEndPos );
278 #ifndef PRODUCT
279 #ifdef NIE
280 (aDbstream << "DeleteAtPos: " ).WriteNumber( long( pHt ) ) << endl;
281 DumpHints( m_HintStarts, m_HintEnds );
282 #endif
283 #endif
286 #ifndef PRODUCT
288 /*************************************************************************
289 * SwpHintsArray::Check()
290 *************************************************************************/
293 #define CHECK_ERR(cond, text) \
294 if(!(cond)) \
296 ASSERT(!this, text); \
297 DumpHints(m_HintStarts, m_HintEnds); \
298 return !(const_cast<SwpHintsArray*>(this))->Resort(); \
301 bool SwpHintsArray::Check() const
303 // 1) gleiche Anzahl in beiden Arrays
304 CHECK_ERR( m_HintStarts.Count() == m_HintEnds.Count(),
305 "HintsCheck: wrong sizes" );
306 xub_StrLen nLastStart = 0;
307 xub_StrLen nLastEnd = 0;
309 const SwTxtAttr *pLastStart = 0;
310 const SwTxtAttr *pLastEnd = 0;
312 for( USHORT i = 0; i < Count(); ++i )
314 // --- Start-Kontrolle ---
316 // 2a) gueltiger Pointer? vgl. DELETEFF
317 const SwTxtAttr *pHt = m_HintStarts[i];
318 CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" );
320 // 3a) Stimmt die Start-Sortierung?
321 xub_StrLen nIdx = *pHt->GetStart();
322 CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" );
324 // 4a) IsLessStart-Konsistenz
325 if( pLastStart )
326 CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" );
328 nLastStart = nIdx;
329 pLastStart = pHt;
331 // --- End-Kontrolle ---
333 // 2b) gueltiger Pointer? vgl. DELETEFF
334 const SwTxtAttr *pHtEnd = m_HintEnds[i];
335 CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" );
337 // 3b) Stimmt die End-Sortierung?
338 nIdx = *pHtEnd->GetAnyEnd();
339 CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" );
340 nLastEnd = nIdx;
342 // 4b) IsLessEnd-Konsistenz
343 if( pLastEnd )
344 CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" );
346 nLastEnd = nIdx;
347 pLastEnd = pHtEnd;
349 // --- Ueberkreuzungen ---
351 // 5) gleiche Pointer in beiden Arrays
352 if( !m_HintStarts.Seek_Entry( pHt, &nIdx ) )
353 nIdx = STRING_LEN;
355 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" );
357 // 6) gleiche Pointer in beiden Arrays
358 if( !m_HintEnds.Seek_Entry( pHt, &nIdx ) )
359 nIdx = STRING_LEN;
361 CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" );
363 // 7a) character attributes in array?
364 USHORT nWhich = pHt->Which();
365 CHECK_ERR( !isCHRATR(nWhich),
366 "HintsCheck: Character attribute in start array" );
368 // 7b) character attributes in array?
369 nWhich = pHtEnd->Which();
370 CHECK_ERR( !isCHRATR(nWhich),
371 "HintsCheck: Character attribute in end array" );
373 // 8) portion check
374 #if OSL_DEBUG_LEVEL > 1
375 const SwTxtAttr* pHtThis = m_HintStarts[i];
376 const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0;
377 CHECK_ERR( 0 == i ||
378 ( RES_TXTATR_CHARFMT != pHtLast->Which() && RES_TXTATR_AUTOFMT != pHtLast->Which() ) ||
379 ( RES_TXTATR_CHARFMT != pHtThis->Which() && RES_TXTATR_AUTOFMT != pHtThis->Which() ) ||
380 ( *pHtThis->GetStart() >= *pHtLast->GetEnd() ) ||
381 ( *pHtThis->GetStart() == *pHtLast->GetStart() && *pHtThis->GetEnd() == *pHtLast->GetEnd() ) ||
382 ( *pHtThis->GetStart() == *pHtThis->GetEnd() ),
383 "HintsCheck: Portion inconsistency. "
384 "This can be temporarily ok during undo operations" );
386 if (pHtThis->IsNesting())
388 for ( USHORT j = 0; j < Count(); ++j )
390 SwTxtAttr const * const pOther( m_HintStarts[j] );
391 if ( pOther->IsNesting() && (i != j) )
393 SwComparePosition cmp = ComparePosition(
394 *pHtThis->GetStart(), *pHtThis->GetEnd(),
395 *pOther->GetStart(), *pOther->GetEnd());
396 CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) &&
397 (POS_OVERLAP_BEHIND != cmp),
398 "HintsCheck: overlapping nesting hints!!!" );
403 // 9) dummy char check (unfortunately cannot check SwTxtNode::m_Text)
404 if (pHtThis->HasDummyChar())
406 for ( USHORT j = 0; j < i; ++j )
408 SwTxtAttr const * const pOther( m_HintStarts[j] );
409 if (pOther->HasDummyChar())
411 CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()),
412 "HintsCheck: multiple hints claim same CH_TXTATR!");
416 #endif
418 return true;
421 #endif /* PRODUCT */
423 /*************************************************************************
424 * SwpHintsArray::Resort()
425 *************************************************************************/
427 // Resort() wird vor jedem Insert und Delete gerufen.
428 // Wenn Textmasse geloescht wird, so werden die Indizes in
429 // ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung
430 // auf gleichen Positionen.
432 bool SwpHintsArray::Resort()
434 bool bResort = false;
435 const SwTxtAttr *pLast = 0;
436 USHORT i;
438 for ( i = 0; i < m_HintStarts.Count(); ++i )
440 const SwTxtAttr *pHt = m_HintStarts[i];
441 if( pLast && !lcl_IsLessStart( *pLast, *pHt ) )
443 #ifdef NIE
444 #ifndef PRODUCT
445 // ASSERT( bResort, "!Resort/Start: correcting hints-array" );
446 aDbstream << "Resort: Starts" << endl;
447 DumpHints( m_HintStarts, m_HintEnds );
448 #endif
449 #endif
450 m_HintStarts.Remove( i );
451 m_HintStarts.Insert( pHt );
452 pHt = m_HintStarts[i];
453 if ( pHt != pLast )
454 --i;
455 bResort = true;
457 pLast = pHt;
460 pLast = 0;
461 for ( i = 0; i < m_HintEnds.Count(); ++i )
463 const SwTxtAttr *pHt = m_HintEnds[i];
464 if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) )
466 #ifdef NIE
467 #ifndef PRODUCT
468 aDbstream << "Resort: Ends" << endl;
469 DumpHints( m_HintStarts, m_HintEnds );
470 #endif
471 #endif
472 m_HintEnds.Remove( i );
473 m_HintEnds.Insert( pHt );
474 pHt = m_HintEnds[i]; // normalerweise == pLast
475 // Wenn die Unordnung etwas groesser ist (24200),
476 // muessen wir Position i erneut vergleichen.
477 if ( pLast != pHt )
478 --i;
479 bResort = true;
481 pLast = pHt;
483 #ifndef PRODUCT
484 #ifdef NIE
485 aDbstream << "Resorted:" << endl;
486 DumpHints( m_HintStarts, m_HintEnds );
487 #endif
488 #endif
489 return bResort;