LCOV - code coverage report
Current view: top level - linguistic/source - misc.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 161 362 44.5 %
Date: 2015-06-13 12:38:46 Functions: 26 41 63.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file754
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <sal/macros.h>
      21             : #include <tools/debug.hxx>
      22             : #include <unotools/pathoptions.hxx>
      23             : #include <svl/lngmisc.hxx>
      24             : #include <ucbhelper/content.hxx>
      25             : #include <i18nlangtag/languagetag.hxx>
      26             : #include <com/sun/star/beans/XPropertySet.hpp>
      27             : #include <com/sun/star/beans/XFastPropertySet.hpp>
      28             : #include <com/sun/star/beans/XPropertyChangeListener.hpp>
      29             : #include <com/sun/star/beans/PropertyValues.hpp>
      30             : #include <com/sun/star/frame/XTerminateListener.hpp>
      31             : #include <com/sun/star/frame/Desktop.hpp>
      32             : #include <com/sun/star/frame/XStorable.hpp>
      33             : #include <com/sun/star/linguistic2/DictionaryType.hpp>
      34             : #include <com/sun/star/linguistic2/DictionaryList.hpp>
      35             : #include <com/sun/star/linguistic2/LinguProperties.hpp>
      36             : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
      37             : #include <com/sun/star/uno/Sequence.hxx>
      38             : #include <com/sun/star/uno/Reference.h>
      39             : #include <comphelper/processfactory.hxx>
      40             : #include <unotools/localedatawrapper.hxx>
      41             : #include <unotools/syslocale.hxx>
      42             : 
      43             : #include <rtl/instance.hxx>
      44             : 
      45             : #include "linguistic/misc.hxx"
      46             : #include "defs.hxx"
      47             : #include "linguistic/lngprops.hxx"
      48             : #include "linguistic/hyphdta.hxx"
      49             : 
      50             : using namespace osl;
      51             : using namespace com::sun::star;
      52             : using namespace com::sun::star::beans;
      53             : using namespace com::sun::star::lang;
      54             : using namespace com::sun::star::uno;
      55             : using namespace com::sun::star::i18n;
      56             : using namespace com::sun::star::linguistic2;
      57             : 
      58             : namespace linguistic
      59             : {
      60             : 
      61             : //!! multi-thread safe mutex for all platforms !!
      62             : struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
      63             : {
      64             : };
      65             : 
      66  8853914113 : osl::Mutex &    GetLinguMutex()
      67             : {
      68  8853914113 :     return LinguMutex::get();
      69             : }
      70             : 
      71    85382539 : LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang )
      72             : {
      73    85382539 :     static LocaleDataWrapper aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
      74             : 
      75    85382539 :     const LanguageTag &rLcl = aLclDtaWrp.getLoadedLanguageTag();
      76   170765078 :     LanguageTag aLcl( nLang );
      77    85382539 :     if (aLcl != rLcl)
      78           0 :         aLclDtaWrp.setLanguageTag( aLcl );
      79   170765078 :     return aLclDtaWrp;
      80             : }
      81             : 
      82  1214068987 : LanguageType LinguLocaleToLanguage( const ::com::sun::star::lang::Locale& rLocale )
      83             : {
      84  1214068987 :     if ( rLocale.Language.isEmpty() )
      85         338 :         return LANGUAGE_NONE;
      86  1214068649 :     return LanguageTag::convertToLanguageType( rLocale );
      87             : }
      88             : 
      89          30 : ::com::sun::star::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
      90             : {
      91          30 :     if (nLanguage == LANGUAGE_NONE)
      92          30 :         return ::com::sun::star::lang::Locale();
      93           0 :     return LanguageTag::convertToLocale( nLanguage);
      94             : }
      95             : 
      96   863173378 : bool LinguIsUnspecified( LanguageType nLanguage )
      97             : {
      98   863173378 :     switch (nLanguage)
      99             :     {
     100             :         case LANGUAGE_NONE:
     101             :         case LANGUAGE_UNDETERMINED:
     102             :         case LANGUAGE_MULTIPLE:
     103   388885079 :             return true;
     104             :     }
     105   474288299 :     return false;
     106             : }
     107             : 
     108             : // When adding anything keep both LinguIsUnspecified() methods in sync!
     109             : // For mappings between language code string and LanguageType see
     110             : // i18nlangtag/source/isolang/isolang.cxx
     111             : 
     112         344 : bool LinguIsUnspecified( const OUString & rBcp47 )
     113             : {
     114         344 :     if (rBcp47.getLength() != 3)
     115         344 :         return false;
     116           0 :     if (rBcp47 == "zxx" || rBcp47 == "und" || rBcp47 == "mul")
     117           0 :         return true;
     118           0 :     return false;
     119             : }
     120             : 
     121           0 : static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
     122             : {
     123           0 :     sal_Int32 nMin = n1 < n2 ? n1 : n2;
     124           0 :     return nMin < n3 ? nMin : n3;
     125             : }
     126             : 
     127             : class IntArray2D
     128             : {
     129             : private:
     130             :     sal_Int32  *pData;
     131             :     int         n1, n2;
     132             : 
     133             : public:
     134             :     IntArray2D( int nDim1, int nDim2 );
     135             :     ~IntArray2D();
     136             : 
     137             :     sal_Int32 & Value( int i, int k  );
     138             : };
     139             : 
     140           0 : IntArray2D::IntArray2D( int nDim1, int nDim2 )
     141             : {
     142           0 :     n1 = nDim1;
     143           0 :     n2 = nDim2;
     144           0 :     pData = new sal_Int32[n1 * n2];
     145           0 : }
     146             : 
     147           0 : IntArray2D::~IntArray2D()
     148             : {
     149           0 :     delete[] pData;
     150           0 : }
     151             : 
     152           0 : sal_Int32 & IntArray2D::Value( int i, int k  )
     153             : {
     154             :     DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
     155             :     DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
     156             :     DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
     157           0 :     return pData[ i * n2 + k ];
     158             : }
     159             : 
     160           0 : sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
     161             : {
     162           0 :     sal_Int32 nLen1 = rTxt1.getLength();
     163           0 :     sal_Int32 nLen2 = rTxt2.getLength();
     164             : 
     165           0 :     if (nLen1 == 0)
     166           0 :         return nLen2;
     167           0 :     if (nLen2 == 0)
     168           0 :         return nLen1;
     169             : 
     170           0 :     IntArray2D aData( nLen1 + 1, nLen2 + 1 );
     171             : 
     172             :     sal_Int32 i, k;
     173           0 :     for (i = 0;  i <= nLen1;  ++i)
     174           0 :         aData.Value(i, 0) = i;
     175           0 :     for (k = 0;  k <= nLen2;  ++k)
     176           0 :         aData.Value(0, k) = k;
     177           0 :     for (i = 1;  i <= nLen1;  ++i)
     178             :     {
     179           0 :         for (k = 1;  k <= nLen2;  ++k)
     180             :         {
     181           0 :             sal_Unicode c1i = rTxt1[i - 1];
     182           0 :             sal_Unicode c2k = rTxt2[k - 1];
     183           0 :             sal_Int32 nCost = c1i == c2k ? 0 : 1;
     184           0 :             sal_Int32 nNew = Minimum( aData.Value(i-1, k  ) + 1,
     185           0 :                                        aData.Value(i  , k-1) + 1,
     186           0 :                                        aData.Value(i-1, k-1) + nCost );
     187             :             // take transposition (exchange with left or right char) in account
     188           0 :             if (2 < i && 2 < k)
     189             :             {
     190           0 :                 int nT = aData.Value(i-2, k-2) + 1;
     191           0 :                 if (rTxt1[i - 2] != c1i)
     192           0 :                     ++nT;
     193           0 :                 if (rTxt2[k - 2] != c2k)
     194           0 :                     ++nT;
     195           0 :                 if (nT < nNew)
     196           0 :                     nNew = nT;
     197             :             }
     198             : 
     199           0 :             aData.Value(i, k) = nNew;
     200             :         }
     201             :     }
     202           0 :     sal_Int32 nDist = aData.Value(nLen1, nLen2);
     203           0 :     return nDist;
     204             : }
     205             : 
     206    85382531 : bool IsUseDicList( const PropertyValues &rProperties,
     207             :         const uno::Reference< XPropertySet > &rxProp )
     208             : {
     209    85382531 :     bool bRes = true;
     210             : 
     211    85382531 :     sal_Int32 nLen = rProperties.getLength();
     212    85382531 :     const PropertyValue *pVal = rProperties.getConstArray();
     213             :     sal_Int32 i;
     214             : 
     215    85382531 :     for ( i = 0;  i < nLen;  ++i)
     216             :     {
     217           0 :         if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
     218             :         {
     219           0 :             pVal[i].Value >>= bRes;
     220           0 :             break;
     221             :         }
     222             :     }
     223    85382531 :     if (i >= nLen)  // no temporary value found in 'rProperties'
     224             :     {
     225    85382531 :         uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
     226    85382531 :         if (xFast.is())
     227    85382531 :             xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
     228             :     }
     229             : 
     230    85382531 :     return bRes;
     231             : }
     232             : 
     233    85382531 : bool IsIgnoreControlChars( const PropertyValues &rProperties,
     234             :         const uno::Reference< XPropertySet > &rxProp )
     235             : {
     236    85382531 :     bool bRes = true;
     237             : 
     238    85382531 :     sal_Int32 nLen = rProperties.getLength();
     239    85382531 :     const PropertyValue *pVal = rProperties.getConstArray();
     240             :     sal_Int32 i;
     241             : 
     242    85382531 :     for ( i = 0;  i < nLen;  ++i)
     243             :     {
     244           0 :         if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
     245             :         {
     246           0 :             pVal[i].Value >>= bRes;
     247           0 :             break;
     248             :         }
     249             :     }
     250    85382531 :     if (i >= nLen)  // no temporary value found in 'rProperties'
     251             :     {
     252    85382531 :         uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
     253    85382531 :         if (xFast.is())
     254    85382531 :             xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
     255             :     }
     256             : 
     257    85382531 :     return bRes;
     258             : }
     259             : 
     260           0 : static bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
     261             : {
     262           0 :     bool bRes = false;
     263           0 :     if (xEntry.is())
     264             :     {
     265             :         // there has to be (at least one) '=' or '[' denoting a hyphenation position
     266             :         // and it must not be before any character of the word
     267           0 :         sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
     268           0 :         if (nIdx == -1)
     269           0 :             nIdx = xEntry->getDictionaryWord().indexOf( '[' );
     270           0 :         bRes = nIdx != -1  &&  nIdx != 0;
     271             :     }
     272           0 :     return bRes;
     273             : }
     274             : 
     275   194442621 : uno::Reference< XDictionaryEntry > SearchDicList(
     276             :         const uno::Reference< XSearchableDictionaryList > &xDicList,
     277             :         const OUString &rWord, sal_Int16 nLanguage,
     278             :         bool bSearchPosDics, bool bSearchSpellEntry )
     279             : {
     280   194442621 :     MutexGuard  aGuard( GetLinguMutex() );
     281             : 
     282   194442621 :     uno::Reference< XDictionaryEntry > xEntry;
     283             : 
     284   194442621 :     if (!xDicList.is())
     285           0 :         return xEntry;
     286             : 
     287             :     const uno::Sequence< uno::Reference< XDictionary > >
     288   388885242 :             aDics( xDicList->getDictionaries() );
     289             :     const uno::Reference< XDictionary >
     290   194442621 :             *pDic = aDics.getConstArray();
     291   194442621 :     sal_Int32 nDics = xDicList->getCount();
     292             : 
     293             :     sal_Int32 i;
     294  1166652871 :     for (i = 0;  i < nDics;  i++)
     295             :     {
     296   972210891 :         uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
     297             : 
     298   972210891 :         DictionaryType  eType = axDic->getDictionaryType();
     299   972210891 :         sal_Int16           nLang = LinguLocaleToLanguage( axDic->getLocale() );
     300             : 
     301  2916632673 :         if ( axDic.is() && axDic->isActive()
     302  1944421782 :             && (nLang == nLanguage  ||  LinguIsUnspecified( nLang)) )
     303             :         {
     304             :             DBG_ASSERT( eType != DictionaryType_MIXED,
     305             :                 "lng : unexpected dictionary type" );
     306             : 
     307   583326929 :             if (   (!bSearchPosDics  &&  eType == DictionaryType_NEGATIVE)
     308   583326929 :                 || ( bSearchPosDics  &&  eType == DictionaryType_POSITIVE))
     309             :             {
     310   291670676 :                 if ( (xEntry = axDic->getEntry( rWord )).is() )
     311             :                 {
     312         641 :                     if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
     313         641 :                         break;
     314             :                 }
     315   291670035 :                 xEntry = 0;
     316             :             }
     317             :         }
     318   972210250 :     }
     319             : 
     320   388885242 :     return xEntry;
     321             : }
     322             : 
     323           0 : bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
     324             : {
     325           0 :     if (!xDicList.is())
     326           0 :         return true;
     327             : 
     328           0 :     bool bRet = true;
     329             : 
     330           0 :     Sequence< uno::Reference< XDictionary >  > aDics( xDicList->getDictionaries() );
     331           0 :     const uno::Reference< XDictionary >  *pDic = aDics.getConstArray();
     332           0 :     sal_Int32 nCount = aDics.getLength();
     333           0 :     for (sal_Int32 i = 0;  i < nCount;  i++)
     334             :     {
     335             :         try
     336             :         {
     337           0 :             uno::Reference< frame::XStorable >  xStor( pDic[i], UNO_QUERY );
     338           0 :             if (xStor.is())
     339             :             {
     340           0 :                 if (!xStor->isReadonly() && xStor->hasLocation())
     341           0 :                     xStor->store();
     342           0 :             }
     343             :         }
     344           0 :         catch(uno::Exception &)
     345             :         {
     346           0 :             bRet = false;
     347             :         }
     348             :     }
     349             : 
     350           0 :     return bRet;
     351             : }
     352             : 
     353           0 : DictionaryError AddEntryToDic(
     354             :         uno::Reference< XDictionary >  &rxDic,
     355             :         const OUString &rWord, bool bIsNeg,
     356             :         const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
     357             :         bool bStripDot )
     358             : {
     359           0 :     if (!rxDic.is())
     360           0 :         return DictionaryError::NOT_EXISTS;
     361             : 
     362           0 :     OUString aTmp( rWord );
     363           0 :     if (bStripDot)
     364             :     {
     365           0 :         sal_Int32 nLen = rWord.getLength();
     366           0 :         if (nLen > 0  &&  '.' == rWord[ nLen - 1])
     367             :         {
     368             :             // remove trailing '.'
     369             :             // (this is the official way to do this :-( )
     370           0 :             aTmp = aTmp.copy( 0, nLen - 1 );
     371             :         }
     372             :     }
     373           0 :     bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
     374             : 
     375           0 :     DictionaryError nRes = DictionaryError::NONE;
     376           0 :     if (!bAddOk)
     377             :     {
     378           0 :         if (rxDic->isFull())
     379           0 :             nRes = DictionaryError::FULL;
     380             :         else
     381             :         {
     382           0 :             uno::Reference< frame::XStorable >  xStor( rxDic, UNO_QUERY );
     383           0 :             if (xStor.is() && xStor->isReadonly())
     384           0 :                 nRes = DictionaryError::READONLY;
     385             :             else
     386           0 :                 nRes = DictionaryError::UNKNOWN;
     387             :         }
     388             :     }
     389             : 
     390           0 :     return nRes;
     391             : }
     392             : 
     393             : uno::Sequence< sal_Int16 >
     394         129 :     LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
     395             : {
     396         129 :     const Locale *pLocale = rLocaleSeq.getConstArray();
     397         129 :     sal_Int32 nCount = rLocaleSeq.getLength();
     398             : 
     399         129 :     uno::Sequence< sal_Int16 >   aLangs( nCount );
     400         129 :     sal_Int16 *pLang = aLangs.getArray();
     401         473 :     for (sal_Int32 i = 0;  i < nCount;  ++i)
     402             :     {
     403         344 :         pLang[i] = LinguLocaleToLanguage( pLocale[i] );
     404             :     }
     405             : 
     406         129 :     return aLangs;
     407             : }
     408             : 
     409           0 : bool    IsReadOnly( const OUString &rURL, bool *pbExist )
     410             : {
     411           0 :     bool bRes = false;
     412           0 :     bool bExists = false;
     413             : 
     414           0 :     if (!rURL.isEmpty())
     415             :     {
     416             :         try
     417             :         {
     418           0 :             uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
     419           0 :             ::ucbhelper::Content aContent( rURL, xCmdEnv, comphelper::getProcessComponentContext() );
     420             : 
     421           0 :             bExists = aContent.isDocument();
     422           0 :             if (bExists)
     423             :             {
     424           0 :                 Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
     425           0 :                 aAny >>= bRes;
     426           0 :             }
     427             :         }
     428           0 :         catch (Exception &)
     429             :         {
     430           0 :             bRes = true;
     431             :         }
     432             :     }
     433             : 
     434           0 :     if (pbExist)
     435           0 :         *pbExist = bExists;
     436           0 :     return bRes;
     437             : }
     438             : 
     439           0 : static bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
     440             :         uno::Reference< XHyphenatedWord > &rxHyphWord )
     441             : {
     442           0 :     bool bRes = rxHyphWord->isAlternativeSpelling();
     443           0 :     if (bRes)
     444             :     {
     445           0 :         OUString aWord( rxHyphWord->getWord() ),
     446           0 :                  aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
     447           0 :         sal_Int16   nHyphenationPos     = rxHyphWord->getHyphenationPos();
     448             :         /*sal_Int16   nHyphenPos          = rxHyphWord->getHyphenPos()*/;
     449           0 :         const sal_Unicode *pWord    = aWord.getStr(),
     450           0 :                           *pAltWord = aHyphenatedWord.getStr();
     451             : 
     452             :         // at least char changes directly left or right to the hyphen
     453             :         // should(!) be handled properly...
     454             :         //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
     455             :         //! Beware: eg "Schiffahrt" in German (pre spelling reform)
     456             :         //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
     457             :         //! to an extend.)
     458             : 
     459             :         // find first different char from left
     460           0 :         sal_Int32   nPosL    = 0,
     461           0 :                     nAltPosL = 0;
     462           0 :         for (sal_Int16 i = 0 ;  pWord[ nPosL ] == pAltWord[ nAltPosL ];  nPosL++, nAltPosL++, i++)
     463             :         {
     464             :             // restrict changes area beginning to the right to
     465             :             // the char immediately following the hyphen.
     466             :             //! serves to insert the additional "f" in "Schiffahrt" at
     467             :             //! position 5 rather than position 6.
     468           0 :             if (i >= nHyphenationPos + 1)
     469           0 :                 break;
     470             :         }
     471             : 
     472             :         // find first different char from right
     473           0 :         sal_Int32   nPosR    = aWord.getLength() - 1,
     474           0 :                     nAltPosR = aHyphenatedWord.getLength() - 1;
     475           0 :         for ( ;  nPosR >= nPosL  &&  nAltPosR >= nAltPosL
     476           0 :                     &&  pWord[ nPosR ] == pAltWord[ nAltPosR ];
     477             :                 nPosR--, nAltPosR--)
     478             :             ;
     479             : 
     480           0 :         rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
     481           0 :         rnChgLen = sal::static_int_cast< sal_Int16 >(nAltPosR - nPosL);
     482             :         DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
     483             : 
     484           0 :         sal_Int32 nTxtStart = nPosL;
     485           0 :         sal_Int32 nTxtLen   = nAltPosR - nPosL + 1;
     486           0 :         rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
     487             :     }
     488           0 :     return bRes;
     489             : }
     490             : 
     491           0 : static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
     492             : {
     493           0 :     sal_Int32 nLen = rOrigWord.getLength();
     494           0 :     sal_Int32 i = -1;
     495           0 :     while (nPos >= 0  &&  i++ < nLen)
     496             :     {
     497           0 :         sal_Unicode cChar = rOrigWord[i];
     498           0 :         bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
     499           0 :         if (!bSkip)
     500           0 :             --nPos;
     501             :     }
     502           0 :     return sal::static_int_cast< sal_Int16 >((0 <= i  &&  i < nLen) ? i : -1);
     503             : }
     504             : 
     505       10470 : sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
     506             : {
     507       10470 :     sal_Int32 nRes = -1;
     508       10470 :     sal_Int32 nLen = rTxt.getLength();
     509       10470 :     if (0 <= nPos  &&  nPos < nLen)
     510             :     {
     511       10470 :         nRes = 0;
     512       23336 :         for (sal_Int32 i = 0;  i < nPos;  ++i)
     513             :         {
     514       12866 :             sal_Unicode cChar = rTxt[i];
     515       12866 :             bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
     516       12866 :             if (!bSkip)
     517       12866 :                 ++nRes;
     518             :         }
     519             :     }
     520       10470 :     return nRes;
     521             : }
     522             : 
     523           0 : uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
     524             :         const OUString &rOrigWord,
     525             :         uno::Reference< XHyphenatedWord > &rxHyphWord )
     526             : {
     527           0 :     uno::Reference< XHyphenatedWord > xRes;
     528           0 :     if (!rOrigWord.isEmpty() && rxHyphWord.is())
     529             :     {
     530           0 :         sal_Int16    nChgPos = 0,
     531           0 :                  nChgLen = 0;
     532           0 :         OUString aRplc;
     533           0 :         bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
     534             : 
     535           0 :         OUString aOrigHyphenatedWord;
     536           0 :         sal_Int16 nOrigHyphenPos        = -1;
     537           0 :         sal_Int16 nOrigHyphenationPos   = -1;
     538           0 :         if (!bAltSpelling)
     539             :         {
     540           0 :             aOrigHyphenatedWord = rOrigWord;
     541           0 :             nOrigHyphenPos      = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
     542           0 :             nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
     543             :         }
     544             :         else
     545             :         {
     546             :             //! should at least work with the German words
     547             :             //! B-"u-c-k-er and Sc-hif-fah-rt
     548             : 
     549           0 :             OUString aLeft, aRight;
     550           0 :             sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
     551             : 
     552             :             // get words like Sc-hif-fah-rt to work correct
     553           0 :             sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
     554           0 :             if (nChgPos > nHyphenationPos)
     555           0 :                 --nPos;
     556             : 
     557           0 :             aLeft = rOrigWord.copy( 0, nPos );
     558           0 :             aRight = rOrigWord.copy( nPos ); // FIXME: changes at the right side
     559             : 
     560           0 :             aOrigHyphenatedWord =  aLeft;
     561           0 :             aOrigHyphenatedWord += aRplc;
     562           0 :             aOrigHyphenatedWord += aRight;
     563             : 
     564           0 :             nOrigHyphenPos      = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
     565           0 :                                   rxHyphWord->getHyphenPos() - nChgPos);
     566           0 :             nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
     567             :         }
     568             : 
     569           0 :         if (nOrigHyphenPos == -1  ||  nOrigHyphenationPos == -1)
     570             :         {
     571             :             DBG_ASSERT( false, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
     572             :         }
     573             :         else
     574             :         {
     575           0 :             sal_Int16 nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
     576           0 :             xRes = new HyphenatedWord(
     577             :                         rOrigWord, nLang, nOrigHyphenationPos,
     578           0 :                         aOrigHyphenatedWord, nOrigHyphenPos );
     579           0 :         }
     580             : 
     581             :     }
     582           0 :     return xRes;
     583             : }
     584             : 
     585         425 : static CharClass & lcl_GetCharClass()
     586             : {
     587         425 :     static CharClass aCC( LanguageTag( LANGUAGE_ENGLISH_US ));
     588         425 :     return aCC;
     589             : }
     590             : 
     591         425 : osl::Mutex & lcl_GetCharClassMutex()
     592             : {
     593         425 :     static osl::Mutex   aMutex;
     594         425 :     return aMutex;
     595             : }
     596             : 
     597           0 : bool IsUpper( const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, sal_Int16 nLanguage )
     598             : {
     599           0 :     MutexGuard  aGuard( lcl_GetCharClassMutex() );
     600             : 
     601           0 :     CharClass &rCC = lcl_GetCharClass();
     602           0 :     rCC.setLanguageTag( LanguageTag( nLanguage ));
     603           0 :     sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
     604           0 :     return      (nFlags & KCharacterType::UPPER)
     605           0 :             && !(nFlags & KCharacterType::LOWER);
     606             : }
     607             : 
     608    85381890 : CapType SAL_CALL capitalType(const OUString& aTerm, CharClass * pCC)
     609             : {
     610    85381890 :         sal_Int32 tlen = aTerm.getLength();
     611    85381890 :         if ((pCC) && (tlen))
     612             :         {
     613    85381890 :             OUString aStr(aTerm);
     614    85381890 :             sal_Int32 nc = 0;
     615   821649993 :             for (sal_Int32 tindex = 0; tindex < tlen; ++tindex)
     616             :             {
     617   736268103 :                 if (pCC->getCharacterType(aStr,tindex) &
     618    68389708 :                    ::com::sun::star::i18n::KCharacterType::UPPER) nc++;
     619             :             }
     620             : 
     621    85381890 :             if (nc == 0)
     622    50798510 :                 return CapType::NOCAP;
     623    34583380 :             if (nc == tlen)
     624         532 :                 return CapType::ALLCAP;
     625    34582848 :             if ((nc == 1) && (pCC->getCharacterType(aStr,0) &
     626             :                   ::com::sun::star::i18n::KCharacterType::UPPER))
     627    11844277 :                 return CapType::INITCAP;
     628             : 
     629    22738571 :             return CapType::MIXED;
     630             :         }
     631           0 :         return CapType::UNKNOWN;
     632             : }
     633             : 
     634         425 : OUString ToLower( const OUString &rText, sal_Int16 nLanguage )
     635             : {
     636         425 :     MutexGuard  aGuard( lcl_GetCharClassMutex() );
     637             : 
     638         425 :     CharClass &rCC = lcl_GetCharClass();
     639         425 :     rCC.setLanguageTag( LanguageTag( nLanguage ));
     640         425 :     return rCC.lowercase( rText );
     641             : }
     642             : 
     643             : // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
     644             : // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
     645             : static const sal_uInt32 the_aDigitZeroes [] =
     646             : {
     647             :     0x00000030, //0039    ; Decimal # Nd  [10] DIGIT ZERO..DIGIT NINE
     648             :     0x00000660, //0669    ; Decimal # Nd  [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
     649             :     0x000006F0, //06F9    ; Decimal # Nd  [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
     650             :     0x000007C0, //07C9    ; Decimal # Nd  [10] NKO DIGIT ZERO..NKO DIGIT NINE
     651             :     0x00000966, //096F    ; Decimal # Nd  [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
     652             :     0x000009E6, //09EF    ; Decimal # Nd  [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
     653             :     0x00000A66, //0A6F    ; Decimal # Nd  [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
     654             :     0x00000AE6, //0AEF    ; Decimal # Nd  [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
     655             :     0x00000B66, //0B6F    ; Decimal # Nd  [10] ODIA DIGIT ZERO..ODIA DIGIT NINE
     656             :     0x00000BE6, //0BEF    ; Decimal # Nd  [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
     657             :     0x00000C66, //0C6F    ; Decimal # Nd  [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
     658             :     0x00000CE6, //0CEF    ; Decimal # Nd  [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
     659             :     0x00000D66, //0D6F    ; Decimal # Nd  [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
     660             :     0x00000E50, //0E59    ; Decimal # Nd  [10] THAI DIGIT ZERO..THAI DIGIT NINE
     661             :     0x00000ED0, //0ED9    ; Decimal # Nd  [10] LAO DIGIT ZERO..LAO DIGIT NINE
     662             :     0x00000F20, //0F29    ; Decimal # Nd  [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
     663             :     0x00001040, //1049    ; Decimal # Nd  [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
     664             :     0x00001090, //1099    ; Decimal # Nd  [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
     665             :     0x000017E0, //17E9    ; Decimal # Nd  [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
     666             :     0x00001810, //1819    ; Decimal # Nd  [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
     667             :     0x00001946, //194F    ; Decimal # Nd  [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
     668             :     0x000019D0, //19D9    ; Decimal # Nd  [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
     669             :     0x00001B50, //1B59    ; Decimal # Nd  [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
     670             :     0x00001BB0, //1BB9    ; Decimal # Nd  [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
     671             :     0x00001C40, //1C49    ; Decimal # Nd  [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
     672             :     0x00001C50, //1C59    ; Decimal # Nd  [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
     673             :     0x0000A620, //A629    ; Decimal # Nd  [10] VAI DIGIT ZERO..VAI DIGIT NINE
     674             :     0x0000A8D0, //A8D9    ; Decimal # Nd  [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
     675             :     0x0000A900, //A909    ; Decimal # Nd  [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
     676             :     0x0000AA50, //AA59    ; Decimal # Nd  [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
     677             :     0x0000FF10, //FF19    ; Decimal # Nd  [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
     678             :     0x000104A0, //104A9   ; Decimal # Nd  [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
     679             :     0x0001D7CE  //1D7FF   ; Decimal # Nd  [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
     680             : };
     681             : 
     682    71070576 : bool HasDigits( const OUString &rText )
     683             : {
     684             :     static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
     685    71070576 :     const sal_Int32 nLen = rText.getLength();
     686             : 
     687    71070576 :     sal_Int32 i = 0;
     688   834224598 :     while (i < nLen) // for all characters ...
     689             :     {
     690   692088837 :         const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i );    // handle unicode surrogates correctly...
     691  1364855972 :         for (int j = 0; j < nNumDigitZeroes; ++j)   // ... check in all 0..9 ranges
     692             :         {
     693  1364855972 :             sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
     694  1364855972 :             if (nDigitZero > nCodePoint)
     695   692083446 :                 break;
     696   672772526 :             if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
     697        5391 :                 return true;
     698             :         }
     699             :     }
     700    71065185 :     return false;
     701             : }
     702             : 
     703           0 : bool IsNumeric( const OUString &rText )
     704             : {
     705           0 :     bool bRes = false;
     706           0 :     if (!rText.isEmpty())
     707             :     {
     708           0 :         sal_Int32 nLen = rText.getLength();
     709           0 :         bRes = true;
     710           0 :         for(sal_Int32 i = 0; i < nLen; ++i)
     711             :         {
     712           0 :             sal_Unicode cChar = rText[ i ];
     713           0 :             if ( !((sal_Unicode)'0' <= cChar  &&  cChar <= (sal_Unicode)'9') )
     714             :             {
     715           0 :                 bRes = false;
     716           0 :                 break;
     717             :             }
     718             :         }
     719             :     }
     720           0 :     return bRes;
     721             : }
     722             : 
     723         220 : uno::Reference< XLinguProperties > GetLinguProperties()
     724             : {
     725         220 :     return LinguProperties::create( comphelper::getProcessComponentContext() );
     726             : }
     727             : 
     728   194437498 : uno::Reference< XSearchableDictionaryList > GetDictionaryList()
     729             : {
     730   194437498 :     uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
     731   194437498 :     uno::Reference< XSearchableDictionaryList > xRef;
     732             :     try
     733             :     {
     734   194437498 :         xRef = DictionaryList::create(xContext);
     735             :     }
     736           0 :     catch (const uno::Exception &)
     737             :     {
     738             :         DBG_ASSERT( false, "createInstance failed" );
     739             :     }
     740             : 
     741   194437498 :     return xRef;
     742             : }
     743             : 
     744    97218693 : uno::Reference< XDictionary > GetIgnoreAllList()
     745             : {
     746    97218693 :     uno::Reference< XDictionary > xRes;
     747   194437386 :     uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
     748    97218693 :     if (xDL.is())
     749    97218693 :         xRes = xDL->getDictionaryByName( "IgnoreAllList" );
     750   194437386 :     return xRes;
     751             : }
     752             : 
     753          58 : AppExitListener::AppExitListener()
     754             : {
     755             :     // add object to Desktop EventListeners in order to properly call
     756             :     // the AtExit function at appliction exit.
     757          58 :     uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
     758             : 
     759             :     try
     760             :     {
     761          58 :         xDesktop = frame::Desktop::create(xContext);
     762             :     }
     763           0 :     catch (const uno::Exception &)
     764             :     {
     765             :         DBG_ASSERT( false, "createInstance failed" );
     766          58 :     }
     767          58 : }
     768             : 
     769          54 : AppExitListener::~AppExitListener()
     770             : {
     771          54 : }
     772             : 
     773          58 : void AppExitListener::Activate()
     774             : {
     775          58 :     if (xDesktop.is())
     776          58 :         xDesktop->addTerminateListener( this );
     777          58 : }
     778             : 
     779          54 : void AppExitListener::Deactivate()
     780             : {
     781          54 :     if (xDesktop.is())
     782           0 :         xDesktop->removeTerminateListener( this );
     783          54 : }
     784             : 
     785             : void SAL_CALL
     786          58 :     AppExitListener::disposing( const EventObject& rEvtSource )
     787             :         throw(RuntimeException, std::exception)
     788             : {
     789          58 :     MutexGuard  aGuard( GetLinguMutex() );
     790             : 
     791          58 :     if (xDesktop.is()  &&  rEvtSource.Source == xDesktop)
     792             :     {
     793          58 :         xDesktop = NULL;    //! release reference to desktop
     794          58 :     }
     795          58 : }
     796             : 
     797             : void SAL_CALL
     798          30 :     AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
     799             :         throw(frame::TerminationVetoException, RuntimeException, std::exception)
     800             : {
     801          30 : }
     802             : 
     803             : void SAL_CALL
     804          30 :     AppExitListener::notifyTermination( const EventObject& rEvtSource )
     805             :         throw(RuntimeException, std::exception)
     806             : {
     807          30 :     MutexGuard  aGuard( GetLinguMutex() );
     808             : 
     809          30 :     if (xDesktop.is()  &&  rEvtSource.Source == xDesktop)
     810             :     {
     811          30 :         AtExit();
     812          30 :     }
     813          30 : }
     814             : 
     815             : }   // namespace linguistic
     816             : 
     817             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11