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