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