1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include <tools/urlobj.hxx>
29 #include <hintids.hxx>
30 #include <hints.hxx>
31 #include <unotools/transliterationwrapper.hxx>
32 #include <acmplwrd.hxx>
33 #include <doc.hxx>
34 #include <ndindex.hxx>
35 #include <docary.hxx>
36 #include <ndtxt.hxx>
37 #include <pam.hxx>
38 #include <pagedesc.hxx>
39 #include <poolfmt.hxx>
40 #include <calbck.hxx>
41 #include <editeng/svxacorr.hxx>
42
43 #include <editeng/acorrcfg.hxx>
44 #include <sfx2/docfile.hxx>
45 #include <docsh.hxx>
46
47 #include <vector>
48 /* -----------------------------05.08.2002 12:43------------------------------
49
50 ---------------------------------------------------------------------------*/
51 class SwAutoCompleteClient : public SwClient
52 {
53 SwAutoCompleteWord* pAutoCompleteWord;
54 SwDoc* pDoc;
55 #ifdef DBG_UTIL
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
GetDoc()65 const SwDoc& GetDoc(){return *pDoc;}
66 #ifdef DBG_UTIL
GetElementCount()67 static sal_uLong GetElementCount() {return nSwAutoCompleteClientCount;}
68 #endif
69 protected:
70 virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
71 };
72 /* -----------------------------05.08.2002 12:48------------------------------
73
74 ---------------------------------------------------------------------------*/
75 typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector;
76
77 class SwAutoCompleteWord_Impl
78 {
79 SwAutoCompleteClientVector aClientVector;
80 SwAutoCompleteWord& rAutoCompleteWord;
81 public:
SwAutoCompleteWord_Impl(SwAutoCompleteWord & rParent)82 SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) :
83 rAutoCompleteWord(rParent){}
84 void AddDocument(SwDoc& rDoc);
85 void RemoveDocument(const SwDoc& rDoc);
86 };
87
88 /* -----------------------------05.08.2002 14:11------------------------------
89
90 ---------------------------------------------------------------------------*/
91 typedef const SwDoc* SwDocPtr;
92 typedef std::vector<SwDocPtr> SwDocPtrVector;
93 class SwAutoCompleteString : public String
94 {
95 #ifdef DBG_UTIL
96 static sal_uLong nSwAutoCompleteStringCount;
97 #endif
98 SwDocPtrVector aSourceDocs;
99 public:
100 SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen);
101
102 ~SwAutoCompleteString();
103 void AddDocument(const SwDoc& rDoc);
104 //returns true if last document reference has been removed
105 sal_Bool RemoveDocument(const SwDoc& rDoc);
106 #ifdef DBG_UTIL
GetElementCount()107 static sal_uLong GetElementCount() {return nSwAutoCompleteStringCount;}
108 #endif
109 };
110 #ifdef DBG_UTIL
111 sal_uLong SwAutoCompleteClient::nSwAutoCompleteClientCount = 0;
112 sal_uLong SwAutoCompleteString::nSwAutoCompleteStringCount = 0;
113 #endif
114 /* -----------------------------06.08.2002 08:57------------------------------
115
116 ---------------------------------------------------------------------------*/
SwAutoCompleteClient(SwAutoCompleteWord & rToTell,SwDoc & rSwDoc)117 SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) :
118 pAutoCompleteWord(&rToTell),
119 pDoc(&rSwDoc)
120 {
121 pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
122 #ifdef DBG_UTIL
123 ++nSwAutoCompleteClientCount;
124 #endif
125 }
126 /* -----------------------------05.08.2002 14:07------------------------------
127
128 ---------------------------------------------------------------------------*/
SwAutoCompleteClient(const SwAutoCompleteClient & rClient)129 SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) :
130 SwClient(),
131 pAutoCompleteWord(rClient.pAutoCompleteWord),
132 pDoc(rClient.pDoc)
133 {
134 pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
135 #ifdef DBG_UTIL
136 ++nSwAutoCompleteClientCount;
137 #endif
138 }
139 /* -----------------------------05.08.2002 14:10------------------------------
140
141 ---------------------------------------------------------------------------*/
~SwAutoCompleteClient()142 SwAutoCompleteClient::~SwAutoCompleteClient()
143 {
144 #ifdef DBG_UTIL
145 --nSwAutoCompleteClientCount;
146 #endif
147 }
148 /* -----------------06.03.2003 15:30-----------------
149
150 --------------------------------------------------*/
operator =(const SwAutoCompleteClient & rClient)151 SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient)
152 {
153 pAutoCompleteWord = rClient.pAutoCompleteWord;
154 pDoc = rClient.pDoc;
155 if(rClient.GetRegisteredIn())
156 ((SwModify*)rClient.GetRegisteredIn())->Add(this);
157 else if(GetRegisteredIn())
158 GetRegisteredInNonConst()->Remove(this);
159 return *this;
160 }
161 /* -----------------------------05.08.2002 12:49------------------------------
162
163 ---------------------------------------------------------------------------*/
Modify(const SfxPoolItem * pOld,const SfxPoolItem *)164 void SwAutoCompleteClient::Modify( const SfxPoolItem* pOld, const SfxPoolItem *)
165 {
166 switch( pOld ? pOld->Which() : 0 )
167 {
168 case RES_REMOVE_UNO_OBJECT:
169 case RES_OBJECTDYING:
170 if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject )
171 ((SwModify*)GetRegisteredIn())->Remove(this);
172 pAutoCompleteWord->DocumentDying(*pDoc);
173 break;
174
175 }
176 }
177 /* -----------------------------05.08.2002 13:03------------------------------
178
179 ---------------------------------------------------------------------------*/
AddDocument(SwDoc & rDoc)180 void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc)
181 {
182 SwAutoCompleteClientVector::iterator aIt;
183 for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
184 {
185 if(&aIt->GetDoc() == &rDoc)
186 return;
187 }
188 aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc));
189 }
190 /* -----------------------------05.08.2002 14:33------------------------------
191
192 ---------------------------------------------------------------------------*/
RemoveDocument(const SwDoc & rDoc)193 void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc)
194 {
195 SwAutoCompleteClientVector::iterator aIt;
196 for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
197 {
198 if(&aIt->GetDoc() == &rDoc)
199 {
200 aClientVector.erase(aIt);
201 return;
202 }
203 }
204 }
205 /* -----------------------------06.08.2002 08:54------------------------------
206
207 ---------------------------------------------------------------------------*/
SwAutoCompleteString(const String & rStr,xub_StrLen nPos,xub_StrLen nLen)208 SwAutoCompleteString::SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen) :
209 String( rStr, nPos, nLen )
210 {
211 #ifdef DBG_UTIL
212 ++nSwAutoCompleteStringCount;
213 #endif
214 }
215 /* -----------------------------05.08.2002 14:22------------------------------
216
217 ---------------------------------------------------------------------------*/
~SwAutoCompleteString()218 SwAutoCompleteString::~SwAutoCompleteString()
219 {
220 #ifdef DBG_UTIL
221 --nSwAutoCompleteStringCount;
222 #endif
223 }
224 /* -----------------------------05.08.2002 14:17------------------------------
225
226 ---------------------------------------------------------------------------*/
AddDocument(const SwDoc & rDoc)227 void SwAutoCompleteString::AddDocument(const SwDoc& rDoc)
228 {
229 SwDocPtrVector::iterator aIt;
230 for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
231 {
232 if(*aIt == &rDoc)
233 return;
234 }
235 SwDocPtr pNew = &rDoc;
236 aSourceDocs.push_back(pNew);
237 }
238 /* -----------------------------05.08.2002 14:36------------------------------
239
240 ---------------------------------------------------------------------------*/
RemoveDocument(const SwDoc & rDoc)241 sal_Bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc)
242 {
243 SwDocPtrVector::iterator aIt;
244 for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
245 {
246 if(*aIt == &rDoc)
247 {
248 aSourceDocs.erase(aIt);
249 return !aSourceDocs.size();
250 }
251 }
252 return sal_False;
253 }
254 /* ---------------------------------------------------------------------------
255
256 ---------------------------------------------------------------------------*/
SwAutoCompleteWord(sal_uInt16 nWords,sal_uInt16 nMWrdLen)257 SwAutoCompleteWord::SwAutoCompleteWord( sal_uInt16 nWords, sal_uInt16 nMWrdLen )
258 : aWordLst( 0, 255 ), aLRULst( 0, 255 ),
259 pImpl(new SwAutoCompleteWord_Impl(*this)),
260 nMaxCount( nWords ),
261 nMinWrdLen( nMWrdLen ),
262 bLockWordLst( sal_False )
263 {
264 }
265
~SwAutoCompleteWord()266 SwAutoCompleteWord::~SwAutoCompleteWord()
267 {
268 for(sal_uInt16 nPos = aWordLst.Count(); nPos; nPos--)
269 {
270 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
271 aWordLst.Remove( nPos - 1 );
272 delete pCurrent;
273 }
274 delete pImpl;
275 #ifdef DBG_UTIL
276 sal_uLong nStrings = SwAutoCompleteString::GetElementCount();
277 sal_uLong nClients = SwAutoCompleteClient::GetElementCount();
278 DBG_ASSERT(!nStrings && !nClients, "AutoComplete: clients or string count mismatch");
279 #endif
280 }
281
InsertWord(const String & rWord,SwDoc & rDoc)282 sal_Bool SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc )
283 {
284 SwDocShell* pDocShell = rDoc.GetDocShell();
285 SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : 0;
286 // strings from help module should not be added
287 if( pMedium )
288 {
289 const INetURLObject& rURL = pMedium->GetURLObject();
290 if ( rURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
291 return sal_False;
292 }
293
294 String aNewWord(rWord);
295 aNewWord.EraseAllChars( CH_TXTATR_INWORD );
296 aNewWord.EraseAllChars( CH_TXTATR_BREAKWORD );
297
298 pImpl->AddDocument(rDoc);
299 sal_Bool bRet = sal_False;
300 xub_StrLen nWrdLen = aNewWord.Len();
301 while( nWrdLen && '.' == aNewWord.GetChar( nWrdLen-1 ))
302 --nWrdLen;
303
304 if( !bLockWordLst && nWrdLen >= nMinWrdLen )
305 {
306 SwAutoCompleteString* pAutoString;
307 StringPtr pNew = pAutoString = new SwAutoCompleteString( aNewWord, 0, nWrdLen );
308 pAutoString->AddDocument(rDoc);
309 sal_uInt16 nInsPos;
310 if( aWordLst.Insert( pNew, nInsPos ) )
311 {
312 bRet = sal_True;
313 if( aLRULst.Count() < nMaxCount )
314 aLRULst.Insert( pNew, 0 );
315 else
316 {
317 // der letzte muss entfernt werden
318 // damit der neue vorne Platz hat
319 String* pDel = (String*)aLRULst[ nMaxCount - 1 ];
320
321 void** ppData = (void**)aLRULst.GetData();
322 memmove( ppData+1, ppData, (nMaxCount - 1) * sizeof( void* ));
323 *ppData = pNew;
324
325 aWordLst.Remove( pDel );
326 delete (SwAutoCompleteString*)pDel;
327 }
328 }
329 else
330 {
331 delete (SwAutoCompleteString*)pNew;
332 // dann aber auf jedenfall nach "oben" moven
333 pNew = aWordLst[ nInsPos ];
334
335 //add the document to the already inserted string
336 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)pNew;
337 pCurrent->AddDocument(rDoc);
338
339 nInsPos = aLRULst.GetPos( (void*)pNew );
340 ASSERT( USHRT_MAX != nInsPos, "String nicht gefunden" );
341 if( nInsPos )
342 {
343 void** ppData = (void**)aLRULst.GetData();
344 memmove( ppData+1, ppData, nInsPos * sizeof( void* ) );
345 *ppData = pNew;
346 }
347 }
348 }
349 return bRet;
350 }
351
SetMaxCount(sal_uInt16 nNewMax)352 void SwAutoCompleteWord::SetMaxCount( sal_uInt16 nNewMax )
353 {
354 if( nNewMax < nMaxCount && aLRULst.Count() > nNewMax )
355 {
356 // dann die unten ueberhaengenden entfernen
357 sal_uInt16 nLRUIndex = nNewMax-1;
358 while( nNewMax < aWordLst.Count() && nLRUIndex < aLRULst.Count())
359 {
360 sal_uInt16 nPos = aWordLst.GetPos( (String*)aLRULst[ nLRUIndex++ ] );
361 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
362 void * pDel = aWordLst[nPos];
363 aWordLst.Remove(nPos);
364 delete (SwAutoCompleteString*)pDel;
365 }
366 aLRULst.Remove( nNewMax-1, aLRULst.Count() - nNewMax );
367 }
368 nMaxCount = nNewMax;
369 }
370
SetMinWordLen(sal_uInt16 n)371 void SwAutoCompleteWord::SetMinWordLen( sal_uInt16 n )
372 {
373 // will man wirklich alle Worte, die kleiner als die neue Min Laenge
374 // sind entfernen?
375 // JP 02.02.99 - erstmal nicht.
376
377 // JP 11.03.99 - mal testhalber eingebaut
378 if( n < nMinWrdLen )
379 {
380 for( sal_uInt16 nPos = 0; nPos < aWordLst.Count(); ++nPos )
381 if( aWordLst[ nPos ]->Len() < n )
382 {
383 void* pDel = aWordLst[ nPos ];
384 aWordLst.Remove(nPos);
385
386 sal_uInt16 nDelPos = aLRULst.GetPos( pDel );
387 ASSERT( USHRT_MAX != nDelPos, "String nicht gefunden" );
388 aLRULst.Remove( nDelPos );
389 --nPos;
390 delete (SwAutoCompleteString*)pDel;
391 }
392 }
393
394 nMinWrdLen = n;
395 }
396
GetRange(const String & rWord,sal_uInt16 & rStt,sal_uInt16 & rEnd) const397 sal_Bool SwAutoCompleteWord::GetRange( const String& rWord, sal_uInt16& rStt,
398 sal_uInt16& rEnd ) const
399 {
400 const StringPtr pStr = (StringPtr)&rWord;
401 aWordLst.Seek_Entry( pStr, &rStt );
402 rEnd = rStt;
403
404 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
405 while( rEnd < aWordLst.Count() && rSCmp.isMatch( rWord, *aWordLst[ rEnd ]))
406 ++rEnd;
407
408 return rStt < rEnd;
409 }
410
CheckChangedList(const SvStringsISortDtor & rNewLst)411 void SwAutoCompleteWord::CheckChangedList( const SvStringsISortDtor& rNewLst )
412 {
413 sal_uInt16 nMyLen = aWordLst.Count(), nNewLen = rNewLst.Count();
414 sal_uInt16 nMyPos = 0, nNewPos = 0;
415
416 for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos )
417 {
418 const StringPtr pStr = rNewLst[ nNewPos ];
419 while( aWordLst[ nMyPos ] != pStr )
420 {
421 void* pDel = aWordLst[ nMyPos ];
422 aWordLst.Remove(nMyPos);
423
424 sal_uInt16 nPos = aLRULst.GetPos( pDel );
425 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
426 aLRULst.Remove( nPos );
427 delete (SwAutoCompleteString*)pDel;
428 if( nMyPos >= --nMyLen )
429 break;
430 }
431 }
432 //remove the elements at the end of the array
433 if( nMyPos < nMyLen )
434 {
435 //clear LRU array first then delete the string object
436 for( ; nNewPos < nMyLen; ++nNewPos )
437 {
438 void* pDel = aWordLst[ nNewPos ];
439 sal_uInt16 nPos = aLRULst.GetPos( pDel );
440 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
441 aLRULst.Remove( nPos );
442 delete (SwAutoCompleteString*)pDel;
443 }
444 //remove from array
445 aWordLst.Remove( nMyPos, nMyLen - nMyPos );
446 }
447 }
448 /* -----------------------------05.08.2002 12:54------------------------------
449
450 ---------------------------------------------------------------------------*/
DocumentDying(const SwDoc & rDoc)451 void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc)
452 {
453 pImpl->RemoveDocument(rDoc);
454
455 SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect();
456 const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
457 for(sal_uInt16 nPos = aWordLst.Count(); nPos; nPos--)
458 {
459 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
460 if(pCurrent->RemoveDocument(rDoc) && bDelete)
461 {
462 aWordLst.Remove( nPos - 1 );
463 sal_uInt16 nLRUPos = aLRULst.GetPos( (void*)pCurrent );
464 DBG_ASSERT(nLRUPos < USHRT_MAX, "word not found in LRU list" );
465 aLRULst.Remove( nLRUPos );
466 delete pCurrent;
467 }
468 }
469 }
470
471