diff options
Diffstat (limited to 'sw/source/core/txtnode/ndhints.cxx')
-rw-r--r-- | sw/source/core/txtnode/ndhints.cxx | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/sw/source/core/txtnode/ndhints.cxx b/sw/source/core/txtnode/ndhints.cxx new file mode 100644 index 000000000000..c4c78fd6d59d --- /dev/null +++ b/sw/source/core/txtnode/ndhints.cxx @@ -0,0 +1,497 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "txatbase.hxx" +#include "ndhints.hxx" +#include <txtatr.hxx> + +#ifndef PRODUCT +#include <pam.hxx> +#endif + + +_SV_IMPL_SORTAR_ALG( SwpHtStart, SwTxtAttr* ) +_SV_IMPL_SORTAR_ALG( SwpHtEnd, SwTxtAttr* ) + +#ifdef NIE + +void DumpHints( const SwpHtStart &rHtStart, + const SwpHtEnd &rHtEnd ) +{ +#ifdef DBG_UTIL + aDbstream << "DumpHints:" << endl; + (aDbstream << "\tStarts:" ).WriteNumber(rHtStart.Count()) << endl; + for( USHORT i = 0; i < rHtStart.Count(); ++i ) + { + const SwTxtAttr *pHt = rHtStart[i]; + ((((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() ) + << ']' << '\t').WriteNumber( long( pHt ) ) + << '\t').WriteNumber( *pHt->GetStart() ); + if( pHt->GetEnd() ) + (aDbstream << " -> " ).WriteNumber( *pHt->GetEnd() ); + aDbstream << endl; + } + (aDbstream << "\tEnds:").WriteNumber( rHtEnd.Count() )<< endl; + for( i = 0; i < rHtEnd.Count(); ++i ) + { + const SwTxtAttr *pHt = rHtEnd[i]; + (((aDbstream << '\t').WriteNumber( i )<< " [").WriteNumber( pHt->Which() ) + << ']' << '\t' ).WriteNumber( long( pHt ) ); + if( pHt->GetEnd() ) + (aDbstream << '\t').WriteNumber( *pHt->GetEnd() )<< " <- "; + aDbstream.WriteNumber( *pHt->GetStart() )<< endl; + } + aDbstream << endl; +#endif +} +#else +inline void DumpHints(const SwpHtStart &, const SwpHtEnd &) { } +#endif + +/************************************************************************* + * inline IsEqual() + *************************************************************************/ + +inline BOOL IsEqual( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 ) +{ + return (long)(&rHt1) == (long)(&rHt2); +} + +/************************************************************************* + * IsLessStart() + *************************************************************************/ + +// SV_IMPL_OP_PTRARR_SORT( SwpHtStart, SwTxtAttr* ) +// kein SV_IMPL_PTRARR_SORT( name,ArrElement ) +// unser SEEK_PTR_TO_OBJECT_NOTL( name,ArrElement ) + +// Sortierreihenfolge: Start, Ende (umgekehrt!), Which-Wert (umgekehrt!), +// als letztes die Adresse selbst + +static BOOL lcl_IsLessStart( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 ) +{ + if ( *rHt1.GetStart() == *rHt2.GetStart() ) + { + const xub_StrLen nHt1 = *rHt1.GetAnyEnd(); + const xub_StrLen nHt2 = *rHt2.GetAnyEnd(); + if ( nHt1 == nHt2 ) + { + const USHORT nWhich1 = rHt1.Which(); + const USHORT nWhich2 = rHt2.Which(); + if ( nWhich1 == nWhich2 ) + { + if ( RES_TXTATR_CHARFMT == nWhich1 ) + { + const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber(); + const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber(); + ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessStart trouble" ) + if ( nS1 != nS2 ) // robust + return nS1 < nS2; + } + + return (long)&rHt1 < (long)&rHt2; + } + // order is important! for requirements see hintids.hxx + return ( nWhich1 > nWhich2 ); + } + return ( nHt1 > nHt2 ); + } + return ( *rHt1.GetStart() < *rHt2.GetStart() ); +} + +/************************************************************************* + * inline IsLessEnd() + *************************************************************************/ + +// Zuerst nach Ende danach nach Ptr +static BOOL lcl_IsLessEnd( const SwTxtAttr &rHt1, const SwTxtAttr &rHt2 ) +{ + const xub_StrLen nHt1 = *rHt1.GetAnyEnd(); + const xub_StrLen nHt2 = *rHt2.GetAnyEnd(); + if ( nHt1 == nHt2 ) + { + if ( *rHt1.GetStart() == *rHt2.GetStart() ) + { + const USHORT nWhich1 = rHt1.Which(); + const USHORT nWhich2 = rHt2.Which(); + if ( nWhich1 == nWhich2 ) + { + if ( RES_TXTATR_CHARFMT == nWhich1 ) + { + const USHORT nS1 = static_cast<const SwTxtCharFmt&>(rHt1).GetSortNumber(); + const USHORT nS2 = static_cast<const SwTxtCharFmt&>(rHt2).GetSortNumber(); + ASSERT( nS1 != nS2, "AUTOSTYLES: lcl_IsLessEnd trouble" ) + if ( nS1 != nS2 ) // robust + return nS1 > nS2; + } + + return (long)&rHt1 > (long)&rHt2; + } + // order is important! for requirements see hintids.hxx + return ( nWhich1 < nWhich2 ); + } + else + return ( *rHt1.GetStart() > *rHt2.GetStart() ); + } + return ( nHt1 < nHt2 ); +} + +/************************************************************************* + * SwpHtStart::Seek_Entry() + *************************************************************************/ + +BOOL SwpHtStart::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const +{ + USHORT nOben = Count(), nMitte, nUnten = 0; + if( nOben > 0 ) + { + nOben--; + while( nUnten <= nOben ) + { + nMitte = nUnten + ( nOben - nUnten ) / 2; + const SwTxtAttr *pMitte = (*this)[nMitte]; + if( IsEqual( *pMitte, *pElement ) ) + { + *pPos = nMitte; + return TRUE; + } + else + if( lcl_IsLessStart( *pMitte, *pElement ) ) + nUnten = nMitte + 1; + else + if( nMitte == 0 ) + { + *pPos = nUnten; + return FALSE; + } + else + nOben = nMitte - 1; + } + } + *pPos = nUnten; + return FALSE; +} + +/************************************************************************* + * SwpHtEnd::Seek_Entry() + *************************************************************************/ + +BOOL SwpHtEnd::Seek_Entry( const SwTxtAttr *pElement, USHORT *pPos ) const +{ + USHORT nOben = Count(), nMitte, nUnten = 0; + if( nOben > 0 ) + { + nOben--; + while( nUnten <= nOben ) + { + nMitte = nUnten + ( nOben - nUnten ) / 2; + const SwTxtAttr *pMitte = (*this)[nMitte]; + if( IsEqual( *pMitte, *pElement ) ) + { + *pPos = nMitte; + return TRUE; + } + else + if( lcl_IsLessEnd( *pMitte, *pElement ) ) + nUnten = nMitte + 1; + else + if( nMitte == 0 ) + { + *pPos = nUnten; + return FALSE; + } + else + nOben = nMitte - 1; + } + } + *pPos = nUnten; + return FALSE; +} + +/************************************************************************* + * class SwpHintsArr + *************************************************************************/ + +void SwpHintsArray::Insert( const SwTxtAttr *pHt ) +{ + Resort(); +#ifdef DBG_UTIL + USHORT nPos; + ASSERT(!m_HintStarts.Seek_Entry( pHt, &nPos ), + "Insert: hint already in HtStart"); + ASSERT(!m_HintEnds.Seek_Entry( pHt, &nPos ), + "Insert: hint already in HtEnd"); +#endif + m_HintStarts.Insert( pHt ); + m_HintEnds.Insert( pHt ); +#ifdef DBG_UTIL +#ifdef NIE + (aDbstream << "Insert: " ).WriteNumber( long( pHt ) ) << endl; + DumpHints( m_HintStarts, m_HintEnds ); +#endif +#endif +} + +void SwpHintsArray::DeleteAtPos( const USHORT nPos ) +{ + // optimization: nPos is the position in the Starts array + const SwTxtAttr *pHt = m_HintStarts[ nPos ]; + m_HintStarts.Remove( nPos ); + + Resort(); + + USHORT nEndPos; + m_HintEnds.Seek_Entry( pHt, &nEndPos ); + m_HintEnds.Remove( nEndPos ); +#ifdef DBG_UTIL +#ifdef NIE + (aDbstream << "DeleteAtPos: " ).WriteNumber( long( pHt ) ) << endl; + DumpHints( m_HintStarts, m_HintEnds ); +#endif +#endif +} + +#ifdef DBG_UTIL + +/************************************************************************* + * SwpHintsArray::Check() + *************************************************************************/ + + +#define CHECK_ERR(cond, text) \ + if(!(cond)) \ + { \ + ASSERT(!this, text); \ + DumpHints(m_HintStarts, m_HintEnds); \ + return !(const_cast<SwpHintsArray*>(this))->Resort(); \ + } + +bool SwpHintsArray::Check() const +{ + // 1) gleiche Anzahl in beiden Arrays + CHECK_ERR( m_HintStarts.Count() == m_HintEnds.Count(), + "HintsCheck: wrong sizes" ); + xub_StrLen nLastStart = 0; + xub_StrLen nLastEnd = 0; + + const SwTxtAttr *pLastStart = 0; + const SwTxtAttr *pLastEnd = 0; + + for( USHORT i = 0; i < Count(); ++i ) + { + // --- Start-Kontrolle --- + + // 2a) gueltiger Pointer? vgl. DELETEFF + const SwTxtAttr *pHt = m_HintStarts[i]; + CHECK_ERR( 0xFF != *(unsigned char*)pHt, "HintsCheck: start ptr was deleted" ); + + // 3a) Stimmt die Start-Sortierung? + xub_StrLen nIdx = *pHt->GetStart(); + CHECK_ERR( nIdx >= nLastStart, "HintsCheck: starts are unsorted" ); + + // 4a) IsLessStart-Konsistenz + if( pLastStart ) + CHECK_ERR( lcl_IsLessStart( *pLastStart, *pHt ), "HintsCheck: IsLastStart" ); + + nLastStart = nIdx; + pLastStart = pHt; + + // --- End-Kontrolle --- + + // 2b) gueltiger Pointer? vgl. DELETEFF + const SwTxtAttr *pHtEnd = m_HintEnds[i]; + CHECK_ERR( 0xFF != *(unsigned char*)pHtEnd, "HintsCheck: end ptr was deleted" ); + + // 3b) Stimmt die End-Sortierung? + nIdx = *pHtEnd->GetAnyEnd(); + CHECK_ERR( nIdx >= nLastEnd, "HintsCheck: ends are unsorted" ); + nLastEnd = nIdx; + + // 4b) IsLessEnd-Konsistenz + if( pLastEnd ) + CHECK_ERR( lcl_IsLessEnd( *pLastEnd, *pHtEnd ), "HintsCheck: IsLastEnd" ); + + nLastEnd = nIdx; + pLastEnd = pHtEnd; + + // --- Ueberkreuzungen --- + + // 5) gleiche Pointer in beiden Arrays + if( !m_HintStarts.Seek_Entry( pHt, &nIdx ) ) + nIdx = STRING_LEN; + + CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetStartOf" ); + + // 6) gleiche Pointer in beiden Arrays + if( !m_HintEnds.Seek_Entry( pHt, &nIdx ) ) + nIdx = STRING_LEN; + + CHECK_ERR( STRING_LEN != nIdx, "HintsCheck: no GetEndOf" ); + + // 7a) character attributes in array? + USHORT nWhich = pHt->Which(); + CHECK_ERR( !isCHRATR(nWhich), + "HintsCheck: Character attribute in start array" ); + + // 7b) character attributes in array? + nWhich = pHtEnd->Which(); + CHECK_ERR( !isCHRATR(nWhich), + "HintsCheck: Character attribute in end array" ); + + // 8) style portion check +#if OSL_DEBUG_LEVEL > 1 + const SwTxtAttr* pHtThis = m_HintStarts[i]; + const SwTxtAttr* pHtLast = i > 0 ? m_HintStarts[i-1] : 0; + CHECK_ERR( 0 == i || + ( RES_TXTATR_CHARFMT != pHtLast->Which() && RES_TXTATR_AUTOFMT != pHtLast->Which() ) || + ( RES_TXTATR_CHARFMT != pHtThis->Which() && RES_TXTATR_AUTOFMT != pHtThis->Which() ) || + ( *pHtThis->GetStart() >= *pHtLast->GetEnd() ) || + ( ( ( (*pHtThis->GetStart() == *pHtLast->GetStart()) + && (*pHtThis->GetEnd() == *pHtLast->GetEnd()) + ) // same range + || (*pHtThis->GetStart() == *pHtThis->GetEnd()) + ) + && ( (pHtThis->Which() != RES_TXTATR_AUTOFMT) + || (pHtLast->Which() != RES_TXTATR_AUTOFMT) + ) // never two AUTOFMT on same range + ), + "HintsCheck: Portion inconsistency. " + "This can be temporarily ok during undo operations" ); + + // 9) nesting portion check + if (pHtThis->IsNesting()) + { + for ( USHORT j = 0; j < Count(); ++j ) + { + SwTxtAttr const * const pOther( m_HintStarts[j] ); + if ( pOther->IsNesting() && (i != j) ) + { + SwComparePosition cmp = ComparePosition( + *pHtThis->GetStart(), *pHtThis->GetEnd(), + *pOther->GetStart(), *pOther->GetEnd()); + CHECK_ERR( (POS_OVERLAP_BEFORE != cmp) && + (POS_OVERLAP_BEHIND != cmp), + "HintsCheck: overlapping nesting hints!!!" ); + } + } + } + + // 10) dummy char check (unfortunately cannot check SwTxtNode::m_Text) + if (pHtThis->HasDummyChar()) + { + for ( USHORT j = 0; j < i; ++j ) + { + SwTxtAttr const * const pOther( m_HintStarts[j] ); + if (pOther->HasDummyChar()) + { + CHECK_ERR( (*pOther->GetStart() != *pHtThis->GetStart()), + "HintsCheck: multiple hints claim same CH_TXTATR!"); + } + } + } +#endif + } + return true; +} + +#endif /* PRODUCT */ + +/************************************************************************* + * SwpHintsArray::Resort() + *************************************************************************/ + +// Resort() wird vor jedem Insert und Delete gerufen. +// Wenn Textmasse geloescht wird, so werden die Indizes in +// ndtxt.cxx angepasst. Leider erfolgt noch keine Neusortierung +// auf gleichen Positionen. + +bool SwpHintsArray::Resort() +{ + bool bResort = false; + const SwTxtAttr *pLast = 0; + USHORT i; + + for ( i = 0; i < m_HintStarts.Count(); ++i ) + { + const SwTxtAttr *pHt = m_HintStarts[i]; + if( pLast && !lcl_IsLessStart( *pLast, *pHt ) ) + { +#ifdef NIE +#ifdef DBG_UTIL +// ASSERT( bResort, "!Resort/Start: correcting hints-array" ); + aDbstream << "Resort: Starts" << endl; + DumpHints( m_HintStarts, m_HintEnds ); +#endif +#endif + m_HintStarts.Remove( i ); + m_HintStarts.Insert( pHt ); + pHt = m_HintStarts[i]; + if ( pHt != pLast ) + --i; + bResort = true; + } + pLast = pHt; + } + + pLast = 0; + for ( i = 0; i < m_HintEnds.Count(); ++i ) + { + const SwTxtAttr *pHt = m_HintEnds[i]; + if( pLast && !lcl_IsLessEnd( *pLast, *pHt ) ) + { +#ifdef NIE +#ifdef DBG_UTIL + aDbstream << "Resort: Ends" << endl; + DumpHints( m_HintStarts, m_HintEnds ); +#endif +#endif + m_HintEnds.Remove( i ); + m_HintEnds.Insert( pHt ); + pHt = m_HintEnds[i]; // normalerweise == pLast + // Wenn die Unordnung etwas groesser ist (24200), + // muessen wir Position i erneut vergleichen. + if ( pLast != pHt ) + --i; + bResort = true; + } + pLast = pHt; + } +#ifdef DBG_UTIL +#ifdef NIE + aDbstream << "Resorted:" << endl; + DumpHints( m_HintStarts, m_HintEnds ); +#endif +#endif + return bResort; +} + + |