LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/doc - acmplwrd.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 94 181 51.9 %
Date: 2012-12-17 Functions: 18 28 64.3 %
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 file
      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 <comphelper/string.hxx>
      21             : #include <tools/urlobj.hxx>
      22             : #include <hintids.hxx>
      23             : #include <hints.hxx>
      24             : #include <unotools/transliterationwrapper.hxx>
      25             : #include <acmplwrd.hxx>
      26             : #include <doc.hxx>
      27             : #include <ndindex.hxx>
      28             : #include <docary.hxx>
      29             : #include <ndtxt.hxx>
      30             : #include <pam.hxx>
      31             : #include <pagedesc.hxx>
      32             : #include <poolfmt.hxx>
      33             : #include <calbck.hxx>
      34             : #include <editeng/svxacorr.hxx>
      35             : 
      36             : #include <editeng/acorrcfg.hxx>
      37             : #include <sfx2/docfile.hxx>
      38             : #include <docsh.hxx>
      39             : 
      40             : #include <vector>
      41             : 
      42             : class SwAutoCompleteClient : public SwClient
      43             : {
      44             :     SwAutoCompleteWord* pAutoCompleteWord;
      45             :     SwDoc*              pDoc;
      46             : #if OSL_DEBUG_LEVEL > 0
      47             :     static sal_uLong nSwAutoCompleteClientCount;
      48             : #endif
      49             : public:
      50             :     SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc);
      51             :     SwAutoCompleteClient(const SwAutoCompleteClient& rClient);
      52             :     ~SwAutoCompleteClient();
      53             : 
      54             :     SwAutoCompleteClient& operator=(const SwAutoCompleteClient& rClient);
      55             : 
      56           3 :     const SwDoc& GetDoc(){return *pDoc;}
      57             : #if OSL_DEBUG_LEVEL > 0
      58             :     static sal_uLong GetElementCount() {return nSwAutoCompleteClientCount;}
      59             : #endif
      60             : protected:
      61             :     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
      62             : };
      63             : 
      64             : typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector;
      65             : 
      66          24 : class SwAutoCompleteWord_Impl
      67             : {
      68             :     SwAutoCompleteClientVector  aClientVector;
      69             :     SwAutoCompleteWord&         rAutoCompleteWord;
      70             : public:
      71          24 :     SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) :
      72          24 :         rAutoCompleteWord(rParent){}
      73             :     void AddDocument(SwDoc& rDoc);
      74             :     void RemoveDocument(const SwDoc& rDoc);
      75             : };
      76             : 
      77             : typedef const SwDoc* SwDocPtr;
      78             : typedef std::vector<SwDocPtr> SwDocPtrVector;
      79             : class SwAutoCompleteString
      80             :     : public editeng::IAutoCompleteString
      81             : {
      82             : #if OSL_DEBUG_LEVEL > 0
      83             :     static sal_uLong nSwAutoCompleteStringCount;
      84             : #endif
      85             :     SwDocPtrVector aSourceDocs;
      86             :     public:
      87             :         SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen);
      88             : 
      89             :         ~SwAutoCompleteString();
      90             :         void        AddDocument(const SwDoc& rDoc);
      91             :         //returns true if last document reference has been removed
      92             :         bool        RemoveDocument(const SwDoc& rDoc);
      93             : #if OSL_DEBUG_LEVEL > 0
      94             :     static sal_uLong GetElementCount() {return nSwAutoCompleteStringCount;}
      95             : #endif
      96             : };
      97             : #if OSL_DEBUG_LEVEL > 0
      98             :     sal_uLong SwAutoCompleteClient::nSwAutoCompleteClientCount = 0;
      99             :     sal_uLong SwAutoCompleteString::nSwAutoCompleteStringCount = 0;
     100             : #endif
     101             : 
     102           1 : SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) :
     103             :         pAutoCompleteWord(&rToTell),
     104           1 :         pDoc(&rSwDoc)
     105             : {
     106           1 :     pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
     107             : #if OSL_DEBUG_LEVEL > 0
     108             :     ++nSwAutoCompleteClientCount;
     109             : #endif
     110           1 : }
     111             : 
     112           1 : SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) :
     113             :     SwClient(),
     114             :     pAutoCompleteWord(rClient.pAutoCompleteWord),
     115           1 :     pDoc(rClient.pDoc)
     116             : {
     117           1 :     pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
     118             : #if OSL_DEBUG_LEVEL > 0
     119             :     ++nSwAutoCompleteClientCount;
     120             : #endif
     121           1 : }
     122             : 
     123           2 : SwAutoCompleteClient::~SwAutoCompleteClient()
     124             : {
     125             : #if OSL_DEBUG_LEVEL > 0
     126             :     --nSwAutoCompleteClientCount;
     127             : #endif
     128           2 : }
     129             : 
     130           0 : SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient)
     131             : {
     132           0 :     pAutoCompleteWord = rClient.pAutoCompleteWord;
     133           0 :     pDoc = rClient.pDoc;
     134           0 :     if(rClient.GetRegisteredIn())
     135           0 :         ((SwModify*)rClient.GetRegisteredIn())->Add(this);
     136           0 :     else if(GetRegisteredIn())
     137           0 :         GetRegisteredInNonConst()->Remove(this);
     138           0 :     return *this;
     139             : }
     140             : 
     141           1 : void SwAutoCompleteClient::Modify( const SfxPoolItem* pOld, const SfxPoolItem *)
     142             : {
     143           1 :     switch( pOld ? pOld->Which() : 0 )
     144             :     {
     145             :     case RES_REMOVE_UNO_OBJECT:
     146             :     case RES_OBJECTDYING:
     147           1 :         if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject )
     148           1 :             ((SwModify*)GetRegisteredIn())->Remove(this);
     149           1 :             pAutoCompleteWord->DocumentDying(*pDoc);
     150           1 :         break;
     151             : 
     152             :     }
     153           1 : }
     154             : 
     155           3 : void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc)
     156             : {
     157           3 :     SwAutoCompleteClientVector::iterator aIt;
     158           3 :     for(aIt = aClientVector.begin(); aIt != aClientVector.end(); ++aIt)
     159             :     {
     160           2 :         if(&aIt->GetDoc() == &rDoc)
     161           3 :             return;
     162             :     }
     163           1 :     aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc));
     164             : }
     165             : 
     166           1 : void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc)
     167             : {
     168           1 :     SwAutoCompleteClientVector::iterator aIt;
     169           1 :     for(aIt = aClientVector.begin(); aIt != aClientVector.end(); ++aIt)
     170             :     {
     171           1 :         if(&aIt->GetDoc() == &rDoc)
     172             :         {
     173           1 :             aClientVector.erase(aIt);
     174           1 :             return;
     175             :         }
     176             :     }
     177             : }
     178             : 
     179           3 : SwAutoCompleteString::SwAutoCompleteString(
     180             :             const String& rStr, xub_StrLen const nPos, xub_StrLen const nLen)
     181           3 :     : editeng::IAutoCompleteString(String(rStr, nPos, nLen))
     182             : {
     183             : #if OSL_DEBUG_LEVEL > 0
     184             :     ++nSwAutoCompleteStringCount;
     185             : #endif
     186           3 : }
     187             : 
     188           6 : SwAutoCompleteString::~SwAutoCompleteString()
     189             : {
     190             : #if OSL_DEBUG_LEVEL > 0
     191             :     --nSwAutoCompleteStringCount;
     192             : #endif
     193           6 : }
     194             : 
     195           4 : void SwAutoCompleteString::AddDocument(const SwDoc& rDoc)
     196             : {
     197           4 :     for(SwDocPtrVector::iterator aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); ++aIt)
     198             :     {
     199           1 :         if( *aIt == &rDoc )
     200           4 :             return;
     201             :     }
     202           3 :     aSourceDocs.push_back(&rDoc);
     203             : }
     204             : 
     205           2 : bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc)
     206             : {
     207           2 :     for(SwDocPtrVector::iterator aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); ++aIt)
     208             :     {
     209           2 :         if( *aIt == &rDoc )
     210             :         {
     211           2 :             aSourceDocs.erase(aIt);
     212           2 :             return aSourceDocs.empty();
     213             :         }
     214             :     }
     215           0 :     return false;
     216             : }
     217             : 
     218          24 : SwAutoCompleteWord::SwAutoCompleteWord( sal_uInt16 nWords, sal_uInt16 nMWrdLen ) :
     219          24 :     pImpl(new SwAutoCompleteWord_Impl(*this)),
     220             :     nMaxCount( nWords ),
     221             :     nMinWrdLen( nMWrdLen ),
     222          48 :     bLockWordLst( sal_False )
     223             : {
     224          24 :     m_LookupTree = new LatinLookupTree(OUString("default"));
     225          24 : }
     226             : 
     227          48 : SwAutoCompleteWord::~SwAutoCompleteWord()
     228             : {
     229          24 :     m_WordList.DeleteAndDestroyAll(); // so the assertion below works
     230          24 :     delete m_LookupTree;
     231          24 :     delete pImpl;
     232             : #if OSL_DEBUG_LEVEL > 0
     233             :     sal_uLong nStrings = SwAutoCompleteString::GetElementCount();
     234             :     sal_uLong nClients = SwAutoCompleteClient::GetElementCount();
     235             :     OSL_ENSURE(!nStrings && !nClients, "AutoComplete: clients or string count mismatch");
     236             : #endif
     237          24 : }
     238             : 
     239           3 : bool SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc )
     240             : {
     241           3 :     SwDocShell* pDocShell = rDoc.GetDocShell();
     242           3 :     SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : 0;
     243             :     // strings from help module should not be added
     244           3 :     if( pMedium )
     245             :     {
     246           3 :         const INetURLObject& rURL = pMedium->GetURLObject();
     247           3 :         if ( rURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
     248           0 :             return sal_False;
     249             :     }
     250             : 
     251           3 :     String aNewWord(rWord);
     252           3 :     aNewWord = comphelper::string::remove(aNewWord, CH_TXTATR_INWORD);
     253           3 :     aNewWord = comphelper::string::remove(aNewWord, CH_TXTATR_BREAKWORD);
     254             : 
     255           3 :     pImpl->AddDocument(rDoc);
     256           3 :     bool bRet = false;
     257           3 :     xub_StrLen nWrdLen = aNewWord.Len();
     258           6 :     while( nWrdLen && '.' == aNewWord.GetChar( nWrdLen-1 ))
     259           0 :         --nWrdLen;
     260             : 
     261           3 :     if( !bLockWordLst && nWrdLen >= nMinWrdLen )
     262             :     {
     263           3 :         SwAutoCompleteString* pNew = new SwAutoCompleteString( aNewWord, 0, nWrdLen );
     264           3 :         pNew->AddDocument(rDoc);
     265             :         std::pair<editeng::SortedAutoCompleteStrings::const_iterator, bool>
     266           3 :             aInsPair = m_WordList.insert(pNew);
     267             : 
     268           3 :         m_LookupTree->insert( OUString(aNewWord) );
     269             : 
     270           3 :         if (aInsPair.second)
     271             :         {
     272           2 :             bRet = true;
     273           2 :             if (aLRULst.size() >= nMaxCount)
     274             :             {
     275             :                 // the last one needs to be removed
     276             :                 // so that there is space for the first one
     277           0 :                 SwAutoCompleteString* pDel = aLRULst.back();
     278           0 :                 aLRULst.pop_back();
     279           0 :                 m_WordList.erase(pDel);
     280           0 :                 delete pDel;
     281             :             }
     282           2 :             aLRULst.push_front(pNew);
     283             :         }
     284             :         else
     285             :         {
     286           1 :             delete pNew;
     287             :             // then move "up"
     288           1 :             pNew = (SwAutoCompleteString*)(*aInsPair.first);
     289             : 
     290             :             // add the document to the already inserted string
     291           1 :             pNew->AddDocument(rDoc);
     292             : 
     293             :             // move pNew to the front of the LRU list
     294           1 :             SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pNew );
     295             :             OSL_ENSURE( aLRULst.end() != it, "String not found" );
     296           1 :             if ( aLRULst.begin() != it && aLRULst.end() != it )
     297             :             {
     298           0 :                 aLRULst.erase( it );
     299           0 :                 aLRULst.push_front( pNew );
     300             :             }
     301             :         }
     302             :     }
     303           3 :     return bRet;
     304             : }
     305             : 
     306           0 : void SwAutoCompleteWord::SetMaxCount( sal_uInt16 nNewMax )
     307             : {
     308           0 :     if( nNewMax < nMaxCount && aLRULst.size() > nNewMax )
     309             :     {
     310             :         // remove the trailing ones
     311           0 :         sal_uInt16 nLRUIndex = nNewMax-1;
     312           0 :         while (nNewMax < m_WordList.size() && nLRUIndex < aLRULst.size())
     313             :         {
     314             :             editeng::SortedAutoCompleteStrings::const_iterator it =
     315           0 :                 m_WordList.find(aLRULst[ nLRUIndex++ ]);
     316             :             OSL_ENSURE( m_WordList.end() != it, "String not found" );
     317           0 :             editeng::IAutoCompleteString *const pDel = *it;
     318           0 :             m_WordList.erase(it - m_WordList.begin());
     319           0 :             delete pDel;
     320             :         }
     321           0 :         aLRULst.erase( aLRULst.begin() + nNewMax - 1, aLRULst.end() );
     322             :     }
     323           0 :     nMaxCount = nNewMax;
     324           0 : }
     325             : 
     326           0 : void SwAutoCompleteWord::SetMinWordLen( sal_uInt16 n )
     327             : {
     328             :     // Do you really want to remove all words that are less than the minWrdLen?
     329           0 :     if( n < nMinWrdLen )
     330             :     {
     331           0 :         for (size_t nPos = 0; nPos < m_WordList.size(); ++nPos)
     332           0 :             if (m_WordList[ nPos ]->GetAutoCompleteString().Len() < n)
     333             :             {
     334             :                 SwAutoCompleteString *const pDel =
     335           0 :                     dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos]);
     336           0 :                 m_WordList.erase(nPos);
     337             : 
     338           0 :                 SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
     339             :                 OSL_ENSURE( aLRULst.end() != it, "String not found" );
     340           0 :                 aLRULst.erase( it );
     341           0 :                 --nPos;
     342           0 :                 delete pDel;
     343             :             }
     344             :     }
     345             : 
     346           0 :     nMinWrdLen = n;
     347           0 : }
     348             : 
     349             : // Resets the current position within the tree to its root node.
     350           0 : void SwAutoCompleteWord::returnToRoot()
     351             : {
     352           0 :     m_LookupTree->returnToRoot();
     353           0 : }
     354             : 
     355             : // Advances to a given node within the AutoComplete tree.
     356           0 : void SwAutoCompleteWord::gotoNode(OUString sNode)
     357             : {
     358           0 :     m_LookupTree->gotoNode( sNode );
     359           0 : }
     360             : 
     361             : // Advances from the current position towards the node keyed with cKey.
     362           0 : void SwAutoCompleteWord::advance(const sal_Unicode cKey)
     363             : {
     364           0 :     m_LookupTree->advance( cKey );
     365           0 : }
     366             : 
     367             : // Goes back one char within the tree, except if the current node is already the root node.
     368           0 : void SwAutoCompleteWord::goBack()
     369             : {
     370           0 :     m_LookupTree->goBack();
     371           0 : }
     372             : 
     373             : // Returns all words matching a given prefix aMatch. If bIgnoreCurrentPos is set, the current
     374             : // position within the tree is ignored and replaced by aMatch.
     375           0 : bool SwAutoCompleteWord::GetWordsMatching(String aMatch, std::vector<String>& aWords, bool bIgnoreCurrentPos) const
     376             : {
     377           0 :     OUString aStringRoot = OUString( aMatch );
     378             : 
     379             :     // The lookup tree already contains the information about the root keyword in most cases. Only if we don't trust that
     380             :     // information (e.g. if we need some autocompletion for a place other than the main writing area), the location within
     381             :     // the tree needs to be refreshed.
     382           0 :     if (bIgnoreCurrentPos)
     383             :     {
     384           0 :         m_LookupTree->gotoNode( aStringRoot );
     385             :     }
     386             : 
     387           0 :     OUString aAutocompleteWord = m_LookupTree->suggestAutoCompletion();
     388           0 :     if (aAutocompleteWord.isEmpty())
     389             :     {
     390           0 :         return false;
     391             :     }
     392             : 
     393           0 :     OUString aCompleteWord = aStringRoot + aAutocompleteWord;
     394           0 :     aWords.push_back( String(aCompleteWord) );
     395           0 :     return true;
     396             : }
     397             : 
     398           0 : void SwAutoCompleteWord::CheckChangedList(
     399             :         const editeng::SortedAutoCompleteStrings& rNewLst)
     400             : {
     401           0 :     size_t nMyLen = m_WordList.size(), nNewLen = rNewLst.size();
     402           0 :     size_t nMyPos = 0, nNewPos = 0;
     403             : 
     404           0 :     for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos )
     405             :     {
     406           0 :         const editeng::IAutoCompleteString * pStr = rNewLst[ nNewPos ];
     407           0 :         while (m_WordList[nMyPos] != pStr)
     408             :         {
     409             :             SwAutoCompleteString *const pDel =
     410           0 :                 dynamic_cast<SwAutoCompleteString*>(m_WordList[nMyPos]);
     411           0 :             m_WordList.erase(nMyPos);
     412           0 :             SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
     413             :             OSL_ENSURE( aLRULst.end() != it, "String not found" );
     414           0 :             aLRULst.erase( it );
     415           0 :             delete pDel;
     416           0 :             if( nMyPos >= --nMyLen )
     417             :                 break;
     418             :         }
     419             :     }
     420             :     // remove the elements at the end of the array
     421           0 :     if( nMyPos < nMyLen )
     422             :     {
     423             :         // clear LRU array first then delete the string object
     424           0 :         for( ; nNewPos < nMyLen; ++nNewPos )
     425             :         {
     426             :             SwAutoCompleteString *const pDel =
     427           0 :                 dynamic_cast<SwAutoCompleteString*>(m_WordList[nNewPos]);
     428           0 :             SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
     429             :             OSL_ENSURE( aLRULst.end() != it, "String not found" );
     430           0 :             aLRULst.erase( it );
     431           0 :             delete pDel;
     432             :         }
     433             :         // remove from array
     434           0 :         m_WordList.erase(m_WordList.begin() + nMyPos,
     435           0 :                          m_WordList.begin() + nMyLen);
     436             :     }
     437           0 : }
     438             : 
     439           1 : void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc)
     440             : {
     441           1 :     pImpl->RemoveDocument(rDoc);
     442             : 
     443           1 :     SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
     444           1 :     const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
     445           3 :     for (size_t nPos = m_WordList.size(); nPos; nPos--)
     446             :     {
     447             :         SwAutoCompleteString *const pCurrent =
     448           2 :             dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos - 1]);
     449           2 :         if(pCurrent->RemoveDocument(rDoc) && bDelete)
     450             :         {
     451           0 :             m_WordList.erase(nPos - 1);
     452           0 :             SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pCurrent );
     453             :             OSL_ENSURE( aLRULst.end() != it, "word not found in LRU list" );
     454           0 :             aLRULst.erase( it );
     455           0 :             delete pCurrent;
     456             :         }
     457             :     }
     458           1 : }
     459             : 
     460             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10