Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


Hi,

This patch implements the following:

(1) Completes a TODO in the code related to i18n handling of month and day names with auto-completion. Previously, when non-ASCII names were added to the auto-complete word list these had to be an exact case-sensitive match of the word to be auto-completed. This patch allows a case-insensitive match for non-ASCII names when deciding what names to add to the auto-complete list.

(2) Smarter auto-complete capitalization as described in OpenOffice bug 22961. 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".

https://issues.apache.org/ooo/show_bug.cgi?id=22961

* The algorithm simply looks at the first character in the word to decide whether a word is sentence case. * I've put a TODO in the code as SwAutoCompleteWord::GetRange() only performs an ASCII case-insensitive match (existing limitation). * Sidenote - Initially I tried using CharClass::titlecase() but discovered this doesn't actually work. There appears to be an issue with class cclass_Unicode where "trans" is only ever set to "Transliteration_casemapping" and there is no mechanism to set it to "Transliteration_titlecase".

- make + make dev-install successful
- functionality tested ok
- licence statement on file

Cheers,
Brad

From 7f1e68f9a06bebd6690c8938b379508af96ab26c Mon Sep 17 00:00:00 2001
From: Brad Sowden <code@sowden.org>
Date: Mon, 4 Jun 2012 22:02:34 +1200
Subject: [PATCH 2/2] 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
---
 sw/source/ui/docvw/edtwin.cxx |  114 +++++++++++++++++++++++++----------------
 1 files changed, 70 insertions(+), 44 deletions(-)

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;
         }
     }
 }
-- 
1.7.7.6



Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.