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"
40 _SV_IMPL_SORTAR_ALG( SwpHtStart
, SwTxtAttr
* )
41 _SV_IMPL_SORTAR_ALG( SwpHtEnd
, SwTxtAttr
* )
45 void DumpHints( const SwpHtStart
&rHtStart
,
46 const SwpHtEnd
&rHtEnd
)
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() );
58 (aDbstream
<< " -> " ).WriteNumber( *pHt
->GetEnd() );
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
) );
68 (aDbstream
<< '\t').WriteNumber( *pHt
->GetEnd() )<< " <- ";
69 aDbstream
.WriteNumber( *pHt
->GetStart() )<< endl
;
75 inline void DumpHints(const SwpHtStart
&, const SwpHtEnd
&) { }
78 /*************************************************************************
80 *************************************************************************/
82 inline BOOL
IsEqual( const SwTxtAttr
&rHt1
, const SwTxtAttr
&rHt2
)
84 return (long)(&rHt1
) == (long)(&rHt2
);
87 /*************************************************************************
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();
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
119 return (long)&rHt1
< (long)&rHt2
;
122 return ( nHt1
> nHt2
);
124 return ( *rHt1
.GetStart() < *rHt2
.GetStart() );
127 /*************************************************************************
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();
138 if ( *rHt1
.GetStart() == *rHt2
.GetStart() )
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
154 return (long)&rHt1
> (long)&rHt2
;
156 // else return nHt1 < nHt2, see below
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;
174 while( nUnten
<= nOben
)
176 nMitte
= nUnten
+ ( nOben
- nUnten
) / 2;
177 const SwTxtAttr
*pMitte
= (*this)[nMitte
];
178 if( IsEqual( *pMitte
, *pElement
) )
184 if( lcl_IsLessStart( *pMitte
, *pElement
) )
200 /*************************************************************************
201 * SwpHtEnd::Seek_Entry()
202 *************************************************************************/
204 BOOL
SwpHtEnd::Seek_Entry( const SwTxtAttr
*pElement
, USHORT
*pPos
) const
206 USHORT nOben
= Count(), nMitte
, nUnten
= 0;
210 while( nUnten
<= nOben
)
212 nMitte
= nUnten
+ ( nOben
- nUnten
) / 2;
213 const SwTxtAttr
*pMitte
= (*this)[nMitte
];
214 if( IsEqual( *pMitte
, *pElement
) )
220 if( lcl_IsLessEnd( *pMitte
, *pElement
) )
236 /*************************************************************************
238 *************************************************************************/
240 void SwpHintsArray::Insert( const SwTxtAttr
*pHt
)
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");
250 m_HintStarts
.Insert( pHt
);
251 m_HintEnds
.Insert( pHt
);
254 (aDbstream
<< "Insert: " ).WriteNumber( long( pHt
) ) << endl
;
255 DumpHints( m_HintStarts
, m_HintEnds
);
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
);
269 m_HintEnds
.Seek_Entry( pHt
, &nEndPos
);
270 m_HintEnds
.Remove( nEndPos
);
273 (aDbstream
<< "DeleteAtPos: " ).WriteNumber( long( pHt
) ) << endl
;
274 DumpHints( m_HintStarts
, m_HintEnds
);
281 /*************************************************************************
282 * SwpHintsArray::Check()
283 *************************************************************************/
286 #define CHECK_ERR(cond, text) \
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
319 CHECK_ERR( lcl_IsLessStart( *pLastStart
, *pHt
), "HintsCheck: IsLastStart" );
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" );
335 // 4b) IsLessEnd-Konsistenz
337 CHECK_ERR( lcl_IsLessEnd( *pLastEnd
, *pHtEnd
), "HintsCheck: IsLastEnd" );
342 // --- Ueberkreuzungen ---
344 // 5) gleiche Pointer in beiden Arrays
345 if( !m_HintStarts
.Seek_Entry( pHt
, &nIdx
) )
348 CHECK_ERR( STRING_LEN
!= nIdx
, "HintsCheck: no GetStartOf" );
350 // 6) gleiche Pointer in beiden Arrays
351 if( !m_HintEnds
.Seek_Entry( pHt
, &nIdx
) )
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" );
367 #if OSL_DEBUG_LEVEL > 1
368 const SwTxtAttr
* pHtThis
= m_HintStarts
[i
];
369 const SwTxtAttr
* pHtLast
= i
> 0 ? m_HintStarts
[i
-1] : 0;
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" );
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;
400 for ( i
= 0; i
< m_HintStarts
.Count(); ++i
)
402 const SwTxtAttr
*pHt
= m_HintStarts
[i
];
403 if( pLast
&& !lcl_IsLessStart( *pLast
, *pHt
) )
407 // ASSERT( bResort, "!Resort/Start: correcting hints-array" );
408 aDbstream
<< "Resort: Starts" << endl
;
409 DumpHints( m_HintStarts
, m_HintEnds
);
412 m_HintStarts
.Remove( i
);
413 m_HintStarts
.Insert( pHt
);
414 pHt
= m_HintStarts
[i
];
423 for ( i
= 0; i
< m_HintEnds
.Count(); ++i
)
425 const SwTxtAttr
*pHt
= m_HintEnds
[i
];
426 if( pLast
&& !lcl_IsLessEnd( *pLast
, *pHt
) )
430 aDbstream
<< "Resort: Ends" << endl
;
431 DumpHints( m_HintStarts
, m_HintEnds
);
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.
447 aDbstream
<< "Resorted:" << endl
;
448 DumpHints( m_HintStarts
, m_HintEnds
);