1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndhints.cxx,v $
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"
45 _SV_IMPL_SORTAR_ALG( SwpHtStart
, SwTxtAttr
* )
46 _SV_IMPL_SORTAR_ALG( SwpHtEnd
, SwTxtAttr
* )
50 void DumpHints( const SwpHtStart
&rHtStart
,
51 const SwpHtEnd
&rHtEnd
)
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() );
63 (aDbstream
<< " -> " ).WriteNumber( *pHt
->GetEnd() );
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
) );
73 (aDbstream
<< '\t').WriteNumber( *pHt
->GetEnd() )<< " <- ";
74 aDbstream
.WriteNumber( *pHt
->GetStart() )<< endl
;
80 inline void DumpHints(const SwpHtStart
&, const SwpHtEnd
&) { }
83 /*************************************************************************
85 *************************************************************************/
87 inline BOOL
IsEqual( const SwTxtAttr
&rHt1
, const SwTxtAttr
&rHt2
)
89 return (long)(&rHt1
) == (long)(&rHt2
);
92 /*************************************************************************
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();
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
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 /*************************************************************************
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();
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
160 return (long)&rHt1
> (long)&rHt2
;
162 // the order must ensure that META is inside RUBY!
163 return ( nWhich1
> nWhich2
);
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;
181 while( nUnten
<= nOben
)
183 nMitte
= nUnten
+ ( nOben
- nUnten
) / 2;
184 const SwTxtAttr
*pMitte
= (*this)[nMitte
];
185 if( IsEqual( *pMitte
, *pElement
) )
191 if( lcl_IsLessStart( *pMitte
, *pElement
) )
207 /*************************************************************************
208 * SwpHtEnd::Seek_Entry()
209 *************************************************************************/
211 BOOL
SwpHtEnd::Seek_Entry( const SwTxtAttr
*pElement
, USHORT
*pPos
) const
213 USHORT nOben
= Count(), nMitte
, nUnten
= 0;
217 while( nUnten
<= nOben
)
219 nMitte
= nUnten
+ ( nOben
- nUnten
) / 2;
220 const SwTxtAttr
*pMitte
= (*this)[nMitte
];
221 if( IsEqual( *pMitte
, *pElement
) )
227 if( lcl_IsLessEnd( *pMitte
, *pElement
) )
243 /*************************************************************************
245 *************************************************************************/
247 void SwpHintsArray::Insert( const SwTxtAttr
*pHt
)
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");
257 m_HintStarts
.Insert( pHt
);
258 m_HintEnds
.Insert( pHt
);
261 (aDbstream
<< "Insert: " ).WriteNumber( long( pHt
) ) << endl
;
262 DumpHints( m_HintStarts
, m_HintEnds
);
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
);
276 m_HintEnds
.Seek_Entry( pHt
, &nEndPos
);
277 m_HintEnds
.Remove( nEndPos
);
280 (aDbstream
<< "DeleteAtPos: " ).WriteNumber( long( pHt
) ) << endl
;
281 DumpHints( m_HintStarts
, m_HintEnds
);
288 /*************************************************************************
289 * SwpHintsArray::Check()
290 *************************************************************************/
293 #define CHECK_ERR(cond, text) \
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
326 CHECK_ERR( lcl_IsLessStart( *pLastStart
, *pHt
), "HintsCheck: IsLastStart" );
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" );
342 // 4b) IsLessEnd-Konsistenz
344 CHECK_ERR( lcl_IsLessEnd( *pLastEnd
, *pHtEnd
), "HintsCheck: IsLastEnd" );
349 // --- Ueberkreuzungen ---
351 // 5) gleiche Pointer in beiden Arrays
352 if( !m_HintStarts
.Seek_Entry( pHt
, &nIdx
) )
355 CHECK_ERR( STRING_LEN
!= nIdx
, "HintsCheck: no GetStartOf" );
357 // 6) gleiche Pointer in beiden Arrays
358 if( !m_HintEnds
.Seek_Entry( pHt
, &nIdx
) )
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" );
374 #if OSL_DEBUG_LEVEL > 1
375 const SwTxtAttr
* pHtThis
= m_HintStarts
[i
];
376 const SwTxtAttr
* pHtLast
= i
> 0 ? m_HintStarts
[i
-1] : 0;
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!");
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;
438 for ( i
= 0; i
< m_HintStarts
.Count(); ++i
)
440 const SwTxtAttr
*pHt
= m_HintStarts
[i
];
441 if( pLast
&& !lcl_IsLessStart( *pLast
, *pHt
) )
445 // ASSERT( bResort, "!Resort/Start: correcting hints-array" );
446 aDbstream
<< "Resort: Starts" << endl
;
447 DumpHints( m_HintStarts
, m_HintEnds
);
450 m_HintStarts
.Remove( i
);
451 m_HintStarts
.Insert( pHt
);
452 pHt
= m_HintStarts
[i
];
461 for ( i
= 0; i
< m_HintEnds
.Count(); ++i
)
463 const SwTxtAttr
*pHt
= m_HintEnds
[i
];
464 if( pLast
&& !lcl_IsLessEnd( *pLast
, *pHt
) )
468 aDbstream
<< "Resort: Ends" << endl
;
469 DumpHints( m_HintStarts
, m_HintEnds
);
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.
485 aDbstream
<< "Resorted:" << endl
;
486 DumpHints( m_HintStarts
, m_HintEnds
);