xref: /trunk/main/sw/source/core/doc/acmplwrd.cxx (revision efeef26f)
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