merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / acmplwrd.cxx
blobc1bebf848c25500afbfdc0fa838549253e8b0617
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: acmplwrd.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <hints.hxx>
37 #include <unotools/transliterationwrapper.hxx>
38 #include <acmplwrd.hxx>
39 #include <doc.hxx>
40 #include <ndindex.hxx>
41 #include <docary.hxx>
42 #include <ndtxt.hxx>
43 #include <pam.hxx>
44 #include <pagedesc.hxx>
45 #include <poolfmt.hxx>
46 #include <calbck.hxx>
47 #include <svx/svxacorr.hxx>
49 #include <svx/acorrcfg.hxx>
50 #include <sfx2/docfile.hxx>
51 #include <docsh.hxx>
53 #include <vector>
54 /* -----------------------------05.08.2002 12:43------------------------------
56 ---------------------------------------------------------------------------*/
57 class SwAutoCompleteClient : public SwClient
59 SwAutoCompleteWord* pAutoCompleteWord;
60 SwDoc* pDoc;
61 #ifdef DBG_UTIL
62 static ULONG nSwAutoCompleteClientCount;
63 #endif
64 public:
65 SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc);
66 SwAutoCompleteClient(const SwAutoCompleteClient& rClient);
67 ~SwAutoCompleteClient();
69 SwAutoCompleteClient& operator=(const SwAutoCompleteClient& rClient);
71 virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew);
72 const SwDoc& GetDoc(){return *pDoc;}
73 #ifdef DBG_UTIL
74 static ULONG GetElementCount() {return nSwAutoCompleteClientCount;}
75 #endif
77 /* -----------------------------05.08.2002 12:48------------------------------
79 ---------------------------------------------------------------------------*/
80 typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector;
82 class SwAutoCompleteWord_Impl
84 SwAutoCompleteClientVector aClientVector;
85 SwAutoCompleteWord& rAutoCompleteWord;
86 public:
87 SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) :
88 rAutoCompleteWord(rParent){}
89 void AddDocument(SwDoc& rDoc);
90 void RemoveDocument(const SwDoc& rDoc);
93 /* -----------------------------05.08.2002 14:11------------------------------
95 ---------------------------------------------------------------------------*/
96 typedef const SwDoc* SwDocPtr;
97 typedef std::vector<SwDocPtr> SwDocPtrVector;
98 class SwAutoCompleteString : public String
100 #ifdef DBG_UTIL
101 static ULONG nSwAutoCompleteStringCount;
102 #endif
103 SwDocPtrVector aSourceDocs;
104 public:
105 SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen);
107 ~SwAutoCompleteString();
108 void AddDocument(const SwDoc& rDoc);
109 //returns true if last document reference has been removed
110 sal_Bool RemoveDocument(const SwDoc& rDoc);
111 #ifdef DBG_UTIL
112 static ULONG GetElementCount() {return nSwAutoCompleteStringCount;}
113 #endif
115 #ifdef DBG_UTIL
116 ULONG SwAutoCompleteClient::nSwAutoCompleteClientCount = 0;
117 ULONG SwAutoCompleteString::nSwAutoCompleteStringCount = 0;
118 #endif
119 /* -----------------------------06.08.2002 08:57------------------------------
121 ---------------------------------------------------------------------------*/
122 SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) :
123 pAutoCompleteWord(&rToTell),
124 pDoc(&rSwDoc)
126 pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
127 #ifdef DBG_UTIL
128 ++nSwAutoCompleteClientCount;
129 #endif
131 /* -----------------------------05.08.2002 14:07------------------------------
133 ---------------------------------------------------------------------------*/
134 SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) :
135 SwClient(),
136 pAutoCompleteWord(rClient.pAutoCompleteWord),
137 pDoc(rClient.pDoc)
139 pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
140 #ifdef DBG_UTIL
141 ++nSwAutoCompleteClientCount;
142 #endif
144 /* -----------------------------05.08.2002 14:10------------------------------
146 ---------------------------------------------------------------------------*/
147 SwAutoCompleteClient::~SwAutoCompleteClient()
149 #ifdef DBG_UTIL
150 --nSwAutoCompleteClientCount;
151 #endif
153 /* -----------------06.03.2003 15:30-----------------
155 --------------------------------------------------*/
156 SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient)
158 pAutoCompleteWord = rClient.pAutoCompleteWord;
159 pDoc = rClient.pDoc;
160 if(rClient.GetRegisteredIn())
161 rClient.pRegisteredIn->Add(this);
162 else if(GetRegisteredIn())
163 pRegisteredIn->Remove(this);
164 return *this;
166 /* -----------------------------05.08.2002 12:49------------------------------
168 ---------------------------------------------------------------------------*/
169 void SwAutoCompleteClient::Modify(SfxPoolItem *pOld, SfxPoolItem *)
171 switch( pOld ? pOld->Which() : 0 )
173 case RES_REMOVE_UNO_OBJECT:
174 case RES_OBJECTDYING:
175 if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject )
176 ((SwModify*)GetRegisteredIn())->Remove(this);
177 pAutoCompleteWord->DocumentDying(*pDoc);
178 break;
182 /* -----------------------------05.08.2002 13:03------------------------------
184 ---------------------------------------------------------------------------*/
185 void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc)
187 SwAutoCompleteClientVector::iterator aIt;
188 for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
190 if(&aIt->GetDoc() == &rDoc)
191 return;
193 aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc));
195 /* -----------------------------05.08.2002 14:33------------------------------
197 ---------------------------------------------------------------------------*/
198 void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc)
200 SwAutoCompleteClientVector::iterator aIt;
201 for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
203 if(&aIt->GetDoc() == &rDoc)
205 aClientVector.erase(aIt);
206 return;
210 /* -----------------------------06.08.2002 08:54------------------------------
212 ---------------------------------------------------------------------------*/
213 SwAutoCompleteString::SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen) :
214 String( rStr, nPos, nLen )
216 #ifdef DBG_UTIL
217 ++nSwAutoCompleteStringCount;
218 #endif
220 /* -----------------------------05.08.2002 14:22------------------------------
222 ---------------------------------------------------------------------------*/
223 SwAutoCompleteString::~SwAutoCompleteString()
225 #ifdef DBG_UTIL
226 --nSwAutoCompleteStringCount;
227 #endif
229 /* -----------------------------05.08.2002 14:17------------------------------
231 ---------------------------------------------------------------------------*/
232 void SwAutoCompleteString::AddDocument(const SwDoc& rDoc)
234 SwDocPtrVector::iterator aIt;
235 for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
237 if(*aIt == &rDoc)
238 return;
240 SwDocPtr pNew = &rDoc;
241 aSourceDocs.push_back(pNew);
243 /* -----------------------------05.08.2002 14:36------------------------------
245 ---------------------------------------------------------------------------*/
246 sal_Bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc)
248 SwDocPtrVector::iterator aIt;
249 for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
251 if(*aIt == &rDoc)
253 aSourceDocs.erase(aIt);
254 return !aSourceDocs.size();
257 return sal_False;
259 /* ---------------------------------------------------------------------------
261 ---------------------------------------------------------------------------*/
262 SwAutoCompleteWord::SwAutoCompleteWord( USHORT nWords, USHORT nMWrdLen )
263 : aWordLst( 0, 255 ), aLRULst( 0, 255 ),
264 pImpl(new SwAutoCompleteWord_Impl(*this)),
265 nMaxCount( nWords ),
266 nMinWrdLen( nMWrdLen ),
267 bLockWordLst( FALSE )
271 SwAutoCompleteWord::~SwAutoCompleteWord()
273 for(USHORT nPos = aWordLst.Count(); nPos; nPos--)
275 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
276 aWordLst.Remove( nPos - 1 );
277 delete pCurrent;
279 delete pImpl;
280 #ifdef DBG_UTIL
281 ULONG nStrings = SwAutoCompleteString::GetElementCount();
282 ULONG nClients = SwAutoCompleteClient::GetElementCount();
283 DBG_ASSERT(!nStrings && !nClients, "AutoComplete: clients or string count mismatch");
284 #endif
287 BOOL SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc )
289 SwDocShell* pDocShell = rDoc.GetDocShell();
290 SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : 0;
291 // strings from help module should not be added
292 if( pMedium )
294 const INetURLObject& rURL = pMedium->GetURLObject();
295 if ( rURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
296 return sal_False;
299 String aNewWord(rWord);
300 aNewWord.EraseAllChars( CH_TXTATR_INWORD );
301 aNewWord.EraseAllChars( CH_TXTATR_BREAKWORD );
303 pImpl->AddDocument(rDoc);
304 BOOL bRet = FALSE;
305 xub_StrLen nWrdLen = aNewWord.Len();
306 while( nWrdLen && '.' == aNewWord.GetChar( nWrdLen-1 ))
307 --nWrdLen;
309 if( !bLockWordLst && nWrdLen >= nMinWrdLen )
311 SwAutoCompleteString* pAutoString;
312 StringPtr pNew = pAutoString = new SwAutoCompleteString( aNewWord, 0, nWrdLen );
313 pAutoString->AddDocument(rDoc);
314 USHORT nInsPos;
315 if( aWordLst.Insert( pNew, nInsPos ) )
317 bRet = TRUE;
318 if( aLRULst.Count() < nMaxCount )
319 aLRULst.Insert( pNew, 0 );
320 else
322 // der letzte muss entfernt werden
323 // damit der neue vorne Platz hat
324 String* pDel = (String*)aLRULst[ nMaxCount - 1 ];
326 void** ppData = (void**)aLRULst.GetData();
327 memmove( ppData+1, ppData, (nMaxCount - 1) * sizeof( void* ));
328 *ppData = pNew;
330 aWordLst.Remove( pDel );
331 delete (SwAutoCompleteString*)pDel;
334 else
336 delete (SwAutoCompleteString*)pNew;
337 // dann aber auf jedenfall nach "oben" moven
338 pNew = aWordLst[ nInsPos ];
340 //add the document to the already inserted string
341 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)pNew;
342 pCurrent->AddDocument(rDoc);
344 nInsPos = aLRULst.GetPos( (void*)pNew );
345 ASSERT( USHRT_MAX != nInsPos, "String nicht gefunden" );
346 if( nInsPos )
348 void** ppData = (void**)aLRULst.GetData();
349 memmove( ppData+1, ppData, nInsPos * sizeof( void* ) );
350 *ppData = pNew;
354 return bRet;
357 void SwAutoCompleteWord::SetMaxCount( USHORT nNewMax )
359 if( nNewMax < nMaxCount && aLRULst.Count() > nNewMax )
361 // dann die unten ueberhaengenden entfernen
362 USHORT nLRUIndex = nNewMax-1;
363 while( nNewMax < aWordLst.Count() && nLRUIndex < aLRULst.Count())
365 USHORT nPos = aWordLst.GetPos( (String*)aLRULst[ nLRUIndex++ ] );
366 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
367 void * pDel = aWordLst[nPos];
368 aWordLst.Remove(nPos);
369 delete (SwAutoCompleteString*)pDel;
371 aLRULst.Remove( nNewMax-1, aLRULst.Count() - nNewMax );
373 nMaxCount = nNewMax;
376 void SwAutoCompleteWord::SetMinWordLen( USHORT n )
378 // will man wirklich alle Worte, die kleiner als die neue Min Laenge
379 // sind entfernen?
380 // JP 02.02.99 - erstmal nicht.
382 // JP 11.03.99 - mal testhalber eingebaut
383 if( n < nMinWrdLen )
385 for( USHORT nPos = 0; nPos < aWordLst.Count(); ++nPos )
386 if( aWordLst[ nPos ]->Len() < n )
388 void* pDel = aWordLst[ nPos ];
389 aWordLst.Remove(nPos);
391 USHORT nDelPos = aLRULst.GetPos( pDel );
392 ASSERT( USHRT_MAX != nDelPos, "String nicht gefunden" );
393 aLRULst.Remove( nDelPos );
394 --nPos;
395 delete (SwAutoCompleteString*)pDel;
399 nMinWrdLen = n;
402 BOOL SwAutoCompleteWord::GetRange( const String& rWord, USHORT& rStt,
403 USHORT& rEnd ) const
405 const StringPtr pStr = (StringPtr)&rWord;
406 aWordLst.Seek_Entry( pStr, &rStt );
407 rEnd = rStt;
409 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
410 while( rEnd < aWordLst.Count() && rSCmp.isMatch( rWord, *aWordLst[ rEnd ]))
411 ++rEnd;
413 return rStt < rEnd;
416 void SwAutoCompleteWord::CheckChangedList( const SvStringsISortDtor& rNewLst )
418 USHORT nMyLen = aWordLst.Count(), nNewLen = rNewLst.Count();
419 USHORT nMyPos = 0, nNewPos = 0;
421 for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos )
423 const StringPtr pStr = rNewLst[ nNewPos ];
424 while( aWordLst[ nMyPos ] != pStr )
426 void* pDel = aWordLst[ nMyPos ];
427 aWordLst.Remove(nMyPos);
429 USHORT nPos = aLRULst.GetPos( pDel );
430 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
431 aLRULst.Remove( nPos );
432 delete (SwAutoCompleteString*)pDel;
433 if( nMyPos >= --nMyLen )
434 break;
437 //remove the elements at the end of the array
438 if( nMyPos < nMyLen )
440 //clear LRU array first then delete the string object
441 for( ; nNewPos < nMyLen; ++nNewPos )
443 void* pDel = aWordLst[ nNewPos ];
444 USHORT nPos = aLRULst.GetPos( pDel );
445 ASSERT( USHRT_MAX != nPos, "String nicht gefunden" );
446 aLRULst.Remove( nPos );
447 delete (SwAutoCompleteString*)pDel;
449 //remove from array
450 aWordLst.Remove( nMyPos, nMyLen - nMyPos );
453 /* -----------------------------05.08.2002 12:54------------------------------
455 ---------------------------------------------------------------------------*/
456 void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc)
458 pImpl->RemoveDocument(rDoc);
460 SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect();
461 const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
462 for(USHORT nPos = aWordLst.Count(); nPos; nPos--)
464 SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
465 if(pCurrent->RemoveDocument(rDoc) && bDelete)
467 aWordLst.Remove( nPos - 1 );
468 USHORT nLRUPos = aLRULst.GetPos( (void*)pCurrent );
469 DBG_ASSERT(nLRUPos < USHRT_MAX, "word not found in LRU list" );
470 aLRULst.Remove( nLRUPos );
471 delete pCurrent;