sw/source/ui/docvw/edtwin.cxx | 210 ++++++++++++++++++++++++++--------------- sw/source/ui/inc/gloslst.hxx | 5 sw/source/ui/utlui/gloslst.cxx | 6 - 3 files changed, 141 insertions(+), 80 deletions(-)
New commits: commit 230662c3afa208780d280401d63add3eece7ab8f Author: Brad Sowden <c...@sowden.org> Date: Mon Jun 4 22:02:34 2012 +1200 Smarter auto-complete capitalization (#i22961#) and i18n handling If a word is in sentence case then the auto-completed word should be in the same case i.e. if the auto-complete list contains the word "LIBRE" then "Lib" should auto-complete to "Libre" rather than "LibRE". See OpenOffice bug 22961. Also implement better i18n handling for calander month and day names. Previously, if a month or day name was not ASCII then it would only auto-complete if it exactly matched the names retrieved from the internal calander i.e. had be a case sensitive match. Change-Id: I0c4543bd9e912072bce1ceaf4adecd41b55b576b diff --git a/sw/source/ui/docvw/edtwin.cxx b/sw/source/ui/docvw/edtwin.cxx index dca8219..831ab46 100644 --- a/sw/source/ui/docvw/edtwin.cxx +++ b/sw/source/ui/docvw/edtwin.cxx @@ -5565,67 +5565,93 @@ void QuickHelpData::Stop( SwWrtShell& rSh ) void QuickHelpData::FillStrArr( SwWrtShell& rSh, const String& rWord ) { + enum Capitalization { CASE_LOWER, CASE_UPPER, CASE_SENTENCE, CASE_OTHER }; + + // Determine word capitalization + const CharClass& rCC = GetAppCharClass(); + const String sWordLower = rCC.lowercase( rWord ); + Capitalization aWordCase = CASE_OTHER; + if ( rWord.Len() > 0 ) + { + if ( rWord.GetChar(0) == sWordLower.GetChar(0) ) + { + if ( rWord == sWordLower ) + aWordCase = CASE_LOWER; + } + else + { + // First character is not lower case i.e. assume upper or title case + String sWordSentence = sWordLower; + sWordSentence.SetChar( 0, rWord.GetChar(0) ); + if ( rWord == sWordSentence ) + aWordCase = CASE_SENTENCE; + else + { + if ( rWord == static_cast<String>( rCC.uppercase( rWord ) ) ) + aWordCase = CASE_UPPER; + } + } + } + salhelper::SingletonRef<SwCalendarWrapper>* pCalendar = s_getCalendarWrapper(); (*pCalendar)->LoadDefaultCalendar( rSh.GetCurLang() ); + // Add matching calendar month and day names + uno::Sequence< i18n::CalendarItem2 > aNames( (*pCalendar)->getMonths() ); + for ( sal_uInt16 i = 0; i < 2; ++i ) { - uno::Sequence< i18n::CalendarItem2 > aNames( - (*pCalendar)->getMonths() ); - for( int n = 0; n < 2; ++n ) + for ( long n = 0; n < aNames.getLength(); ++n ) { - for( long nPos = 0, nEnd = aNames.getLength(); nPos < nEnd; ++nPos ) + const String& rStr( aNames[n].FullName ); + // Check string longer than word and case insensitive match + if( rStr.Len() > rWord.Len() && + static_cast<String>( rCC.lowercase( rStr, 0, rWord.Len() ) ) + == sWordLower ) { - String sStr( aNames[ nPos ].FullName ); - if( rWord.Len() + 1 < sStr.Len() && - -//!!! UNICODE: missing interface - COMPARE_EQUAL == rWord.CompareIgnoreCaseToAscii( - sStr, rWord.Len() )) + if ( aWordCase == CASE_LOWER ) + pHelpStrings->push_back( rCC.lowercase( rStr ) ); + else if ( aWordCase == CASE_SENTENCE ) { - pHelpStrings->push_back( sStr ); + String sTmp = rCC.lowercase( rStr ); + sTmp.SetChar( 0, rStr.GetChar(0) ); + pHelpStrings->push_back( sTmp ); } + else if ( aWordCase == CASE_UPPER ) + pHelpStrings->push_back( rCC.uppercase( rStr ) ); + else // CASE_OTHER - use retrieved capitalization + pHelpStrings->push_back( rStr ); } - if( !n ) // get data for the second loop - aNames = (*pCalendar)->getDays(); } + // Data for second loop iteration + if ( i == 0 ) + aNames = (*pCalendar)->getDays(); } - // and than add all words from the AutoCompleteWord-List - const SwAutoCompleteWord& rACLst = rSh.GetAutoCompleteWords(); - sal_uInt16 nStt, nEnd; - if( rACLst.GetRange( rWord, nStt, nEnd ) ) + // Add matching words from AutoCompleteWord list + const SwAutoCompleteWord& rACList = rSh.GetAutoCompleteWords(); + sal_uInt16 nPos, nEnd; + // TODO - GetRange only performs a case insensitive match for ASCII + if ( rACList.GetRange( rWord, nPos, nEnd ) ) { - while( nStt < nEnd ) + for ( ; nPos < nEnd; ++nPos ) { - const String& rS = rACLst[ nStt ]; - // only if the count of chars - // from the suggest greater as the - // actual word - if( rS.Len() > rWord.Len() ) + const String& rStr = rACList[nPos]; + // Check string longer than word + if ( rStr.Len() > rWord.Len() ) { - CharClass &rCC = GetAppCharClass(); - String aMatch; - int upper = 0, lower = 0, letters = 0; - for( xub_StrLen i = 0; i < rWord.Len(); i++ ) { - sal_Int32 nCharType = rCC.getCharacterType( rWord, i ); - if( !CharClass::isLetterType( nCharType ) ) - continue; - letters++; - if( i18n::KCharacterType::LOWER & nCharType ) - lower++; - if( i18n::KCharacterType::UPPER & nCharType ) - upper++; + if ( aWordCase == CASE_LOWER ) + pHelpStrings->push_back( rCC.lowercase( rStr ) ); + else if ( aWordCase == CASE_SENTENCE ) + { + String sTmp = rCC.lowercase( rStr ); + sTmp.SetChar( 0, rStr.GetChar(0) ); + pHelpStrings->push_back( sTmp ); } - if (lower == letters) - aMatch = rCC.lowercase( rS ); - else if (upper == letters) - aMatch = rCC.uppercase( rS ); - else // mixed case - use what we have - aMatch = rS; - - pHelpStrings->push_back( aMatch ); + else if ( aWordCase == CASE_UPPER ) + pHelpStrings->push_back( rCC.uppercase( rStr ) ); + else // CASE_OTHER - use retrieved capitalization + pHelpStrings->push_back( rStr ); } - ++nStt; } } } commit d7a6815fbf56fd3f8e6712f1c2cb761e8e1bbd8f Author: Brad Sowden <c...@sowden.org> Date: Sat Jun 2 19:09:43 2012 +1200 Replace SvStringsISortDtor in edtwin.cxx and gloslst.[ch]xx Note that the replacement vector stores all strings first and then sort and "unique" are applied (ASCII treated as case-insensitive). Previously strings were inserted sequentially and only the first version of a string would be stored (case-insensitive ASCII comparision). This should have no material impact as the strings retreived from SwAutoCompleteWord are already unique (case- insensitive ASCII comparison) and the capitalization of the string is generally changed anyway to match the capitalization of the word to be auto-completed. Also, there appears to be no logical reason to store the first inserted version of a string over of the first version post-sort. Change-Id: I132865bbb9b382d417fb2cff9de351fdb2cbfb13 diff --git a/sw/source/ui/docvw/edtwin.cxx b/sw/source/ui/docvw/edtwin.cxx index 6d5cc4f..dca8219 100644 --- a/sw/source/ui/docvw/edtwin.cxx +++ b/sw/source/ui/docvw/edtwin.cxx @@ -143,6 +143,7 @@ #include <PostItMgr.hxx> #include <algorithm> +#include <vector> #include "../../core/inc/rootfrm.hxx" @@ -271,33 +272,39 @@ public: struct QuickHelpData { - SvStringsISortDtor aArr; + std::vector<String> *pHelpStrings; sal_uInt16* pAttrs; CommandExtTextInputData* pCETID; sal_uLong nTipId; sal_uInt16 nLen, nCurArrPos; sal_Bool bClear : 1, bChkInsBlank : 1, bIsTip : 1, bIsAutoText : 1; - QuickHelpData() : pAttrs( 0 ), pCETID( 0 ) { ClearCntnt(); } + QuickHelpData() : pAttrs( 0 ), pCETID( 0 ) + { + pHelpStrings = new std::vector<String>; + ClearCntnt(); + } + ~QuickHelpData() { delete pHelpStrings; } void Move( QuickHelpData& rCpy ); void ClearCntnt(); void Start( SwWrtShell& rSh, sal_uInt16 nWrdLen ); void Stop( SwWrtShell& rSh ); - sal_Bool HasCntnt() const { return aArr.Count() && 0 != nLen; } + sal_Bool HasCntnt() const { return !pHelpStrings->empty() && 0 != nLen; } void Inc( sal_Bool bEndLess ) - { - if( ++nCurArrPos >= aArr.Count() ) - nCurArrPos = (bEndLess && !bIsAutoText )? 0 : nCurArrPos-1; - } + { + if( ++nCurArrPos >= pHelpStrings->size() ) + nCurArrPos = (bEndLess && !bIsAutoText ) ? 0 : nCurArrPos-1; + } void Dec( sal_Bool bEndLess ) - { - if( 0 == nCurArrPos-- ) - nCurArrPos = (bEndLess && !bIsAutoText ) ? aArr.Count()-1 : 0; - } + { + if( 0 == nCurArrPos-- ) + nCurArrPos = (bEndLess && !bIsAutoText ) ? pHelpStrings->size()-1 : 0; + } void FillStrArr( SwWrtShell& rSh, const String& rWord ); + void SortAndFilter(); }; /*-------------------------------------------------------------------- @@ -2468,7 +2475,7 @@ KEYINPUT_CHECKTABLE_INSDEL: // replace the word or abbreviation with the auto text rSh.StartUndo( UNDO_START ); - String sFnd( *aTmpQHD.aArr[ aTmpQHD.nCurArrPos ] ); + String sFnd( (*aTmpQHD.pHelpStrings)[ aTmpQHD.nCurArrPos ] ); if( aTmpQHD.bIsAutoText ) { SwGlossaryList* pList = ::GetGlossaryList(); @@ -5464,9 +5471,9 @@ uno::Reference< ::com::sun::star::accessibility::XAccessible > SwEditWin::Create void QuickHelpData::Move( QuickHelpData& rCpy ) { - // move pointer - aArr.Insert( &rCpy.aArr ); - rCpy.aArr.Remove( (sal_uInt16)0, rCpy.aArr.Count() ); + pHelpStrings->clear(); + std::swap( pHelpStrings, rCpy.pHelpStrings ); + bClear = rCpy.bClear; nLen = rCpy.nLen; nCurArrPos = rCpy.nCurArrPos; @@ -5478,8 +5485,7 @@ void QuickHelpData::Move( QuickHelpData& rCpy ) pCETID = rCpy.pCETID; rCpy.pCETID = 0; - if( pAttrs ) - delete[] pAttrs; + delete[] pAttrs; pAttrs = rCpy.pAttrs; rCpy.pAttrs = 0; } @@ -5489,7 +5495,7 @@ void QuickHelpData::ClearCntnt() nLen = nCurArrPos = 0; bClear = bChkInsBlank = sal_False; nTipId = 0; - aArr.DeleteAndDestroy( 0 , aArr.Count() ); + pHelpStrings->clear(); bIsTip = sal_True; bIsAutoText = sal_True; delete pCETID, pCETID = 0; @@ -5498,8 +5504,11 @@ void QuickHelpData::ClearCntnt() void QuickHelpData::Start( SwWrtShell& rSh, sal_uInt16 nWrdLen ) { - if( pCETID ) delete pCETID, pCETID = 0; - if( pAttrs ) delete[] pAttrs, pAttrs = 0; + delete pCETID; + pCETID = 0; + + delete[] pAttrs; + pAttrs = 0; if( USHRT_MAX != nWrdLen ) { @@ -5515,12 +5524,12 @@ void QuickHelpData::Start( SwWrtShell& rSh, sal_uInt16 nWrdLen ) rSh.GetCharRect().Pos() ))); aPt.Y() -= 3; nTipId = Help::ShowTip( &rWin, Rectangle( aPt, Size( 1, 1 )), - *aArr[ nCurArrPos ], + (*pHelpStrings)[ nCurArrPos ], QUICKHELP_LEFT | QUICKHELP_BOTTOM ); } else { - String sStr( *aArr[ nCurArrPos ] ); + String sStr( (*pHelpStrings)[ nCurArrPos ] ); sStr.Erase( 0, nLen ); sal_uInt16 nL = sStr.Len(); pAttrs = new sal_uInt16[ nL ]; @@ -5573,9 +5582,7 @@ void QuickHelpData::FillStrArr( SwWrtShell& rSh, const String& rWord ) COMPARE_EQUAL == rWord.CompareIgnoreCaseToAscii( sStr, rWord.Len() )) { - String* pNew = new String( sStr ); - if( !aArr.Insert( pNew ) ) - delete pNew; + pHelpStrings->push_back( sStr ); } } if( !n ) // get data for the second loop @@ -5616,15 +5623,42 @@ void QuickHelpData::FillStrArr( SwWrtShell& rSh, const String& rWord ) else // mixed case - use what we have aMatch = rS; - String *pNew = new String( aMatch ); - if (!aArr.Insert( pNew )) - delete pNew; + pHelpStrings->push_back( aMatch ); } ++nStt; } } } +// TODO - implement an i18n aware sort +void QuickHelpData::SortAndFilter() +{ + struct CompareIgnoreCaseAscii + { + bool operator()(const String& s1, const String& s2) const + { + return s1.CompareIgnoreCaseToAscii(s2) == COMPARE_LESS; + } + }; + std::sort( pHelpStrings->begin(), + pHelpStrings->end(), + CompareIgnoreCaseAscii() ); + + struct EqualIgnoreCaseAscii + { + bool operator()(const String& s1, const String& s2) const + { + return s1.CompareIgnoreCaseToAscii(s2) == COMPARE_EQUAL; + } + }; + std::vector<String>::iterator it = std::unique( pHelpStrings->begin(), + pHelpStrings->end(), + EqualIgnoreCaseAscii() ); + pHelpStrings->erase( it, pHelpStrings->end() ); + + nCurArrPos = 0; +} + void SwEditWin::ShowAutoTextCorrectQuickHelp( const String& rWord, SvxAutoCorrCfg* pACfg, SvxAutoCorrect* pACorr, sal_Bool bFromIME ) @@ -5634,10 +5668,10 @@ void SwEditWin::ShowAutoTextCorrectQuickHelp( if( pACfg->IsAutoTextTip() ) { SwGlossaryList* pList = ::GetGlossaryList(); - pList->HasLongName( rWord, &pQuickHlpData->aArr ); + pList->HasLongName( rWord, pQuickHlpData->pHelpStrings ); } - if( pQuickHlpData->aArr.Count() ) + if( !pQuickHlpData->pHelpStrings->empty() ) { pQuickHlpData->bIsTip = sal_True; pQuickHlpData->bIsAutoText = sal_True; @@ -5652,8 +5686,12 @@ void SwEditWin::ShowAutoTextCorrectQuickHelp( pQuickHlpData->FillStrArr( rSh, rWord ); } - if( pQuickHlpData->aArr.Count() ) + + if( !pQuickHlpData->pHelpStrings->empty() ) + { + pQuickHlpData->SortAndFilter(); pQuickHlpData->Start( rSh, rWord.Len() ); + } } void SwEditWin::ShowHeaderFooterSeparator( bool bShowHeader, bool bShowFooter ) diff --git a/sw/source/ui/inc/gloslst.hxx b/sw/source/ui/inc/gloslst.hxx index 66ed6d7..f10cb7b 100644 --- a/sw/source/ui/inc/gloslst.hxx +++ b/sw/source/ui/inc/gloslst.hxx @@ -33,10 +33,9 @@ #include <tools/datetime.hxx> #include <tools/string.hxx> #include <vcl/timer.hxx> -#include <svl/svarray.hxx> class SwGlossaries; -class SvStringsISortDtor; +class vector; struct AutoTextGroup { @@ -66,7 +65,7 @@ public: SwGlossaryList(); ~SwGlossaryList(); - sal_Bool HasLongName(const String& rBegin, SvStringsISortDtor* pLongNames ); + bool HasLongName(const String& rBegin, std::vector<String> *pLongNames); sal_Bool GetShortName(const String& rLongName, String& rShortName, String& rGroupName ); diff --git a/sw/source/ui/utlui/gloslst.cxx b/sw/source/ui/utlui/gloslst.cxx index f5be64a..9203000 100644 --- a/sw/source/ui/utlui/gloslst.cxx +++ b/sw/source/ui/utlui/gloslst.cxx @@ -26,7 +26,6 @@ * ************************************************************************/ -#include <svl/svstdarr.hxx> #include <tools/urlobj.hxx> #include <vcl/dialog.hxx> #include <vcl/msgbox.hxx> @@ -423,7 +422,7 @@ void SwGlossaryList::FillGroup(AutoTextGroup* pGroup, SwGlossaries* pGlossaries) passendem Anfang zurueckgeben ********************************************************************/ -sal_Bool SwGlossaryList::HasLongName(const String& rBegin, SvStringsISortDtor* pLongNames ) +bool SwGlossaryList::HasLongName(const String& rBegin, std::vector<String> *pLongNames) { if(!bFilled) Update(); @@ -441,8 +440,7 @@ sal_Bool SwGlossaryList::HasLongName(const String& rBegin, SvStringsISortDtor* p if( rSCmp.isEqual( sBlock.Copy(0, nBeginLen), rBegin ) && nBeginLen + 1 < sBlock.Len()) { - String* pBlock = new String(sBlock); - pLongNames->Insert(pBlock); + pLongNames->push_back( sBlock ); nFound++; if(FIND_MAX_GLOS == nFound) break; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits