LibreOffice Module sw (master)  1
acmplwrd.cxx
Go to the documentation of this file.
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 <tools/urlobj.hxx>
21 #include <hintids.hxx>
22 #include <hints.hxx>
23 #include <acmplwrd.hxx>
24 #include <doc.hxx>
25 #include <pagedesc.hxx>
26 #include <poolfmt.hxx>
27 #include <calbck.hxx>
29 #include <editeng/svxacorr.hxx>
30 #include <osl/diagnose.h>
31 
32 #include <editeng/acorrcfg.hxx>
33 #include <sfx2/docfile.hxx>
34 #include <docsh.hxx>
35 
36 #include <cassert>
37 #include <vector>
38 
40 {
43 #if OSL_DEBUG_LEVEL > 0
45 #endif
46 public:
49  virtual ~SwAutoCompleteClient() override;
50 
52 
53  const SwDoc& GetDoc() const {return *m_pDoc;}
54 #if OSL_DEBUG_LEVEL > 0
56 #endif
57 protected:
58  virtual void SwClientNotify(const SwModify&, const SfxHint&) override;
59 };
60 
62 {
63  std::vector<SwAutoCompleteClient>
66 public:
68  m_rAutoCompleteWord(rParent){}
69  void AddDocument(SwDoc& rDoc);
70  void RemoveDocument(const SwDoc& rDoc);
71 };
72 
75 {
76 #if OSL_DEBUG_LEVEL > 0
78 #endif
79  std::vector<const SwDoc*> m_aSourceDocs;
80  public:
81  SwAutoCompleteString(const OUString& rStr, sal_Int32 nLen);
82 
83  virtual ~SwAutoCompleteString() override;
84  void AddDocument(const SwDoc& rDoc);
85  //returns true if last document reference has been removed
86  bool RemoveDocument(const SwDoc& rDoc);
87 #if OSL_DEBUG_LEVEL > 0
89 #endif
90 };
91 #if OSL_DEBUG_LEVEL > 0
94 #endif
95 
97  m_pAutoCompleteWord(&rToTell),
98  m_pDoc(&rSwDoc)
99 {
101 #if OSL_DEBUG_LEVEL > 0
103 #endif
104 }
105 
107  SwClient(),
108  m_pAutoCompleteWord(rClient.m_pAutoCompleteWord),
109  m_pDoc(rClient.m_pDoc)
110 {
112 #if OSL_DEBUG_LEVEL > 0
114 #endif
115 }
116 
118 {
119 #if OSL_DEBUG_LEVEL > 0
121 #else
122  (void) this;
123 #endif
124 }
125 
127 {
129  m_pDoc = rClient.m_pDoc;
131  return *this;
132 }
133 
135 {
136  auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
137  if(!pLegacy)
138  return;
139  switch(pLegacy->GetWhich())
140  {
142  case RES_OBJECTDYING:
143  EndListeningAll();
145  }
146 }
147 
149 {
150  if (std::any_of(m_aClientVector.begin(), m_aClientVector.end(),
151  [&rDoc](SwAutoCompleteClient& rClient) { return &rClient.GetDoc() == &rDoc; }))
152  return;
153  m_aClientVector.emplace_back(m_rAutoCompleteWord, rDoc);
154 }
155 
157 {
158  auto aIt = std::find_if(m_aClientVector.begin(), m_aClientVector.end(),
159  [&rDoc](SwAutoCompleteClient& rClient) { return &rClient.GetDoc() == &rDoc; });
160  if (aIt != m_aClientVector.end())
161  m_aClientVector.erase(aIt);
162 }
163 
165  const OUString& rStr, sal_Int32 const nLen)
166  : editeng::IAutoCompleteString(rStr.copy(0, nLen))
167 {
168 #if OSL_DEBUG_LEVEL > 0
170 #endif
171 }
172 
174 {
175 #if OSL_DEBUG_LEVEL > 0
177 #else
178  (void) this;
179 #endif
180 }
181 
183 {
184  auto aIt = std::find(m_aSourceDocs.begin(), m_aSourceDocs.end(), &rDoc);
185  if (aIt != m_aSourceDocs.end())
186  return;
187  m_aSourceDocs.push_back(&rDoc);
188 }
189 
191 {
192  auto aIt = std::find(m_aSourceDocs.begin(), m_aSourceDocs.end(), &rDoc);
193  if (aIt != m_aSourceDocs.end())
194  {
195  m_aSourceDocs.erase(aIt);
196  return m_aSourceDocs.empty();
197  }
198  return false;
199 }
200 
202  editeng::SortedAutoCompleteStrings::size_type nWords, sal_uInt16 nMWrdLen ):
203  m_pImpl(new SwAutoCompleteWord_Impl(*this)),
204  m_nMaxCount( nWords ),
205  m_nMinWordLen( nMWrdLen ),
206  m_bLockWordList( false )
207 {
208 }
209 
211 {
212  m_WordList.DeleteAndDestroyAll(); // so the assertion below works
213 #if OSL_DEBUG_LEVEL > 0
216  OSL_ENSURE(!nStrings && !nClients, "AutoComplete: clients or string count mismatch");
217 #endif
218 }
219 
220 bool SwAutoCompleteWord::InsertWord( const OUString& rWord, SwDoc& rDoc )
221 {
222  SwDocShell* pDocShell = rDoc.GetDocShell();
223  SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : nullptr;
224  // strings from help module should not be added
225  if( pMedium )
226  {
227  const INetURLObject& rURL = pMedium->GetURLObject();
228  if ( rURL.GetProtocol() == INetProtocol::VndSunStarHelp )
229  return false;
230  }
231 
232  OUString aNewWord = rWord.replaceAll(OUStringChar(CH_TXTATR_INWORD), "")
233  .replaceAll(OUStringChar(CH_TXTATR_BREAKWORD), "");
234 
235  m_pImpl->AddDocument(rDoc);
236  bool bRet = false;
237  sal_Int32 nWrdLen = aNewWord.getLength();
238  while( nWrdLen && '.' == aNewWord[ nWrdLen-1 ])
239  --nWrdLen;
240 
241  if( !m_bLockWordList && nWrdLen >= m_nMinWordLen )
242  {
243  SwAutoCompleteString* pNew = new SwAutoCompleteString( aNewWord, nWrdLen );
244  pNew->AddDocument(rDoc);
245  std::pair<editeng::SortedAutoCompleteStrings::const_iterator, bool>
246  aInsPair = m_WordList.insert(pNew);
247 
248  m_LookupTree.insert( aNewWord.copy(0, nWrdLen) );
249 
250  if (aInsPair.second)
251  {
252  bRet = true;
253  if (m_aLRUList.size() >= m_nMaxCount)
254  {
255  // the last one needs to be removed
256  // so that there is space for the first one
257  SwAutoCompleteString* pDel = m_aLRUList.back();
258  m_aLRUList.pop_back();
259  m_WordList.erase(pDel);
260  delete pDel;
261  }
262  m_aLRUList.push_front(pNew);
263  }
264  else
265  {
266  delete pNew;
267  // then move "up"
268  pNew = static_cast<SwAutoCompleteString*>(*aInsPair.first);
269 
270  // add the document to the already inserted string
271  pNew->AddDocument(rDoc);
272 
273  // move pNew to the front of the LRU list
274  SwAutoCompleteStringPtrDeque::iterator it = std::find( m_aLRUList.begin(), m_aLRUList.end(), pNew );
275  OSL_ENSURE( m_aLRUList.end() != it, "String not found" );
276  if ( m_aLRUList.begin() != it && m_aLRUList.end() != it )
277  {
278  m_aLRUList.erase( it );
279  m_aLRUList.push_front( pNew );
280  }
281  }
282  }
283  return bRet;
284 }
285 
287  editeng::SortedAutoCompleteStrings::size_type nNewMax )
288 {
289  if( nNewMax < m_nMaxCount && m_aLRUList.size() > nNewMax )
290  {
291  // remove the trailing ones
292  SwAutoCompleteStringPtrDeque::size_type nLRUIndex = nNewMax-1;
293  while (nNewMax < m_WordList.size() && nLRUIndex < m_aLRUList.size())
294  {
295  editeng::SortedAutoCompleteStrings::const_iterator it =
296  m_WordList.find(m_aLRUList[ nLRUIndex++ ]);
297  OSL_ENSURE( m_WordList.end() != it, "String not found" );
298  editeng::IAutoCompleteString *const pDel = *it;
299  m_WordList.erase(it - m_WordList.begin());
300  delete pDel;
301  }
302  m_aLRUList.erase( m_aLRUList.begin() + nNewMax - 1, m_aLRUList.end() );
303  }
304  m_nMaxCount = nNewMax;
305 }
306 
308 {
309  // Do you really want to remove all words that are less than the minWrdLen?
310  if( n < m_nMinWordLen )
311  {
312  for (size_t nPos = 0; nPos < m_WordList.size(); ++nPos)
313  if (m_WordList[ nPos ]->GetAutoCompleteString().getLength() < n)
314  {
315  SwAutoCompleteString *const pDel =
316  dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos]);
317  m_WordList.erase(nPos);
318 
319  SwAutoCompleteStringPtrDeque::iterator it = std::find( m_aLRUList.begin(), m_aLRUList.end(), pDel );
320  OSL_ENSURE( m_aLRUList.end() != it, "String not found" );
321  m_aLRUList.erase( it );
322  --nPos;
323  delete pDel;
324  }
325  }
326 
327  m_nMinWordLen = n;
328 }
329 
335 bool SwAutoCompleteWord::GetWordsMatching(const OUString& aMatch, std::vector<OUString>& rWords) const
336 {
337  assert(rWords.empty());
338  m_LookupTree.findSuggestions(aMatch, rWords);
339  return !rWords.empty();
340 }
341 
343  const editeng::SortedAutoCompleteStrings& rNewLst)
344 {
345  size_t nMyLen = m_WordList.size(), nNewLen = rNewLst.size();
346  size_t nMyPos = 0, nNewPos = 0;
347 
348  for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos )
349  {
350  const editeng::IAutoCompleteString * pStr = rNewLst[ nNewPos ];
351  while (m_WordList[nMyPos] != pStr)
352  {
353  SwAutoCompleteString *const pDel =
354  dynamic_cast<SwAutoCompleteString*>(m_WordList[nMyPos]);
355  m_WordList.erase(nMyPos);
356  SwAutoCompleteStringPtrDeque::iterator it = std::find( m_aLRUList.begin(), m_aLRUList.end(), pDel );
357  OSL_ENSURE( m_aLRUList.end() != it, "String not found" );
358  m_aLRUList.erase( it );
359  delete pDel;
360  if( nMyPos >= --nMyLen )
361  break;
362  }
363  }
364  // remove the elements at the end of the array
365  if( nMyPos >= nMyLen )
366  return;
367 
368  // clear LRU array first then delete the string object
369  for( ; nNewPos < nMyLen; ++nNewPos )
370  {
371  SwAutoCompleteString *const pDel =
372  dynamic_cast<SwAutoCompleteString*>(m_WordList[nNewPos]);
373  SwAutoCompleteStringPtrDeque::iterator it = std::find( m_aLRUList.begin(), m_aLRUList.end(), pDel );
374  OSL_ENSURE( m_aLRUList.end() != it, "String not found" );
375  m_aLRUList.erase( it );
376  delete pDel;
377  }
378  // remove from array
379  m_WordList.erase(m_WordList.begin() + nMyPos,
380  m_WordList.begin() + nMyLen);
381 }
382 
384 {
385  m_pImpl->RemoveDocument(rDoc);
386 
388  const bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
389  for (size_t nPos = m_WordList.size(); nPos; nPos--)
390  {
391  SwAutoCompleteString *const pCurrent = dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos - 1]);
392  if(pCurrent && pCurrent->RemoveDocument(rDoc) && bDelete)
393  {
394  m_WordList.erase(nPos - 1);
395  SwAutoCompleteStringPtrDeque::iterator it = std::find( m_aLRUList.begin(), m_aLRUList.end(), pCurrent );
396  OSL_ENSURE( m_aLRUList.end() != it, "word not found in LRU list" );
397  m_aLRUList.erase( it );
398  delete pCurrent;
399  }
400  }
401 }
402 
403 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool InsertWord(const OUString &rWord, SwDoc &rDoc)
Definition: acmplwrd.cxx:220
void Add(SwClient *pDepend)
Definition: calbck.cxx:199
static SvxAutoCorrCfg & Get()
void DocumentDying(const SwDoc &rDoc)
Definition: acmplwrd.cxx:383
std::unique_ptr< SwAutoCompleteWord_Impl > m_pImpl
Definition: acmplwrd.hxx:45
SwDocShell * GetDocShell()
Definition: doc.hxx:1348
SwAutoCompleteString(const OUString &rStr, sal_Int32 nLen)
Definition: acmplwrd.cxx:164
void AddDocument(const SwDoc &rDoc)
Definition: acmplwrd.cxx:182
static sal_uLong GetElementCount()
Definition: acmplwrd.cxx:88
sal_uIntPtr sal_uLong
SwAutoCompleteClient(SwAutoCompleteWord &rToTell, SwDoc &rSwDoc)
Definition: acmplwrd.cxx:96
virtual void SwClientNotify(const SwModify &, const SfxHint &) override
Definition: acmplwrd.cxx:134
Definition: doc.hxx:184
SwAutoCompleteWord * m_pAutoCompleteWord
Definition: acmplwrd.cxx:41
SwAutoCompleteWord(editeng::SortedAutoCompleteStrings::size_type nWords, sal_uInt16 nMWrdLen)
Definition: acmplwrd.cxx:201
editeng::SortedAutoCompleteStrings m_WordList
contains extended strings carrying source information
Definition: acmplwrd.hxx:41
void StartListeningToSameModifyAs(const SwClient &)
Definition: calbck.cxx:119
void findSuggestions(const OUString &sWordPart, std::vector< OUString > &rSuggestionList) const
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:169
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
void insert(const OUString &sInputString) const
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
SvxSwAutoFormatFlags & GetSwFlags()
static sal_uLong s_nSwAutoCompleteClientCount
Definition: acmplwrd.cxx:44
SwAutoCompleteWord & m_rAutoCompleteWord
Definition: acmplwrd.cxx:65
virtual SwPageDesc * GetPageDescFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return required automatic page style.
void EndListeningAll()
Definition: calbck.cxx:127
virtual ~SwAutoCompleteClient() override
Definition: acmplwrd.cxx:117
void CheckChangedList(const editeng::SortedAutoCompleteStrings &rNewLst)
Definition: acmplwrd.cxx:342
bool GetWordsMatching(const OUString &aMatch, std::vector< OUString > &aWords) const
Return all words matching a given prefix.
Definition: acmplwrd.cxx:335
SwAutoCompleteStringPtrDeque m_aLRUList
Definition: acmplwrd.hxx:43
editeng::SortedAutoCompleteStrings::size_type m_nMaxCount
Definition: acmplwrd.hxx:46
SvxAutoCorrect * GetAutoCorrect()
std::vector< SwAutoCompleteClient > m_aClientVector
Definition: acmplwrd.cxx:64
virtual ~SwAutoCompleteString() override
Definition: acmplwrd.cxx:173
SwAutoCompleteClient & operator=(const SwAutoCompleteClient &rClient)
Definition: acmplwrd.cxx:126
SwAutoCompleteWord_Impl(SwAutoCompleteWord &rParent)
Definition: acmplwrd.cxx:67
const SwDoc & GetDoc() const
Definition: acmplwrd.cxx:53
constexpr TypedWhichId< SwPtrMsgPoolItem > RES_REMOVE_UNO_OBJECT(179)
std::vector< const SwDoc * > m_aSourceDocs
Definition: acmplwrd.cxx:79
static sal_uLong s_nSwAutoCompleteStringCount
Definition: acmplwrd.cxx:77
void SetMinWordLen(sal_uInt16 n)
Definition: acmplwrd.cxx:307
sal_uInt16 m_nMinWordLen
Definition: acmplwrd.hxx:47
static sal_uLong GetElementCount()
Definition: acmplwrd.cxx:55
void RemoveDocument(const SwDoc &rDoc)
Definition: acmplwrd.cxx:156
bool RemoveDocument(const SwDoc &rDoc)
Definition: acmplwrd.cxx:190
INetProtocol GetProtocol() const
void copy(const fs::path &src, const fs::path &dest)
const INetURLObject & GetURLObject() const
void SetMaxCount(editeng::SortedAutoCompleteStrings::size_type n)
Definition: acmplwrd.cxx:286
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
Standard page.
Definition: poolfmt.hxx:170
editeng::Trie m_LookupTree
Definition: acmplwrd.hxx:42
void AddDocument(SwDoc &rDoc)
Definition: acmplwrd.cxx:148
constexpr TypedWhichId< SwPtrMsgPoolItem > RES_OBJECTDYING(RES_MSG_BEGIN)
sal_uInt16 nPos
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
SfxMedium * GetMedium() const