Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <comphelper/string.hxx>
30 : : #include <tools/urlobj.hxx>
31 : : #include <hintids.hxx>
32 : : #include <hints.hxx>
33 : : #include <unotools/transliterationwrapper.hxx>
34 : : #include <acmplwrd.hxx>
35 : : #include <doc.hxx>
36 : : #include <ndindex.hxx>
37 : : #include <docary.hxx>
38 : : #include <ndtxt.hxx>
39 : : #include <pam.hxx>
40 : : #include <pagedesc.hxx>
41 : : #include <poolfmt.hxx>
42 : : #include <calbck.hxx>
43 : : #include <editeng/svxacorr.hxx>
44 : :
45 : : #include <editeng/acorrcfg.hxx>
46 : : #include <sfx2/docfile.hxx>
47 : : #include <docsh.hxx>
48 : :
49 : : #include <vector>
50 : :
51 : : class SwAutoCompleteClient : public SwClient
52 : : {
53 : : SwAutoCompleteWord* pAutoCompleteWord;
54 : : SwDoc* pDoc;
55 : : #if OSL_DEBUG_LEVEL > 0
56 : : static sal_uLong nSwAutoCompleteClientCount;
57 : : #endif
58 : : public:
59 : : SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc);
60 : : SwAutoCompleteClient(const SwAutoCompleteClient& rClient);
61 : : ~SwAutoCompleteClient();
62 : :
63 : : SwAutoCompleteClient& operator=(const SwAutoCompleteClient& rClient);
64 : :
65 : 3470 : const SwDoc& GetDoc(){return *pDoc;}
66 : : #if OSL_DEBUG_LEVEL > 0
67 : : static sal_uLong GetElementCount() {return nSwAutoCompleteClientCount;}
68 : : #endif
69 : : protected:
70 : : virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
71 : : };
72 : :
73 : : typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector;
74 : :
75 : 73 : class SwAutoCompleteWord_Impl
76 : : {
77 : : SwAutoCompleteClientVector aClientVector;
78 : : SwAutoCompleteWord& rAutoCompleteWord;
79 : : public:
80 : 73 : SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) :
81 : 73 : rAutoCompleteWord(rParent){}
82 : : void AddDocument(SwDoc& rDoc);
83 : : void RemoveDocument(const SwDoc& rDoc);
84 : : };
85 : :
86 : : typedef const SwDoc* SwDocPtr;
87 : : typedef std::vector<SwDocPtr> SwDocPtrVector;
88 : : class SwAutoCompleteString
89 : : : public editeng::IAutoCompleteString
90 : : {
91 : : #if OSL_DEBUG_LEVEL > 0
92 : : static sal_uLong nSwAutoCompleteStringCount;
93 : : #endif
94 : : SwDocPtrVector aSourceDocs;
95 : : public:
96 : : SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen);
97 : :
98 : : ~SwAutoCompleteString();
99 : : void AddDocument(const SwDoc& rDoc);
100 : : //returns true if last document reference has been removed
101 : : bool RemoveDocument(const SwDoc& rDoc);
102 : : #if OSL_DEBUG_LEVEL > 0
103 : : static sal_uLong GetElementCount() {return nSwAutoCompleteStringCount;}
104 : : #endif
105 : : };
106 : : #if OSL_DEBUG_LEVEL > 0
107 : : sal_uLong SwAutoCompleteClient::nSwAutoCompleteClientCount = 0;
108 : : sal_uLong SwAutoCompleteString::nSwAutoCompleteStringCount = 0;
109 : : #endif
110 : :
111 : 16 : SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) :
112 : : pAutoCompleteWord(&rToTell),
113 : 16 : pDoc(&rSwDoc)
114 : : {
115 [ + - ][ + - ]: 16 : pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
116 : : #if OSL_DEBUG_LEVEL > 0
117 : : ++nSwAutoCompleteClientCount;
118 : : #endif
119 : 16 : }
120 : :
121 : 18 : SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) :
122 : : SwClient(),
123 : : pAutoCompleteWord(rClient.pAutoCompleteWord),
124 : 18 : pDoc(rClient.pDoc)
125 : : {
126 [ + - ][ + - ]: 18 : pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
127 : : #if OSL_DEBUG_LEVEL > 0
128 : : ++nSwAutoCompleteClientCount;
129 : : #endif
130 : 18 : }
131 : :
132 : 34 : SwAutoCompleteClient::~SwAutoCompleteClient()
133 : : {
134 : : #if OSL_DEBUG_LEVEL > 0
135 : : --nSwAutoCompleteClientCount;
136 : : #endif
137 [ - + ]: 34 : }
138 : :
139 : 2 : SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient)
140 : : {
141 : 2 : pAutoCompleteWord = rClient.pAutoCompleteWord;
142 : 2 : pDoc = rClient.pDoc;
143 [ + - ]: 2 : if(rClient.GetRegisteredIn())
144 : 2 : ((SwModify*)rClient.GetRegisteredIn())->Add(this);
145 [ # # ]: 0 : else if(GetRegisteredIn())
146 : 0 : GetRegisteredInNonConst()->Remove(this);
147 : 2 : return *this;
148 : : }
149 : :
150 : 16 : void SwAutoCompleteClient::Modify( const SfxPoolItem* pOld, const SfxPoolItem *)
151 : : {
152 [ + - ][ + - ]: 16 : switch( pOld ? pOld->Which() : 0 )
153 : : {
154 : : case RES_REMOVE_UNO_OBJECT:
155 : : case RES_OBJECTDYING:
156 [ + - ]: 16 : if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject )
157 : 16 : ((SwModify*)GetRegisteredIn())->Remove(this);
158 : 16 : pAutoCompleteWord->DocumentDying(*pDoc);
159 : 16 : break;
160 : :
161 : : }
162 : 16 : }
163 : :
164 : 2734 : void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc)
165 : : {
166 : 2734 : SwAutoCompleteClientVector::iterator aIt;
167 [ + - ][ + + ]: 3470 : for(aIt = aClientVector.begin(); aIt != aClientVector.end(); ++aIt)
168 : : {
169 [ + + ]: 3454 : if(&aIt->GetDoc() == &rDoc)
170 : 2734 : return;
171 : : }
172 [ + - ][ + - ]: 2734 : aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc));
[ + - ]
173 : : }
174 : :
175 : 16 : void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc)
176 : : {
177 : 16 : SwAutoCompleteClientVector::iterator aIt;
178 [ + - ][ + - ]: 16 : for(aIt = aClientVector.begin(); aIt != aClientVector.end(); ++aIt)
179 : : {
180 [ + - ]: 16 : if(&aIt->GetDoc() == &rDoc)
181 : : {
182 [ + - ]: 16 : aClientVector.erase(aIt);
183 : 16 : return;
184 : : }
185 : : }
186 : : }
187 : :
188 : 2734 : SwAutoCompleteString::SwAutoCompleteString(
189 : : const String& rStr, xub_StrLen const nPos, xub_StrLen const nLen)
190 [ + - ][ + - ]: 2734 : : editeng::IAutoCompleteString(String(rStr, nPos, nLen))
191 : : {
192 : : #if OSL_DEBUG_LEVEL > 0
193 : : ++nSwAutoCompleteStringCount;
194 : : #endif
195 : 2734 : }
196 : :
197 : 2734 : SwAutoCompleteString::~SwAutoCompleteString()
198 : : {
199 : : #if OSL_DEBUG_LEVEL > 0
200 : : --nSwAutoCompleteStringCount;
201 : : #endif
202 [ - + ]: 5468 : }
203 : :
204 : 4083 : void SwAutoCompleteString::AddDocument(const SwDoc& rDoc)
205 : : {
206 [ + - ][ + - ]: 4799 : for(SwDocPtrVector::iterator aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); ++aIt)
[ + + ]
207 : : {
208 [ + - ][ + + ]: 1337 : if( *aIt == &rDoc )
209 : 4083 : return;
210 : : }
211 [ + - ]: 4083 : aSourceDocs.push_back(&rDoc);
212 : : }
213 : :
214 : 2040 : bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc)
215 : : {
216 [ + - ][ + - ]: 2060 : for(SwDocPtrVector::iterator aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); ++aIt)
[ + + ]
217 : : {
218 [ + - ][ + + ]: 1770 : if( *aIt == &rDoc )
219 : : {
220 [ + - ]: 1750 : aSourceDocs.erase(aIt);
221 : 1750 : return aSourceDocs.empty();
222 : : }
223 : : }
224 : 2040 : return false;
225 : : }
226 : :
227 : 73 : SwAutoCompleteWord::SwAutoCompleteWord( sal_uInt16 nWords, sal_uInt16 nMWrdLen ) :
228 [ + - ]: 73 : pImpl(new SwAutoCompleteWord_Impl(*this)),
229 : : nMaxCount( nWords ),
230 : : nMinWrdLen( nMWrdLen ),
231 [ + - ][ + - ]: 73 : bLockWordLst( sal_False )
232 : : {
233 [ + - ][ + - ]: 73 : m_LookupTree = new LatinLookupTree(OUString("default"));
234 : 73 : }
235 : :
236 : 73 : SwAutoCompleteWord::~SwAutoCompleteWord()
237 : : {
238 [ + - ]: 73 : m_WordList.DeleteAndDestroyAll(); // so the assertion below works
239 [ + - ][ + - ]: 73 : delete m_LookupTree;
240 [ + - ]: 73 : delete pImpl;
241 : : #if OSL_DEBUG_LEVEL > 0
242 : : sal_uLong nStrings = SwAutoCompleteString::GetElementCount();
243 : : sal_uLong nClients = SwAutoCompleteClient::GetElementCount();
244 : : OSL_ENSURE(!nStrings && !nClients, "AutoComplete: clients or string count mismatch");
245 : : #endif
246 : 73 : }
247 : :
248 : 2734 : sal_Bool SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc )
249 : : {
250 : 2734 : SwDocShell* pDocShell = rDoc.GetDocShell();
251 [ + - ]: 2734 : SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : 0;
252 : : // strings from help module should not be added
253 [ + - ]: 2734 : if( pMedium )
254 : : {
255 [ + - ]: 2734 : const INetURLObject& rURL = pMedium->GetURLObject();
256 [ - + ]: 2734 : if ( rURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
257 : 0 : return sal_False;
258 : : }
259 : :
260 [ + - ]: 2734 : String aNewWord(rWord);
261 [ + - ][ + - ]: 2734 : aNewWord = comphelper::string::remove(aNewWord, CH_TXTATR_INWORD);
262 [ + - ][ + - ]: 2734 : aNewWord = comphelper::string::remove(aNewWord, CH_TXTATR_BREAKWORD);
263 : :
264 [ + - ]: 2734 : pImpl->AddDocument(rDoc);
265 : 2734 : sal_Bool bRet = sal_False;
266 : 2734 : xub_StrLen nWrdLen = aNewWord.Len();
267 [ + - ][ + + ]: 2738 : while( nWrdLen && '.' == aNewWord.GetChar( nWrdLen-1 ))
[ + + ]
268 : 4 : --nWrdLen;
269 : :
270 [ + - ][ + - ]: 2734 : if( !bLockWordLst && nWrdLen >= nMinWrdLen )
271 : : {
272 [ + - ][ + - ]: 2734 : SwAutoCompleteString* pNew = new SwAutoCompleteString( aNewWord, 0, nWrdLen );
273 [ + - ]: 2734 : pNew->AddDocument(rDoc);
274 : : std::pair<editeng::SortedAutoCompleteStrings::const_iterator, bool>
275 [ + - ]: 2734 : aInsPair = m_WordList.insert(pNew);
276 : :
277 [ + - ][ + - ]: 2734 : m_LookupTree->insert( OUString(aNewWord) );
278 : :
279 [ + + ]: 2734 : if (aInsPair.second)
280 : : {
281 : 1385 : bRet = sal_True;
282 [ + + ]: 1385 : if (aLRULst.size() >= nMaxCount)
283 : : {
284 : : // the last one needs to be removed
285 : : // so that there is space for the first one
286 [ + - ]: 363 : SwAutoCompleteString* pDel = aLRULst.back();
287 [ + - ]: 363 : aLRULst.pop_back();
288 [ + - ]: 363 : m_WordList.erase(pDel);
289 [ + - ][ + - ]: 363 : delete pDel;
290 : : }
291 [ + - ]: 1385 : aLRULst.push_front(pNew);
292 : : }
293 : : else
294 : : {
295 [ + - ][ + - ]: 1349 : delete pNew;
296 : : // then move "up"
297 [ + - ]: 1349 : pNew = (SwAutoCompleteString*)(*aInsPair.first);
298 : :
299 : : // add the document to the already inserted string
300 [ + - ]: 1349 : pNew->AddDocument(rDoc);
301 : :
302 : : // move pNew to the front of the LRU list
303 [ + - ]: 1349 : SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pNew );
304 : : OSL_ENSURE( aLRULst.end() != it, "String not found" );
305 [ + - ][ + + ]: 1349 : if ( aLRULst.begin() != it && aLRULst.end() != it )
[ + - ][ + - ]
[ + + ][ + - ]
[ + + # #
# # ]
306 : : {
307 [ + - ]: 1311 : aLRULst.erase( it );
308 [ + - ]: 2734 : aLRULst.push_front( pNew );
309 : : }
310 : : }
311 : : }
312 [ + - ]: 2734 : return bRet;
313 : : }
314 : :
315 : 0 : void SwAutoCompleteWord::SetMaxCount( sal_uInt16 nNewMax )
316 : : {
317 [ # # ][ # # ]: 0 : if( nNewMax < nMaxCount && aLRULst.size() > nNewMax )
[ # # ]
318 : : {
319 : : // remove the trailing ones
320 : 0 : sal_uInt16 nLRUIndex = nNewMax-1;
321 [ # # ][ # # ]: 0 : while (nNewMax < m_WordList.size() && nLRUIndex < aLRULst.size())
[ # # ]
322 : : {
323 : : editeng::SortedAutoCompleteStrings::const_iterator it =
324 [ # # ][ # # ]: 0 : m_WordList.find(aLRULst[ nLRUIndex++ ]);
325 : : OSL_ENSURE( m_WordList.end() != it, "String not found" );
326 [ # # ]: 0 : editeng::IAutoCompleteString *const pDel = *it;
327 [ # # ][ # # ]: 0 : m_WordList.erase(it - m_WordList.begin());
328 [ # # ][ # # ]: 0 : delete pDel;
329 : : }
330 [ # # ][ # # ]: 0 : aLRULst.erase( aLRULst.begin() + nNewMax - 1, aLRULst.end() );
[ # # ]
331 : : }
332 : 0 : nMaxCount = nNewMax;
333 : 0 : }
334 : :
335 : 0 : void SwAutoCompleteWord::SetMinWordLen( sal_uInt16 n )
336 : : {
337 : : // Do you really want to remove all words that are less than the minWrdLen?
338 [ # # ]: 0 : if( n < nMinWrdLen )
339 : : {
340 [ # # ]: 0 : for (size_t nPos = 0; nPos < m_WordList.size(); ++nPos)
341 [ # # ]: 0 : if (m_WordList[ nPos ]->GetAutoCompleteString().Len() < n)
342 : : {
343 : : SwAutoCompleteString *const pDel =
344 [ # # ][ # # ]: 0 : dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos]);
345 [ # # ]: 0 : m_WordList.erase(nPos);
346 : :
347 [ # # ]: 0 : SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
348 : : OSL_ENSURE( aLRULst.end() != it, "String not found" );
349 [ # # ]: 0 : aLRULst.erase( it );
350 : 0 : --nPos;
351 [ # # ][ # # ]: 0 : delete pDel;
352 : : }
353 : : }
354 : :
355 : 0 : nMinWrdLen = n;
356 : 0 : }
357 : :
358 : 0 : bool SwAutoCompleteWord::GetWordsMatching(String aMatch, std::vector<String>& aWords) const
359 : : {
360 [ # # ]: 0 : OUString aStringRoot = OUString(aMatch);
361 [ # # ]: 0 : m_LookupTree->gotoNode( aStringRoot );
362 [ # # ]: 0 : OUString aAutocompleteWord = m_LookupTree->suggestAutoCompletion();
363 [ # # ]: 0 : if (aAutocompleteWord.isEmpty())
364 : 0 : return false;
365 : :
366 : 0 : OUString aCompleteWord = aStringRoot + aAutocompleteWord;
367 : :
368 [ # # ][ # # ]: 0 : aWords.push_back( String(aCompleteWord) );
[ # # ]
369 : :
370 : 0 : return true;
371 : : }
372 : :
373 : 0 : void SwAutoCompleteWord::CheckChangedList(
374 : : const editeng::SortedAutoCompleteStrings& rNewLst)
375 : : {
376 : 0 : size_t nMyLen = m_WordList.size(), nNewLen = rNewLst.size();
377 : 0 : size_t nMyPos = 0, nNewPos = 0;
378 : :
379 [ # # ][ # # ]: 0 : for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos )
[ # # ]
380 : : {
381 : 0 : const editeng::IAutoCompleteString * pStr = rNewLst[ nNewPos ];
382 [ # # ]: 0 : while (m_WordList[nMyPos] != pStr)
383 : : {
384 : : SwAutoCompleteString *const pDel =
385 [ # # ][ # # ]: 0 : dynamic_cast<SwAutoCompleteString*>(m_WordList[nMyPos]);
386 [ # # ]: 0 : m_WordList.erase(nMyPos);
387 [ # # ]: 0 : SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
388 : : OSL_ENSURE( aLRULst.end() != it, "String not found" );
389 [ # # ]: 0 : aLRULst.erase( it );
390 [ # # ][ # # ]: 0 : delete pDel;
391 [ # # ]: 0 : if( nMyPos >= --nMyLen )
392 : : break;
393 : : }
394 : : }
395 : : // remove the elements at the end of the array
396 [ # # ]: 0 : if( nMyPos < nMyLen )
397 : : {
398 : : // clear LRU array first then delete the string object
399 [ # # ]: 0 : for( ; nNewPos < nMyLen; ++nNewPos )
400 : : {
401 : : SwAutoCompleteString *const pDel =
402 [ # # ][ # # ]: 0 : dynamic_cast<SwAutoCompleteString*>(m_WordList[nNewPos]);
403 [ # # ]: 0 : SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pDel );
404 : : OSL_ENSURE( aLRULst.end() != it, "String not found" );
405 [ # # ]: 0 : aLRULst.erase( it );
406 [ # # ][ # # ]: 0 : delete pDel;
407 : : }
408 : : // remove from array
409 : 0 : m_WordList.erase(m_WordList.begin() + nMyPos,
410 [ # # # # ]: 0 : m_WordList.begin() + nMyLen);
[ # # ]
411 : : }
412 : 0 : }
413 : :
414 : 16 : void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc)
415 : : {
416 : 16 : pImpl->RemoveDocument(rDoc);
417 : :
418 : 16 : SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
419 : 16 : const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
420 [ + + ]: 2056 : for (size_t nPos = m_WordList.size(); nPos; nPos--)
421 : : {
422 : : SwAutoCompleteString *const pCurrent =
423 [ + - ][ - + ]: 2040 : dynamic_cast<SwAutoCompleteString*>(m_WordList[nPos - 1]);
424 [ + - ][ + + ]: 2040 : if(pCurrent->RemoveDocument(rDoc) && bDelete)
[ - + ][ - + ]
425 : : {
426 [ # # ]: 0 : m_WordList.erase(nPos - 1);
427 [ # # ]: 0 : SwAutoCompleteStringPtrDeque::iterator it = std::find( aLRULst.begin(), aLRULst.end(), pCurrent );
428 : : OSL_ENSURE( aLRULst.end() != it, "word not found in LRU list" );
429 [ # # ]: 0 : aLRULst.erase( it );
430 [ # # ][ # # ]: 0 : delete pCurrent;
431 : : }
432 : : }
433 : 16 : }
434 : :
435 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|