summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn LeMoyne Castle <jlc@mail2lee.com>2010-11-02 00:08:15 -0600
committerCédric Bosdonnat <cedricbosdo@openoffice.org>2010-11-04 14:57:37 +0100
commit335534df4946437a12cd3c18b4a24beee188317b (patch)
treedf0098580358b82ccc827cf708644c877a88eba5
parent66c52b972ac2d04012c79fbef00ab216976d68db (diff)
Fixes char overcount when selection ends in middle of word
Patch in sw changes only one object: sw/source/core/txtedt.cxx
-rw-r--r--sw/source/core/txtnode/txtedt.cxx206
1 files changed, 110 insertions, 96 deletions
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 9f053464f3..c03ab0573b 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1864,116 +1864,130 @@ void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
void SwTxtNode::CountWords( SwDocStat& rStat,
xub_StrLen nStt, xub_StrLen nEnd ) const
{
+ sal_Bool isCountAll = ( (0 == nStt) && (GetTxt().Len() == nEnd) );
+
++rStat.nAllPara; // #i93174#: count _all_ paragraphs
- if( nStt < nEnd )
+ if( nStt >= nEnd )
+ { // empty node or empty selection or bad call
+ return;
+ }
+ if ( IsHidden() )
+ { // not counting hidden paras
+ return;
+ }
+ // Shortcut when counting whole paragraph and current count is clean
+ if ( isCountAll && !IsWordCountDirty() )
{
- if ( !IsHidden() )
- {
- ++rStat.nPara;
- ULONG nTmpWords = 0;
- ULONG nTmpChars = 0;
- ULONG nTmpCharsExcludingSpaces = 0; // Number of characters in actual words (i.e. excluding spaces)
-
- // Shortcut: Whole paragraph should be considered and cached values
- // are valid:
- if ( 0 == nStt && GetTxt().Len() == nEnd && !IsWordCountDirty() )
- {
- nTmpWords = GetParaNumberOfWords();
- nTmpChars = GetParaNumberOfChars();
- nTmpCharsExcludingSpaces = GetParaNumberOfCharsExcludingSpaces();
- }
- else
- {
- String aOldStr( m_Text );
- String& rCastStr = const_cast<String&>(m_Text);
-
- // fills the deleted redlines and hidden ranges with cChar:
- const xub_Unicode cChar(' ');
- const USHORT nNumOfMaskedChars =
- lcl_MaskRedlinesAndHiddenText( *this, rCastStr, nStt, nEnd, cChar, false );
-
- // expand fields
- rtl::OUString aExpandText;
- const ModelToViewHelper::ConversionMap* pConversionMap =
- BuildConversionMap( aExpandText );
+ // accumulate into DocStat record to return the values
+ rStat.nWord += GetParaNumberOfWords();
+ rStat.nChar += GetParaNumberOfChars();
+ rStat.nCharExcludingSpaces += GetParaNumberOfCharsExcludingSpaces();
+ return;
+ }
- const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nStt );
- const sal_uInt32 nExpandEnd = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nEnd );
+ // make a copy of the text
+ String& rTextCopy = const_cast<String&>(m_Text);
- const bool bCount = aExpandText.getLength() > 0;
+ // mask out the redlined and hidden text with ' '
+ const xub_Unicode cChar(' ');
+ const USHORT nNumOfMaskedChars = lcl_MaskRedlinesAndHiddenText( *this, rTextCopy, nStt, nEnd, cChar, false );
- // count words in 'regular' text:
- if( bCount && pBreakIt->GetBreakIter().is() )
- {
- const String aScannerText( aExpandText );
- SwScanner aScanner( *this, aScannerText, 0, pConversionMap,
- i18n::WordType::WORD_COUNT,
- (xub_StrLen)nExpandBegin, (xub_StrLen)nExpandEnd );
+ // expand text into pConversionMap for scanner
+ rtl::OUString aExpandText;
+ const ModelToViewHelper::ConversionMap* pConversionMap = BuildConversionMap( aExpandText );
- const rtl::OUString aBreakWord( CH_TXTATR_BREAKWORD );
+ // map start and end points onto the ConversionMap
+ const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nStt );
+ const sal_uInt32 nExpandEnd = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nEnd );
- while ( aScanner.NextWord() )
- {
- if( aScanner.GetLen() > 1 ||
- CH_TXTATR_BREAKWORD != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
- ++nTmpWords;
+ if ( aExpandText.getLength() <= 0 )
+ {
+ OSL_ENSURE(aExpandText.getLength() >= 0, "Node text expansion error: length < 0." );
+ return;
+ }
- if( CH_TXTATR_BREAKWORD != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
- nTmpCharsExcludingSpaces += aScanner.GetLen();
+ //do the count
+ // all counts exclude hidden paras and hidden+redlined within para
+ // definition of space/white chars in SwScanner (and BreakIter!)
+ // uses both lcl_IsSkippableWhiteSpace and BreakIter getWordBoundary in SwScanner
+ sal_uInt32 nTmpWords = 0; // count of all contiguous blocks of non-white chars
+ sal_uInt32 nTmpChars = 0; // count of all chars
+ sal_uInt32 nTmpCharsExcludingSpaces = 0; // all non-white chars
- }
- }
+ ++rStat.nPara; // count of non-empty paras
- ASSERT( aExpandText.getLength() >= nNumOfMaskedChars,
- "More characters hidden that characters in string!" )
- nTmpChars = nExpandEnd - nExpandBegin - nNumOfMaskedChars;
+ // count words in masked and expanded text:
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ const String aScannerText( aExpandText );
+ // zero is NULL for pLanguage -----------v last param = true for clipping
+ SwScanner aScanner( *this, aScannerText, 0, pConversionMap, i18n::WordType::WORD_COUNT,
+ (xub_StrLen)nExpandBegin, (xub_StrLen)nExpandEnd, true );
- // count words in numbering string:
- if ( nStt == 0 && bCount )
- {
- // add numbering label
- const String aNumString = GetNumString();
- const xub_StrLen nNumStringLen = aNumString.Len();
- if ( nNumStringLen > 0 )
- {
- LanguageType aLanguage = GetLang( 0 );
+ // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
+ const rtl::OUString aBreakWord( CH_TXTATR_BREAKWORD );
- SwScanner aScanner( *this, aNumString, &aLanguage, 0,
- i18n::WordType::WORD_COUNT,
- 0, nNumStringLen );
+ while ( aScanner.NextWord() )
+ {
+ // 1 is len(CH_TXTATR_BREAKWORD) : match returns length of match
+ if( 1 != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
+ {
+ ++nTmpWords;
+ nTmpCharsExcludingSpaces += aScanner.GetLen();
+ }
+ }
+ }
- while ( aScanner.NextWord() )
- ++nTmpWords;
+ nTmpChars = nExpandEnd - nExpandBegin - nNumOfMaskedChars;
+ OSL_ENSURE( nTmpChars >= 0, "Less than zero total characters found!" );
- nTmpChars += nNumStringLen;
- }
- else if ( HasBullet() )
- {
- ++nTmpWords;
- ++nTmpChars;
- }
- }
+ // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
+ // nor for mid-word selection - set scanner bClip = true at creation
- delete pConversionMap;
+ // count words in numbering string if started at beginning of para:
+ if ( nStt == 0 )
+ {
+ // count outline number label - ? no expansion into map
+ // always counts all of number-ish label
+ const String aNumString = GetNumString();
+ const xub_StrLen nNumStringLen = aNumString.Len();
+ if ( nNumStringLen > 0 )
+ {
+ LanguageType aLanguage = GetLang( 0 );
- rCastStr = aOldStr;
+ SwScanner aScanner( *this, aNumString, &aLanguage, 0,
+ i18n::WordType::WORD_COUNT, 0, nNumStringLen, true );
- // If the whole paragraph has been calculated, update cached
- // values:
- if ( 0 == nStt && GetTxt().Len() == nEnd )
- {
- SetParaNumberOfWords( nTmpWords );
- SetParaNumberOfChars( nTmpChars );
- SetParaNumberOfCharsExcludingSpaces( nTmpCharsExcludingSpaces );
- SetWordCountDirty( false );
- }
+ while ( aScanner.NextWord() )
+ {
+ ++nTmpWords;
+ nTmpCharsExcludingSpaces += aScanner.GetLen();
}
- rStat.nWord += nTmpWords;
- rStat.nChar += nTmpChars;
- rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
+ nTmpChars += nNumStringLen;
}
+ else if ( HasBullet() )
+ {
+ ++nTmpWords;
+ ++nTmpChars;
+ ++nTmpCharsExcludingSpaces;
+ }
+ }
+
+ delete pConversionMap;
+
+ // If counting the whole para then update cached values and mark clean
+ if ( isCountAll )
+ {
+ SetParaNumberOfWords( nTmpWords );
+ SetParaNumberOfChars( nTmpChars );
+ SetParaNumberOfCharsExcludingSpaces( nTmpCharsExcludingSpaces );
+ SetWordCountDirty( false );
}
+ // accumulate into DocStat record to return the values
+ rStat.nWord += nTmpWords;
+ rStat.nChar += nTmpChars;
+ rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
}
//
@@ -1981,17 +1995,17 @@ void SwTxtNode::CountWords( SwDocStat& rStat,
//
struct SwParaIdleData_Impl
{
- SwWrongList* pWrong; // for spell checking
+ SwWrongList* pWrong; // for spell checking
SwGrammarMarkUp* pGrammarCheck; // for grammar checking / proof reading
SwWrongList* pSmartTags;
ULONG nNumberOfWords;
ULONG nNumberOfChars;
ULONG nNumberOfCharsExcludingSpaces;
- bool bWordCountDirty : 1;
- bool bWrongDirty : 1; // Ist das Wrong-Feld auf invalid?
- bool bGrammarCheckDirty : 1;
- bool bSmartTagDirty : 1;
- bool bAutoComplDirty : 1; // die ACompl-Liste muss angepasst werden
+ bool bWordCountDirty;
+ bool bWrongDirty; // Ist das Wrong-Feld auf invalid?
+ bool bGrammarCheckDirty;
+ bool bSmartTagDirty;
+ bool bAutoComplDirty; // die ACompl-Liste muss angepasst werden
SwParaIdleData_Impl() :
pWrong ( 0 ),
@@ -1999,7 +2013,7 @@ struct SwParaIdleData_Impl
pSmartTags ( 0 ),
nNumberOfWords ( 0 ),
nNumberOfChars ( 0 ),
- nNumberOfCharsExcludingSpaces ( 0 ),
+ nNumberOfCharsExcludingSpaces ( 0 ),
bWordCountDirty ( true ),
bWrongDirty ( true ),
bGrammarCheckDirty ( true ),