xref: /aoo41x/main/sw/source/core/txtnode/txtedt.cxx (revision 2ca38e89)
1efeef26fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3efeef26fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4efeef26fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5efeef26fSAndrew Rist  * distributed with this work for additional information
6efeef26fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7efeef26fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8efeef26fSAndrew Rist  * "License"); you may not use this file except in compliance
9efeef26fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10efeef26fSAndrew Rist  *
11efeef26fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12efeef26fSAndrew Rist  *
13efeef26fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14efeef26fSAndrew Rist  * software distributed under the License is distributed on an
15efeef26fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16efeef26fSAndrew Rist  * KIND, either express or implied.  See the License for the
17efeef26fSAndrew Rist  * specific language governing permissions and limitations
18efeef26fSAndrew Rist  * under the License.
19efeef26fSAndrew Rist  *
20efeef26fSAndrew Rist  *************************************************************/
21efeef26fSAndrew Rist 
22efeef26fSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sw.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir // So kann man die Linguistik-Statistik ( (Tmp-Path)\swlingu.stk ) aktivieren:
28cdf0e10cSrcweir //#define LINGU_STATISTIK
29cdf0e10cSrcweir #ifdef LINGU_STATISTIK
30cdf0e10cSrcweir 	#include <stdio.h>			// in SwLinguStatistik::DTOR
31cdf0e10cSrcweir 	#include <stdlib.h> 		// getenv()
32cdf0e10cSrcweir 	#include <time.h> 			// clock()
33cdf0e10cSrcweir     #include <tools/stream.hxx>
34cdf0e10cSrcweir #endif
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include <hintids.hxx>
37cdf0e10cSrcweir #include <vcl/svapp.hxx>
38cdf0e10cSrcweir #include <svl/itemiter.hxx>
39cdf0e10cSrcweir #include <editeng/splwrap.hxx>
40cdf0e10cSrcweir #include <editeng/langitem.hxx>
41cdf0e10cSrcweir #include <editeng/fontitem.hxx>
42cdf0e10cSrcweir #include <editeng/scripttypeitem.hxx>
43cdf0e10cSrcweir #include <editeng/hangulhanja.hxx>
44cdf0e10cSrcweir #include <SwSmartTagMgr.hxx>
45cdf0e10cSrcweir #include <linguistic/lngprops.hxx>
46cdf0e10cSrcweir #include <unotools/transliterationwrapper.hxx>
47cdf0e10cSrcweir #include <unotools/charclass.hxx>
48cdf0e10cSrcweir #include <dlelstnr.hxx>
49cdf0e10cSrcweir #include <swmodule.hxx>
50cdf0e10cSrcweir #include <splargs.hxx>
51cdf0e10cSrcweir #include <viewopt.hxx>
52cdf0e10cSrcweir #include <acmplwrd.hxx>
53cdf0e10cSrcweir #include <doc.hxx>		// GetDoc()
54cdf0e10cSrcweir #include <docsh.hxx>
55cdf0e10cSrcweir #include <txtfld.hxx>
56cdf0e10cSrcweir #include <fmtfld.hxx>
57cdf0e10cSrcweir #include <txatbase.hxx>
58cdf0e10cSrcweir #include <charatr.hxx>
59cdf0e10cSrcweir #include <fldbas.hxx>
60cdf0e10cSrcweir #include <pam.hxx>
61cdf0e10cSrcweir #include <hints.hxx>
62cdf0e10cSrcweir #include <ndtxt.hxx>
63cdf0e10cSrcweir #include <txtfrm.hxx>
64cdf0e10cSrcweir #include <SwGrammarMarkUp.hxx>
65cdf0e10cSrcweir 
66cdf0e10cSrcweir #include <txttypes.hxx>
67cdf0e10cSrcweir #include <breakit.hxx>
68cdf0e10cSrcweir #include <crstate.hxx>
69cdf0e10cSrcweir #include <UndoOverwrite.hxx>
70cdf0e10cSrcweir #include <txatritr.hxx>
71cdf0e10cSrcweir #include <redline.hxx>		// SwRedline
72cdf0e10cSrcweir #include <docary.hxx>		// SwRedlineTbl
73cdf0e10cSrcweir #include <scriptinfo.hxx>
74cdf0e10cSrcweir #include <docstat.hxx>
75cdf0e10cSrcweir #include <editsh.hxx>
76cdf0e10cSrcweir #include <unotextmarkup.hxx>
77cdf0e10cSrcweir #include <txtatr.hxx>
78cdf0e10cSrcweir #include <fmtautofmt.hxx>
79cdf0e10cSrcweir #include <istyleaccess.hxx>
80cdf0e10cSrcweir 
81cdf0e10cSrcweir #include <unomid.h>
82cdf0e10cSrcweir 
83cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp>
84cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hdl>
85cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptType.hdl>
86cdf0e10cSrcweir #include <com/sun/star/i18n/TransliterationModules.hpp>
87cdf0e10cSrcweir #include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
88cdf0e10cSrcweir 
89cdf0e10cSrcweir #include <vector>
90cdf0e10cSrcweir 
91bbac9d2cSJürgen Schmidt #include <unotextrange.hxx>
92cdf0e10cSrcweir 
93cdf0e10cSrcweir using rtl::OUString;
94cdf0e10cSrcweir using namespace ::com::sun::star;
95cdf0e10cSrcweir using namespace ::com::sun::star::frame;
96cdf0e10cSrcweir using namespace ::com::sun::star::i18n;
97cdf0e10cSrcweir using namespace ::com::sun::star::beans;
98cdf0e10cSrcweir using namespace ::com::sun::star::uno;
99cdf0e10cSrcweir using namespace ::com::sun::star::linguistic2;
100cdf0e10cSrcweir using namespace ::com::sun::star::smarttags;
101cdf0e10cSrcweir 
102cdf0e10cSrcweir // Wir ersparen uns in Hyphenate ein GetFrm()
103cdf0e10cSrcweir // Achtung: in edlingu.cxx stehen die Variablen!
104cdf0e10cSrcweir extern const SwTxtNode *pLinguNode;
105cdf0e10cSrcweir extern       SwTxtFrm  *pLinguFrm;
106cdf0e10cSrcweir 
lcl_IsSkippableWhiteSpace(xub_Unicode cCh)107cdf0e10cSrcweir bool lcl_IsSkippableWhiteSpace( xub_Unicode cCh )
108cdf0e10cSrcweir {
109cdf0e10cSrcweir     return 0x3000 == cCh ||
110cdf0e10cSrcweir            ' ' == cCh ||
111cdf0e10cSrcweir            '\t' == cCh ||
112cdf0e10cSrcweir            0x0a == cCh;
113cdf0e10cSrcweir }
114cdf0e10cSrcweir 
115cdf0e10cSrcweir /*
116cdf0e10cSrcweir  * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
117cdf0e10cSrcweir  * only for deleted redlines
118cdf0e10cSrcweir  */
119cdf0e10cSrcweir 
lcl_MaskRedlines(const SwTxtNode & rNode,XubString & rText,const xub_StrLen nStt,const xub_StrLen nEnd,const xub_Unicode cChar)120cdf0e10cSrcweir sal_uInt16 lcl_MaskRedlines( const SwTxtNode& rNode, XubString& rText,
121cdf0e10cSrcweir                          const xub_StrLen nStt, const xub_StrLen nEnd,
122cdf0e10cSrcweir                          const xub_Unicode cChar )
123cdf0e10cSrcweir {
124cdf0e10cSrcweir     sal_uInt16 nNumOfMaskedRedlines = 0;
125cdf0e10cSrcweir 
126cdf0e10cSrcweir     const SwDoc& rDoc = *rNode.GetDoc();
127cdf0e10cSrcweir     sal_uInt16 nAct = rDoc.GetRedlinePos( rNode, USHRT_MAX );
128cdf0e10cSrcweir 
129cdf0e10cSrcweir     for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
130cdf0e10cSrcweir     {
131cdf0e10cSrcweir         const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
132cdf0e10cSrcweir 
133cdf0e10cSrcweir         if ( pRed->Start()->nNode > rNode.GetIndex() )
134cdf0e10cSrcweir             break;
135cdf0e10cSrcweir 
136cdf0e10cSrcweir         if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
137cdf0e10cSrcweir         {
138cdf0e10cSrcweir             xub_StrLen nRedlineEnd;
139cdf0e10cSrcweir             xub_StrLen nRedlineStart;
140cdf0e10cSrcweir 
141cdf0e10cSrcweir             pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
142cdf0e10cSrcweir 
143cdf0e10cSrcweir             if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
144cdf0e10cSrcweir                 continue;
145cdf0e10cSrcweir 
146cdf0e10cSrcweir             while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
147cdf0e10cSrcweir             {
148cdf0e10cSrcweir                 if ( nRedlineStart >= nStt && nRedlineStart < nEnd )
149cdf0e10cSrcweir                 {
150cdf0e10cSrcweir                     rText.SetChar( nRedlineStart, cChar );
151cdf0e10cSrcweir                     ++nNumOfMaskedRedlines;
152cdf0e10cSrcweir                 }
153cdf0e10cSrcweir                 ++nRedlineStart;
154cdf0e10cSrcweir             }
155cdf0e10cSrcweir         }
156cdf0e10cSrcweir     }
157cdf0e10cSrcweir 
158cdf0e10cSrcweir     return nNumOfMaskedRedlines;
159cdf0e10cSrcweir }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir /*
162cdf0e10cSrcweir  * Used for spell checking. Deleted redlines and hidden characters are masked
163cdf0e10cSrcweir  */
164cdf0e10cSrcweir 
lcl_MaskRedlinesAndHiddenText(const SwTxtNode & rNode,XubString & rText,const xub_StrLen nStt,const xub_StrLen nEnd,const xub_Unicode cChar=CH_TXTATR_INWORD,bool bCheckShowHiddenChar=true)165cdf0e10cSrcweir sal_uInt16 lcl_MaskRedlinesAndHiddenText( const SwTxtNode& rNode, XubString& rText,
166cdf0e10cSrcweir                                       const xub_StrLen nStt, const xub_StrLen nEnd,
167cdf0e10cSrcweir                                       const xub_Unicode cChar = CH_TXTATR_INWORD,
168cdf0e10cSrcweir                                       bool bCheckShowHiddenChar = true )
169cdf0e10cSrcweir {
170cdf0e10cSrcweir     sal_uInt16 nRedlinesMasked = 0;
171cdf0e10cSrcweir     sal_uInt16 nHiddenCharsMasked = 0;
172cdf0e10cSrcweir 
173cdf0e10cSrcweir     const SwDoc& rDoc = *rNode.GetDoc();
174cdf0e10cSrcweir     const bool bShowChg = 0 != IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
175cdf0e10cSrcweir 
176cdf0e10cSrcweir     // If called from word count or from spell checking, deleted redlines
177cdf0e10cSrcweir     // should be masked:
178cdf0e10cSrcweir     if ( bShowChg )
179cdf0e10cSrcweir     {
180cdf0e10cSrcweir         nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
181cdf0e10cSrcweir     }
182cdf0e10cSrcweir 
183cdf0e10cSrcweir     const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.get(IDocumentSettingAccess::HTML_MODE))->IsShowHiddenChar();
184cdf0e10cSrcweir 
185cdf0e10cSrcweir     // If called from word count, we want to mask the hidden ranges even
186cdf0e10cSrcweir     // if they are visible:
187cdf0e10cSrcweir     if ( !bCheckShowHiddenChar || bHideHidden )
188cdf0e10cSrcweir     {
189cdf0e10cSrcweir         nHiddenCharsMasked =
190cdf0e10cSrcweir             SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
191cdf0e10cSrcweir     }
192cdf0e10cSrcweir 
193cdf0e10cSrcweir     return nRedlinesMasked + nHiddenCharsMasked;
194cdf0e10cSrcweir }
195cdf0e10cSrcweir 
196cdf0e10cSrcweir /*
197cdf0e10cSrcweir  * Used for spell checking. Calculates a rectangle for repaint.
198cdf0e10cSrcweir  */
199cdf0e10cSrcweir 
lcl_CalculateRepaintRect(SwTxtFrm & rTxtFrm,xub_StrLen nChgStart,xub_StrLen nChgEnd)200cdf0e10cSrcweir static SwRect lcl_CalculateRepaintRect( SwTxtFrm& rTxtFrm, xub_StrLen nChgStart, xub_StrLen nChgEnd )
201cdf0e10cSrcweir {
202cdf0e10cSrcweir     SwRect aRect;
203cdf0e10cSrcweir 
204cdf0e10cSrcweir     SwTxtNode *pNode = rTxtFrm.GetTxtNode();
205cdf0e10cSrcweir 
206cdf0e10cSrcweir     SwNodeIndex aNdIdx( *pNode );
207cdf0e10cSrcweir     SwPosition aPos( aNdIdx, SwIndex( pNode, nChgEnd ) );
208cdf0e10cSrcweir     SwCrsrMoveState aTmpState( MV_NONE );
209cdf0e10cSrcweir     aTmpState.b2Lines = sal_True;
210cdf0e10cSrcweir     rTxtFrm.GetCharRect( aRect, aPos, &aTmpState );
211cdf0e10cSrcweir     // information about end of repaint area
212cdf0e10cSrcweir     Sw2LinesPos* pEnd2Pos = aTmpState.p2Lines;
213cdf0e10cSrcweir 
214cdf0e10cSrcweir     const SwTxtFrm *pEndFrm = &rTxtFrm;
215cdf0e10cSrcweir 
216cdf0e10cSrcweir     while( pEndFrm->HasFollow() &&
217cdf0e10cSrcweir            nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
218cdf0e10cSrcweir         pEndFrm = pEndFrm->GetFollow();
219cdf0e10cSrcweir 
220cdf0e10cSrcweir     if ( pEnd2Pos )
221cdf0e10cSrcweir     {
222cdf0e10cSrcweir         // we are inside a special portion, take left border
223cdf0e10cSrcweir         SWRECTFN( pEndFrm )
224cdf0e10cSrcweir         (aRect.*fnRect->fnSetTop)( (pEnd2Pos->aLine.*fnRect->fnGetTop)() );
225cdf0e10cSrcweir         if ( pEndFrm->IsRightToLeft() )
226cdf0e10cSrcweir             (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetLeft)() );
227cdf0e10cSrcweir         else
228cdf0e10cSrcweir             (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetRight)() );
229cdf0e10cSrcweir         (aRect.*fnRect->fnSetWidth)( 1 );
230cdf0e10cSrcweir         (aRect.*fnRect->fnSetHeight)( (pEnd2Pos->aLine.*fnRect->fnGetHeight)() );
231cdf0e10cSrcweir         delete pEnd2Pos;
232cdf0e10cSrcweir     }
233cdf0e10cSrcweir 
234cdf0e10cSrcweir     aTmpState.p2Lines = NULL;
235cdf0e10cSrcweir     SwRect aTmp;
236cdf0e10cSrcweir     aPos = SwPosition( aNdIdx, SwIndex( pNode, nChgStart ) );
237cdf0e10cSrcweir     rTxtFrm.GetCharRect( aTmp, aPos, &aTmpState );
238cdf0e10cSrcweir 
239cdf0e10cSrcweir     // i63141: GetCharRect(..) could cause a formatting,
240cdf0e10cSrcweir     // during the formatting SwTxtFrms could be joined, deleted, created...
241cdf0e10cSrcweir     // => we have to reinit pStartFrm and pEndFrm after the formatting
242cdf0e10cSrcweir     const SwTxtFrm* pStartFrm = &rTxtFrm;
243cdf0e10cSrcweir     while( pStartFrm->HasFollow() &&
244cdf0e10cSrcweir            nChgStart >= pStartFrm->GetFollow()->GetOfst() )
245cdf0e10cSrcweir         pStartFrm = pStartFrm->GetFollow();
246cdf0e10cSrcweir     pEndFrm = pStartFrm;
247cdf0e10cSrcweir     while( pEndFrm->HasFollow() &&
248cdf0e10cSrcweir            nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
249cdf0e10cSrcweir         pEndFrm = pEndFrm->GetFollow();
250cdf0e10cSrcweir 
251cdf0e10cSrcweir     // information about start of repaint area
252cdf0e10cSrcweir     Sw2LinesPos* pSt2Pos = aTmpState.p2Lines;
253cdf0e10cSrcweir     if ( pSt2Pos )
254cdf0e10cSrcweir     {
255cdf0e10cSrcweir         // we are inside a special portion, take right border
256cdf0e10cSrcweir         SWRECTFN( pStartFrm )
257cdf0e10cSrcweir         (aTmp.*fnRect->fnSetTop)( (pSt2Pos->aLine.*fnRect->fnGetTop)() );
258cdf0e10cSrcweir         if ( pStartFrm->IsRightToLeft() )
259cdf0e10cSrcweir             (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
260cdf0e10cSrcweir         else
261cdf0e10cSrcweir             (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
262cdf0e10cSrcweir         (aTmp.*fnRect->fnSetWidth)( 1 );
263cdf0e10cSrcweir         (aTmp.*fnRect->fnSetHeight)( (pSt2Pos->aLine.*fnRect->fnGetHeight)() );
264cdf0e10cSrcweir         delete pSt2Pos;
265cdf0e10cSrcweir     }
266cdf0e10cSrcweir 
267cdf0e10cSrcweir     sal_Bool bSameFrame = sal_True;
268cdf0e10cSrcweir 
269cdf0e10cSrcweir     if( rTxtFrm.HasFollow() )
270cdf0e10cSrcweir     {
271cdf0e10cSrcweir         if( pEndFrm != pStartFrm )
272cdf0e10cSrcweir         {
273cdf0e10cSrcweir             bSameFrame = sal_False;
274cdf0e10cSrcweir             SwRect aStFrm( pStartFrm->PaintArea() );
275cdf0e10cSrcweir             {
276cdf0e10cSrcweir                 SWRECTFN( pStartFrm )
277cdf0e10cSrcweir                 (aTmp.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
278cdf0e10cSrcweir                 (aTmp.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
279cdf0e10cSrcweir                 (aTmp.*fnRect->fnSetBottom)( (aStFrm.*fnRect->fnGetBottom)() );
280cdf0e10cSrcweir             }
281cdf0e10cSrcweir             aStFrm = pEndFrm->PaintArea();
282cdf0e10cSrcweir             {
283cdf0e10cSrcweir                 SWRECTFN( pEndFrm )
284cdf0e10cSrcweir                 (aRect.*fnRect->fnSetTop)( (aStFrm.*fnRect->fnGetTop)() );
285cdf0e10cSrcweir                 (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
286cdf0e10cSrcweir                 (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
287cdf0e10cSrcweir             }
288cdf0e10cSrcweir             aRect.Union( aTmp );
289cdf0e10cSrcweir             while( sal_True )
290cdf0e10cSrcweir             {
291cdf0e10cSrcweir                 pStartFrm = pStartFrm->GetFollow();
292cdf0e10cSrcweir                 if( pStartFrm == pEndFrm )
293cdf0e10cSrcweir                     break;
294cdf0e10cSrcweir                 aRect.Union( pStartFrm->PaintArea() );
295cdf0e10cSrcweir             }
296cdf0e10cSrcweir         }
297cdf0e10cSrcweir     }
298cdf0e10cSrcweir     if( bSameFrame )
299cdf0e10cSrcweir     {
300cdf0e10cSrcweir         SWRECTFN( pStartFrm )
301cdf0e10cSrcweir         if( (aTmp.*fnRect->fnGetTop)() == (aRect.*fnRect->fnGetTop)() )
302cdf0e10cSrcweir             (aRect.*fnRect->fnSetLeft)( (aTmp.*fnRect->fnGetLeft)() );
303cdf0e10cSrcweir         else
304cdf0e10cSrcweir         {
305cdf0e10cSrcweir             SwRect aStFrm( pStartFrm->PaintArea() );
306cdf0e10cSrcweir             (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
307cdf0e10cSrcweir             (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
308cdf0e10cSrcweir             (aRect.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetTop)() );
309cdf0e10cSrcweir         }
310cdf0e10cSrcweir 
311cdf0e10cSrcweir         if( aTmp.Height() > aRect.Height() )
312cdf0e10cSrcweir             aRect.Height( aTmp.Height() );
313cdf0e10cSrcweir     }
314cdf0e10cSrcweir 
315cdf0e10cSrcweir     return aRect;
316cdf0e10cSrcweir }
317cdf0e10cSrcweir 
318cdf0e10cSrcweir /*
319cdf0e10cSrcweir  * Used for automatic styles. Used during RstAttr.
320cdf0e10cSrcweir  */
321cdf0e10cSrcweir 
lcl_HaveCommonAttributes(IStyleAccess & rStyleAccess,const SfxItemSet * pSet1,sal_uInt16 nWhichId,const SfxItemSet & rSet2,boost::shared_ptr<SfxItemSet> & pStyleHandle)322cdf0e10cSrcweir static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
323cdf0e10cSrcweir                                       const SfxItemSet* pSet1,
324cdf0e10cSrcweir                                       sal_uInt16 nWhichId,
325cdf0e10cSrcweir                                       const SfxItemSet& rSet2,
326cdf0e10cSrcweir                                       boost::shared_ptr<SfxItemSet>& pStyleHandle )
327cdf0e10cSrcweir {
328cdf0e10cSrcweir     bool bRet = false;
329cdf0e10cSrcweir 
330cdf0e10cSrcweir     SfxItemSet* pNewSet = 0;
331cdf0e10cSrcweir 
332cdf0e10cSrcweir     if ( !pSet1 )
333cdf0e10cSrcweir     {
334cdf0e10cSrcweir         ASSERT( nWhichId, "lcl_HaveCommonAttributes not used correctly" )
335cdf0e10cSrcweir         if ( SFX_ITEM_SET == rSet2.GetItemState( nWhichId, sal_False ) )
336cdf0e10cSrcweir         {
337cdf0e10cSrcweir             pNewSet = rSet2.Clone( sal_True );
338cdf0e10cSrcweir             pNewSet->ClearItem( nWhichId );
339cdf0e10cSrcweir         }
340cdf0e10cSrcweir     }
341cdf0e10cSrcweir     else if ( pSet1->Count() )
342cdf0e10cSrcweir     {
343cdf0e10cSrcweir         SfxItemIter aIter( *pSet1 );
344cdf0e10cSrcweir         const SfxPoolItem* pItem = aIter.GetCurItem();
345cdf0e10cSrcweir         while( sal_True )
346cdf0e10cSrcweir         {
347cdf0e10cSrcweir             if ( SFX_ITEM_SET == rSet2.GetItemState( pItem->Which(), sal_False ) )
348cdf0e10cSrcweir             {
349cdf0e10cSrcweir                 if ( !pNewSet )
350cdf0e10cSrcweir                     pNewSet = rSet2.Clone( sal_True );
351cdf0e10cSrcweir                 pNewSet->ClearItem( pItem->Which() );
352cdf0e10cSrcweir             }
353cdf0e10cSrcweir 
354cdf0e10cSrcweir             if( aIter.IsAtEnd() )
355cdf0e10cSrcweir                 break;
356cdf0e10cSrcweir 
357cdf0e10cSrcweir             pItem = aIter.NextItem();
358cdf0e10cSrcweir         }
359cdf0e10cSrcweir     }
360cdf0e10cSrcweir 
361cdf0e10cSrcweir     if ( pNewSet )
362cdf0e10cSrcweir     {
363cdf0e10cSrcweir         if ( pNewSet->Count() )
364cdf0e10cSrcweir             pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
365cdf0e10cSrcweir         delete pNewSet;
366cdf0e10cSrcweir         bRet = true;
367cdf0e10cSrcweir     }
368cdf0e10cSrcweir 
369cdf0e10cSrcweir     return bRet;
370cdf0e10cSrcweir }
371cdf0e10cSrcweir 
InRange(xub_StrLen nIdx,xub_StrLen nStart,xub_StrLen nEnd)372cdf0e10cSrcweir inline sal_Bool InRange(xub_StrLen nIdx, xub_StrLen nStart, xub_StrLen nEnd) {
373cdf0e10cSrcweir 	return ((nIdx >=nStart) && (nIdx <= nEnd));
374cdf0e10cSrcweir }
375cdf0e10cSrcweir 
376cdf0e10cSrcweir /*
377cdf0e10cSrcweir  * void SwTxtNode::RstAttr(const SwIndex &rIdx, sal_uInt16 nLen)
378cdf0e10cSrcweir  *
379cdf0e10cSrcweir  * Deletes all attributes, starting at position rIdx, for length nLen.
380cdf0e10cSrcweir  */
381cdf0e10cSrcweir 
382cdf0e10cSrcweir /* 5 cases:
383cdf0e10cSrcweir  * 1) The attribute is completely in the deletion range:
384cdf0e10cSrcweir  *    -> delete it
385cdf0e10cSrcweir  * 2) The end of the attribute is in the deletion range:
386cdf0e10cSrcweir  *    -> delete it, then re-insert it with new end
387cdf0e10cSrcweir  * 3) The start of the attribute is in the deletion range:
388cdf0e10cSrcweir  *    -> delete it, then re-insert it with new start
389cdf0e10cSrcweir  * 4) The attribute contains the deletion range:
390cdf0e10cSrcweir  *       Split, i.e.,
391cdf0e10cSrcweir  *    -> Delete, re-insert from old start to start of deletion range
392cdf0e10cSrcweir  *    -> insert new attribute from end of deletion range to old end
393cdf0e10cSrcweir  * 5) The attribute is outside the deletion range
394cdf0e10cSrcweir  *    -> nothing to do
395cdf0e10cSrcweir  */
396cdf0e10cSrcweir 
RstTxtAttr(const SwIndex & rIdx,const xub_StrLen nLen,const sal_uInt16 nWhich,const SfxItemSet * pSet,const sal_Bool bInclRefToxMark)39769a74367SOliver-Rainer Wittmann void SwTxtNode::RstTxtAttr(
3984d322ebcSOliver-Rainer Wittmann     const SwIndex &rIdx,
3994d322ebcSOliver-Rainer Wittmann     const xub_StrLen nLen,
4004d322ebcSOliver-Rainer Wittmann     const sal_uInt16 nWhich,
4014d322ebcSOliver-Rainer Wittmann     const SfxItemSet* pSet,
4024d322ebcSOliver-Rainer Wittmann     const sal_Bool bInclRefToxMark )
403cdf0e10cSrcweir {
4044d322ebcSOliver-Rainer Wittmann     if ( !GetpSwpHints() )
4054d322ebcSOliver-Rainer Wittmann         return;
406cdf0e10cSrcweir 
40769a74367SOliver-Rainer Wittmann     xub_StrLen nStt = rIdx.GetIndex();
40869a74367SOliver-Rainer Wittmann     xub_StrLen nEnd = nStt + nLen;
40969a74367SOliver-Rainer Wittmann     {
41069a74367SOliver-Rainer Wittmann         // enlarge range for the reset of text attributes in case of an overlapping input field
41169a74367SOliver-Rainer Wittmann         const SwTxtInputFld* pTxtInputFld = dynamic_cast<const SwTxtInputFld*>(GetTxtAttrAt( nStt, RES_TXTATR_INPUTFIELD, PARENT ));
41269a74367SOliver-Rainer Wittmann         if ( pTxtInputFld == NULL )
41369a74367SOliver-Rainer Wittmann         {
41469a74367SOliver-Rainer Wittmann             pTxtInputFld = dynamic_cast<const SwTxtInputFld*>(GetTxtAttrAt(nEnd, RES_TXTATR_INPUTFIELD, PARENT ));
41569a74367SOliver-Rainer Wittmann         }
41669a74367SOliver-Rainer Wittmann         if ( pTxtInputFld != NULL )
41769a74367SOliver-Rainer Wittmann         {
41869a74367SOliver-Rainer Wittmann             if ( nStt > *(pTxtInputFld->GetStart()) )
41969a74367SOliver-Rainer Wittmann             {
42069a74367SOliver-Rainer Wittmann                 nStt = *(pTxtInputFld->GetStart());
42169a74367SOliver-Rainer Wittmann             }
42269a74367SOliver-Rainer Wittmann             if ( nEnd < *(pTxtInputFld->End()) )
42369a74367SOliver-Rainer Wittmann             {
42469a74367SOliver-Rainer Wittmann                 nEnd = *(pTxtInputFld->End());
42569a74367SOliver-Rainer Wittmann             }
42669a74367SOliver-Rainer Wittmann         }
42769a74367SOliver-Rainer Wittmann     }
428cdf0e10cSrcweir 
4294d322ebcSOliver-Rainer Wittmann     bool bChanged = false;
430cdf0e10cSrcweir 
431cdf0e10cSrcweir     // nMin and nMax initialized to maximum / minimum (inverse)
432cdf0e10cSrcweir     xub_StrLen nMin = m_Text.Len();
433cdf0e10cSrcweir     xub_StrLen nMax = nStt;
4344d322ebcSOliver-Rainer Wittmann     const bool bNoLen = nMin == 0;
435cdf0e10cSrcweir 
436cdf0e10cSrcweir     // We have to remember the "new" attributes, which have
437cdf0e10cSrcweir     // been introduced by splitting surrounding attributes (case 4).
438cdf0e10cSrcweir     // They may not be forgotten inside the "Forget" function
439cdf0e10cSrcweir     //std::vector< const SwTxtAttr* > aNewAttributes;
440cdf0e10cSrcweir 
44169a74367SOliver-Rainer Wittmann     // iterate over attribute array until start of attribute is behind deletion range
4424d322ebcSOliver-Rainer Wittmann     sal_uInt16 i = 0;
4434d322ebcSOliver-Rainer Wittmann     xub_StrLen nAttrStart;
4444d322ebcSOliver-Rainer Wittmann     SwTxtAttr *pHt = NULL;
44569a74367SOliver-Rainer Wittmann     while ( (i < m_pSwpHints->Count())
44669a74367SOliver-Rainer Wittmann             && ( ( ( nAttrStart = *(*m_pSwpHints)[i]->GetStart()) < nEnd )
44769a74367SOliver-Rainer Wittmann                  || nLen==0 ) )
448cdf0e10cSrcweir     {
449cdf0e10cSrcweir         pHt = m_pSwpHints->GetTextHint(i);
450cdf0e10cSrcweir 
451cdf0e10cSrcweir         // attributes without end stay in!
4524d322ebcSOliver-Rainer Wittmann         // but consider <bInclRefToxMark> used by Undo
4534d322ebcSOliver-Rainer Wittmann         xub_StrLen* const pAttrEnd = pHt->GetEnd();
4544d322ebcSOliver-Rainer Wittmann         const bool bKeepAttrWithoutEnd =
4554d322ebcSOliver-Rainer Wittmann             pAttrEnd == NULL
4564d322ebcSOliver-Rainer Wittmann             && ( !bInclRefToxMark
4574d322ebcSOliver-Rainer Wittmann                  || ( RES_TXTATR_REFMARK != pHt->Which()
4584d322ebcSOliver-Rainer Wittmann                       && RES_TXTATR_TOXMARK != pHt->Which()
4594d322ebcSOliver-Rainer Wittmann                       && RES_TXTATR_META != pHt->Which()
4604d322ebcSOliver-Rainer Wittmann                       && RES_TXTATR_METAFIELD != pHt->Which() ) );
4614d322ebcSOliver-Rainer Wittmann         if ( bKeepAttrWithoutEnd )
462cdf0e10cSrcweir         {
4634d322ebcSOliver-Rainer Wittmann 
4644d322ebcSOliver-Rainer Wittmann             i++;
4654d322ebcSOliver-Rainer Wittmann             continue;
4664d322ebcSOliver-Rainer Wittmann         }
46769a74367SOliver-Rainer Wittmann         // attributes with content stay in
46869a74367SOliver-Rainer Wittmann         if ( pHt->HasContent() )
46969a74367SOliver-Rainer Wittmann         {
47069a74367SOliver-Rainer Wittmann             ++i;
47169a74367SOliver-Rainer Wittmann             continue;
47269a74367SOliver-Rainer Wittmann         }
473cdf0e10cSrcweir 
474cdf0e10cSrcweir         // Default behavior is to process all attributes:
475cdf0e10cSrcweir         bool bSkipAttr = false;;
476cdf0e10cSrcweir         boost::shared_ptr<SfxItemSet> pStyleHandle;
477cdf0e10cSrcweir 
478cdf0e10cSrcweir         // 1. case: We want to reset only the attributes listed in pSet:
479cdf0e10cSrcweir         if ( pSet )
480cdf0e10cSrcweir         {
481cdf0e10cSrcweir             bSkipAttr = SFX_ITEM_SET != pSet->GetItemState( pHt->Which(), sal_False );
482cdf0e10cSrcweir             if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
483cdf0e10cSrcweir             {
484cdf0e10cSrcweir                 // if the current attribute is an autostyle, we have to check if the autostyle
485cdf0e10cSrcweir                 // and pSet have any attributes in common. If so, pStyleHandle will contain
486cdf0e10cSrcweir                 // a handle to AutoStyle / pSet:
487cdf0e10cSrcweir                 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
488cdf0e10cSrcweir             }
489cdf0e10cSrcweir         }
490cdf0e10cSrcweir         else if ( nWhich )
491cdf0e10cSrcweir         {
492cdf0e10cSrcweir             // 2. case: We want to reset only the attributes with WhichId nWhich:
493cdf0e10cSrcweir             bSkipAttr = nWhich != pHt->Which();
494cdf0e10cSrcweir             if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
495cdf0e10cSrcweir             {
496cdf0e10cSrcweir                 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), 0, nWhich, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
497cdf0e10cSrcweir             }
498cdf0e10cSrcweir         }
499cdf0e10cSrcweir         else if ( !bInclRefToxMark )
500cdf0e10cSrcweir         {
501cdf0e10cSrcweir             // 3. case: Reset all attributes except from ref/toxmarks:
502cdf0e10cSrcweir             // skip hints with CH_TXTATR here
503cdf0e10cSrcweir             // (deleting those is ONLY allowed for UNDO!)
504cdf0e10cSrcweir             bSkipAttr = RES_TXTATR_REFMARK   == pHt->Which()
505cdf0e10cSrcweir                      || RES_TXTATR_TOXMARK   == pHt->Which()
506cdf0e10cSrcweir                      || RES_TXTATR_META      == pHt->Which()
507cdf0e10cSrcweir                      || RES_TXTATR_METAFIELD == pHt->Which();
508cdf0e10cSrcweir         }
509cdf0e10cSrcweir 
510cdf0e10cSrcweir         if ( bSkipAttr )
511cdf0e10cSrcweir         {
5124d322ebcSOliver-Rainer Wittmann             i++;
5134d322ebcSOliver-Rainer Wittmann             continue;
5144d322ebcSOliver-Rainer Wittmann         }
515cdf0e10cSrcweir 
516cdf0e10cSrcweir 
517cdf0e10cSrcweir         if( nStt <= nAttrStart )          // Faelle: 1,3,5
5184d322ebcSOliver-Rainer Wittmann         {
5194d322ebcSOliver-Rainer Wittmann             const xub_StrLen nAttrEnd = pAttrEnd != NULL
5204d322ebcSOliver-Rainer Wittmann                                         ? *pAttrEnd
5214d322ebcSOliver-Rainer Wittmann                                         : nAttrStart;
5224d322ebcSOliver-Rainer Wittmann             if( nEnd > nAttrStart
5234d322ebcSOliver-Rainer Wittmann                 || ( nEnd == nAttrEnd && nEnd == nAttrStart ) )
5244d322ebcSOliver-Rainer Wittmann             {
5254d322ebcSOliver-Rainer Wittmann                 // Faelle: 1,3
5264d322ebcSOliver-Rainer Wittmann                 if ( nMin > nAttrStart )
5274d322ebcSOliver-Rainer Wittmann                     nMin = nAttrStart;
5284d322ebcSOliver-Rainer Wittmann                 if ( nMax < nAttrEnd )
5294d322ebcSOliver-Rainer Wittmann                     nMax = nAttrEnd;
5304d322ebcSOliver-Rainer Wittmann                 // Falls wir nur ein nichtaufgespanntes Attribut entfernen,
5314d322ebcSOliver-Rainer Wittmann                 // tun wir mal so, als ob sich nichts geaendert hat.
5324d322ebcSOliver-Rainer Wittmann                 bChanged = bChanged || nEnd > nAttrStart || bNoLen;
5334d322ebcSOliver-Rainer Wittmann                 if( nAttrEnd <= nEnd ) // Fall: 1
5344d322ebcSOliver-Rainer Wittmann                 {
535cdf0e10cSrcweir                     m_pSwpHints->DeleteAtPos(i);
536cdf0e10cSrcweir                     DestroyAttr( pHt );
537cdf0e10cSrcweir 
538cdf0e10cSrcweir                     if ( pStyleHandle.get() )
539cdf0e10cSrcweir                     {
540cdf0e10cSrcweir                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
541cdf0e10cSrcweir                                 *pStyleHandle, nAttrStart, nAttrEnd );
542cdf0e10cSrcweir                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
543cdf0e10cSrcweir                     }
544cdf0e10cSrcweir 
5454d322ebcSOliver-Rainer Wittmann                     // if the last attribute is a Field, the HintsArray is deleted!
546cdf0e10cSrcweir                     if ( !m_pSwpHints )
547cdf0e10cSrcweir                         break;
548cdf0e10cSrcweir 
5494d322ebcSOliver-Rainer Wittmann                     //JP 26.11.96:
5504d322ebcSOliver-Rainer Wittmann                     // beim DeleteAtPos wird ein Resort ausgefuehrt!!
5514d322ebcSOliver-Rainer Wittmann                     // darum muessen wir wieder bei 0 anfangen!!!
5524d322ebcSOliver-Rainer Wittmann                     // ueber den Fall 3 koennen Attribute nach hinten
5534d322ebcSOliver-Rainer Wittmann                     // verschoben worden sein; damit stimmt jetzt das i
5544d322ebcSOliver-Rainer Wittmann                     // nicht mehr!!!
5554d322ebcSOliver-Rainer Wittmann                     i = 0;
5564d322ebcSOliver-Rainer Wittmann 
5574d322ebcSOliver-Rainer Wittmann                     continue;
5584d322ebcSOliver-Rainer Wittmann                 }
5594d322ebcSOliver-Rainer Wittmann                 else // Fall: 3
560cdf0e10cSrcweir                 {
561cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt );
562cdf0e10cSrcweir                     *pHt->GetStart() = nEnd;
563cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt, sal_True );
564cdf0e10cSrcweir 
565cdf0e10cSrcweir                     if ( pStyleHandle.get() && nAttrStart < nEnd )
566cdf0e10cSrcweir                     {
567cdf0e10cSrcweir                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
568cdf0e10cSrcweir                                 *pStyleHandle, nAttrStart, nEnd );
569cdf0e10cSrcweir                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
570cdf0e10cSrcweir                     }
571cdf0e10cSrcweir 
5724d322ebcSOliver-Rainer Wittmann                     bChanged = true;
5734d322ebcSOliver-Rainer Wittmann                 }
5744d322ebcSOliver-Rainer Wittmann             }
5754d322ebcSOliver-Rainer Wittmann         }
5764d322ebcSOliver-Rainer Wittmann         else if ( pAttrEnd != NULL )    // Faelle: 2,4,5
5774d322ebcSOliver-Rainer Wittmann         {
578cdf0e10cSrcweir             if( *pAttrEnd > nStt )     // Faelle: 2,4
5794d322ebcSOliver-Rainer Wittmann             {
5804d322ebcSOliver-Rainer Wittmann                 if( *pAttrEnd < nEnd )  // Fall: 2
5814d322ebcSOliver-Rainer Wittmann                 {
5824d322ebcSOliver-Rainer Wittmann                     if ( nMin > nAttrStart )
5834d322ebcSOliver-Rainer Wittmann                         nMin = nAttrStart;
5844d322ebcSOliver-Rainer Wittmann                     if ( nMax < *pAttrEnd )
5854d322ebcSOliver-Rainer Wittmann                         nMax = *pAttrEnd;
5864d322ebcSOliver-Rainer Wittmann                     bChanged = true;
587cdf0e10cSrcweir 
588cdf0e10cSrcweir                     const xub_StrLen nAttrEnd = *pAttrEnd;
589cdf0e10cSrcweir 
590cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt );
591cdf0e10cSrcweir                     *pAttrEnd = nStt;
592cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt, sal_True );
593cdf0e10cSrcweir 
594cdf0e10cSrcweir                     if ( pStyleHandle.get() )
595cdf0e10cSrcweir                     {
596cdf0e10cSrcweir                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
5974d322ebcSOliver-Rainer Wittmann                             *pStyleHandle, nStt, nAttrEnd );
598cdf0e10cSrcweir                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
599cdf0e10cSrcweir                     }
6004d322ebcSOliver-Rainer Wittmann                 }
6014d322ebcSOliver-Rainer Wittmann                 else if( nLen ) // Fall: 4
6024d322ebcSOliver-Rainer Wittmann                 {
6034d322ebcSOliver-Rainer Wittmann                     // bei Lange 0 werden beide Hints vom Insert(Ht)
6044d322ebcSOliver-Rainer Wittmann                     // wieder zu einem zusammengezogen !!!!
6054d322ebcSOliver-Rainer Wittmann                     if ( nMin > nAttrStart )
6064d322ebcSOliver-Rainer Wittmann                         nMin = nAttrStart;
6074d322ebcSOliver-Rainer Wittmann                     if ( nMax < *pAttrEnd )
6084d322ebcSOliver-Rainer Wittmann                         nMax = *pAttrEnd;
6094d322ebcSOliver-Rainer Wittmann                     bChanged = true;
6104d322ebcSOliver-Rainer Wittmann                     xub_StrLen nTmpEnd = *pAttrEnd;
611cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt );
612cdf0e10cSrcweir                     *pAttrEnd = nStt;
613cdf0e10cSrcweir                     m_pSwpHints->NoteInHistory( pHt, sal_True );
614cdf0e10cSrcweir 
615cdf0e10cSrcweir                     if ( pStyleHandle.get() && nStt < nEnd )
616cdf0e10cSrcweir                     {
617cdf0e10cSrcweir                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
6184d322ebcSOliver-Rainer Wittmann                             *pStyleHandle, nStt, nEnd );
619cdf0e10cSrcweir                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
620cdf0e10cSrcweir                     }
621cdf0e10cSrcweir 
622cdf0e10cSrcweir                     if( nEnd < nTmpEnd )
623cdf0e10cSrcweir                     {
624cdf0e10cSrcweir                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
6254d322ebcSOliver-Rainer Wittmann                             pHt->GetAttr(), nEnd, nTmpEnd );
626cdf0e10cSrcweir                         if ( pNew )
627cdf0e10cSrcweir                         {
628cdf0e10cSrcweir                             SwTxtCharFmt* pCharFmt = dynamic_cast<SwTxtCharFmt*>(pHt);
629cdf0e10cSrcweir                             if ( pCharFmt )
630cdf0e10cSrcweir                                 static_cast<SwTxtCharFmt*>(pNew)->SetSortNumber( pCharFmt->GetSortNumber() );
631cdf0e10cSrcweir 
632cdf0e10cSrcweir                             InsertHint( pNew,
633cdf0e10cSrcweir                                 nsSetAttrMode::SETATTR_NOHINTADJUST );
634cdf0e10cSrcweir                         }
635cdf0e10cSrcweir 
636cdf0e10cSrcweir 
637cdf0e10cSrcweir                         // jetzt kein i+1, weil das eingefuegte Attribut
6384d322ebcSOliver-Rainer Wittmann                         // ein anderes auf die Position geschoben hat !
6394d322ebcSOliver-Rainer Wittmann                         continue;
6404d322ebcSOliver-Rainer Wittmann                     }
6414d322ebcSOliver-Rainer Wittmann                 }
6424d322ebcSOliver-Rainer Wittmann             }
6434d322ebcSOliver-Rainer Wittmann         }
644*2ca38e89SOliver-Rainer Wittmann 
645*2ca38e89SOliver-Rainer Wittmann         ++i;
6464d322ebcSOliver-Rainer Wittmann     }
647cdf0e10cSrcweir 
648cdf0e10cSrcweir     TryDeleteSwpHints();
649cdf0e10cSrcweir     if (bChanged)
650cdf0e10cSrcweir     {
651cdf0e10cSrcweir         if ( HasHints() )
652cdf0e10cSrcweir         {
653cdf0e10cSrcweir             m_pSwpHints->Resort();
654cdf0e10cSrcweir         }
65569a74367SOliver-Rainer Wittmann         //TxtFrm's reagieren auf aHint, andere auf aNew
65669a74367SOliver-Rainer Wittmann         SwUpdateAttr aHint( nMin, nMax, 0 );
65769a74367SOliver-Rainer Wittmann         NotifyClients( 0, &aHint );
65869a74367SOliver-Rainer Wittmann         SwFmtChg aNew( GetFmtColl() );
65969a74367SOliver-Rainer Wittmann         NotifyClients( 0, &aNew );
66069a74367SOliver-Rainer Wittmann     }
661cdf0e10cSrcweir }
662cdf0e10cSrcweir 
663cdf0e10cSrcweir 
664cdf0e10cSrcweir 
665cdf0e10cSrcweir /*************************************************************************
666cdf0e10cSrcweir  *				  SwTxtNode::GetCurWord()
667cdf0e10cSrcweir  *
668cdf0e10cSrcweir  * Aktuelles Wort zurueckliefern:
669cdf0e10cSrcweir  * Wir suchen immer von links nach rechts, es wird also das Wort
670cdf0e10cSrcweir  * vor nPos gesucht. Es sei denn, wir befinden uns am Anfang des
671cdf0e10cSrcweir  * Absatzes, dann wird das erste Wort zurueckgeliefert.
672cdf0e10cSrcweir  * Wenn dieses erste Wort nur aus Whitespaces besteht, returnen wir
673cdf0e10cSrcweir  * einen leeren String.
674cdf0e10cSrcweir  *************************************************************************/
675cdf0e10cSrcweir 
GetCurWord(xub_StrLen nPos) const676cdf0e10cSrcweir XubString SwTxtNode::GetCurWord( xub_StrLen nPos ) const
677cdf0e10cSrcweir {
678cdf0e10cSrcweir     ASSERT( nPos <= m_Text.Len(), "SwTxtNode::GetCurWord: invalid index." );
679cdf0e10cSrcweir 
680cdf0e10cSrcweir     if (!m_Text.Len())
681cdf0e10cSrcweir         return m_Text;
682cdf0e10cSrcweir 
683cdf0e10cSrcweir 	Boundary aBndry;
684cdf0e10cSrcweir 	const uno::Reference< XBreakIterator > &rxBreak = pBreakIt->GetBreakIter();
685cdf0e10cSrcweir     if (rxBreak.is())
686cdf0e10cSrcweir     {
687cdf0e10cSrcweir         sal_Int16 nWordType = WordType::DICTIONARY_WORD;
688cdf0e10cSrcweir         lang::Locale aLocale( pBreakIt->GetLocale( GetLang( nPos ) ) );
689cdf0e10cSrcweir #ifdef DEBUG
690cdf0e10cSrcweir         sal_Bool bBegin = rxBreak->isBeginWord( m_Text, nPos, aLocale, nWordType );
691cdf0e10cSrcweir         sal_Bool bEnd   = rxBreak->isEndWord  ( m_Text, nPos, aLocale, nWordType );
692cdf0e10cSrcweir         (void)bBegin;
693cdf0e10cSrcweir         (void)bEnd;
694cdf0e10cSrcweir #endif
695cdf0e10cSrcweir         aBndry =
696cdf0e10cSrcweir             rxBreak->getWordBoundary( m_Text, nPos, aLocale, nWordType, sal_True );
697cdf0e10cSrcweir 
698cdf0e10cSrcweir         // if no word was found use previous word (if any)
699cdf0e10cSrcweir         if (aBndry.startPos == aBndry.endPos)
700cdf0e10cSrcweir         {
701cdf0e10cSrcweir             aBndry = rxBreak->previousWord( m_Text, nPos, aLocale, nWordType );
702cdf0e10cSrcweir         }
703cdf0e10cSrcweir     }
704cdf0e10cSrcweir 
705cdf0e10cSrcweir     // check if word was found and if it uses a symbol font, if so
706cdf0e10cSrcweir     // enforce returning an empty string
707cdf0e10cSrcweir     if (aBndry.endPos != aBndry.startPos && IsSymbol( (xub_StrLen)aBndry.startPos ))
708cdf0e10cSrcweir 		aBndry.endPos = aBndry.startPos;
709cdf0e10cSrcweir 
710cdf0e10cSrcweir     return m_Text.Copy( static_cast<xub_StrLen>(aBndry.startPos),
711cdf0e10cSrcweir                        static_cast<xub_StrLen>(aBndry.endPos - aBndry.startPos) );
712cdf0e10cSrcweir }
713cdf0e10cSrcweir 
SwScanner(const SwTxtNode & rNd,const String & rTxt,const LanguageType * pLang,const ModelToViewHelper::ConversionMap * pConvMap,sal_uInt16 nType,xub_StrLen nStart,xub_StrLen nEnde,sal_Bool bClp)714cdf0e10cSrcweir SwScanner::SwScanner( const SwTxtNode& rNd, const String& rTxt, const LanguageType* pLang,
715cdf0e10cSrcweir                       const ModelToViewHelper::ConversionMap* pConvMap,
716cdf0e10cSrcweir                       sal_uInt16 nType, xub_StrLen nStart, xub_StrLen nEnde, sal_Bool bClp )
717cdf0e10cSrcweir     : rNode( rNd ), rText( rTxt), pLanguage( pLang ), pConversionMap( pConvMap ), nLen( 0 ), nWordType( nType ), bClip( bClp )
718cdf0e10cSrcweir {
719cdf0e10cSrcweir     ASSERT( rText.Len(), "SwScanner: EmptyString" );
720cdf0e10cSrcweir     nStartPos = nBegin = nStart;
721cdf0e10cSrcweir     nEndPos = nEnde;
722cdf0e10cSrcweir 
723cdf0e10cSrcweir     if ( pLanguage )
724cdf0e10cSrcweir     {
725cdf0e10cSrcweir         aCurrLang = *pLanguage;
726cdf0e10cSrcweir     }
727cdf0e10cSrcweir     else
728cdf0e10cSrcweir     {
729cdf0e10cSrcweir         ModelToViewHelper::ModelPosition aModelBeginPos = ModelToViewHelper::ConvertToModelPosition( pConversionMap, nBegin );
730cdf0e10cSrcweir         const xub_StrLen nModelBeginPos = (xub_StrLen)aModelBeginPos.mnPos;
731cdf0e10cSrcweir         aCurrLang = rNd.GetLang( nModelBeginPos );
732cdf0e10cSrcweir     }
733cdf0e10cSrcweir }
734cdf0e10cSrcweir 
NextWord()735cdf0e10cSrcweir sal_Bool SwScanner::NextWord()
736cdf0e10cSrcweir {
737cdf0e10cSrcweir     nBegin = nBegin + nLen;
738cdf0e10cSrcweir     Boundary aBound;
739cdf0e10cSrcweir 
740cdf0e10cSrcweir     CharClass& rCC = GetAppCharClass();
741cdf0e10cSrcweir     lang::Locale aOldLocale = rCC.getLocale();
742cdf0e10cSrcweir 
743cdf0e10cSrcweir 	while ( true )
744cdf0e10cSrcweir 	{
745cdf0e10cSrcweir         // skip non-letter characters:
746cdf0e10cSrcweir         while ( nBegin < rText.Len() )
747cdf0e10cSrcweir         {
748cdf0e10cSrcweir             if ( !lcl_IsSkippableWhiteSpace( rText.GetChar( nBegin ) ) )
749cdf0e10cSrcweir             {
750cdf0e10cSrcweir                 if ( !pLanguage )
751cdf0e10cSrcweir                 {
752cdf0e10cSrcweir                     const sal_uInt16 nNextScriptType = pBreakIt->GetBreakIter()->getScriptType( rText, nBegin );
753cdf0e10cSrcweir                     ModelToViewHelper::ModelPosition aModelBeginPos = ModelToViewHelper::ConvertToModelPosition( pConversionMap, nBegin );
754cdf0e10cSrcweir                     const xub_StrLen nBeginModelPos = (xub_StrLen)aModelBeginPos.mnPos;
755cdf0e10cSrcweir                     aCurrLang = rNode.GetLang( nBeginModelPos, 1, nNextScriptType );
756cdf0e10cSrcweir                 }
757cdf0e10cSrcweir 
758cdf0e10cSrcweir                 if ( nWordType != i18n::WordType::WORD_COUNT )
759cdf0e10cSrcweir                 {
760cdf0e10cSrcweir                     rCC.setLocale( pBreakIt->GetLocale( aCurrLang ) );
761cdf0e10cSrcweir                     if ( rCC.isLetterNumeric( rText.GetChar( nBegin ) ) )
762cdf0e10cSrcweir                         break;
763cdf0e10cSrcweir                 }
764cdf0e10cSrcweir                 else
765cdf0e10cSrcweir                     break;
766cdf0e10cSrcweir             }
767cdf0e10cSrcweir             ++nBegin;
768cdf0e10cSrcweir         }
769cdf0e10cSrcweir 
770cdf0e10cSrcweir 		if ( nBegin >= rText.Len() || nBegin >= nEndPos )
771cdf0e10cSrcweir 			return sal_False;
772cdf0e10cSrcweir 
773cdf0e10cSrcweir         // get the word boundaries
774cdf0e10cSrcweir         aBound = pBreakIt->GetBreakIter()->getWordBoundary( rText, nBegin,
775cdf0e10cSrcweir 				pBreakIt->GetLocale( aCurrLang ), nWordType, sal_True );
776cdf0e10cSrcweir         ASSERT( aBound.endPos >= aBound.startPos, "broken aBound result" );
777cdf0e10cSrcweir 
778cdf0e10cSrcweir         //no word boundaries could be found
779cdf0e10cSrcweir         if(aBound.endPos == aBound.startPos)
780cdf0e10cSrcweir             return sal_False;
781cdf0e10cSrcweir 
782cdf0e10cSrcweir         //if a word before is found it has to be searched for the next
783cdf0e10cSrcweir 		if(aBound.endPos == nBegin)
784cdf0e10cSrcweir             ++nBegin;
785cdf0e10cSrcweir         else
786cdf0e10cSrcweir 			break;
787cdf0e10cSrcweir     } // end while( true )
788cdf0e10cSrcweir 
789cdf0e10cSrcweir     rCC.setLocale( aOldLocale );
790cdf0e10cSrcweir 
791cdf0e10cSrcweir     // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
792cdf0e10cSrcweir     if ( nWordType == i18n::WordType::WORD_COUNT )
793cdf0e10cSrcweir     {
794cdf0e10cSrcweir         nBegin = Max( static_cast< xub_StrLen >(aBound.startPos), nBegin );
795cdf0e10cSrcweir         nLen   = 0;
796cdf0e10cSrcweir         if (static_cast< xub_StrLen >(aBound.endPos) > nBegin)
797cdf0e10cSrcweir             nLen = static_cast< xub_StrLen >(aBound.endPos) - nBegin;
798cdf0e10cSrcweir     }
799cdf0e10cSrcweir     else
800cdf0e10cSrcweir     {
801cdf0e10cSrcweir         // we have to differenciate between these cases:
802cdf0e10cSrcweir         if ( aBound.startPos <= nBegin )
803cdf0e10cSrcweir         {
804cdf0e10cSrcweir             ASSERT( aBound.endPos >= nBegin, "Unexpected aBound result" )
805cdf0e10cSrcweir 
806cdf0e10cSrcweir             // restrict boundaries to script boundaries and nEndPos
807cdf0e10cSrcweir             const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( rText, nBegin );
808cdf0e10cSrcweir             XubString aTmpWord = rText.Copy( nBegin, static_cast<xub_StrLen>(aBound.endPos - nBegin) );
809cdf0e10cSrcweir             const sal_Int32 nScriptEnd = nBegin +
810cdf0e10cSrcweir                 pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
811cdf0e10cSrcweir             const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
812cdf0e10cSrcweir 
813cdf0e10cSrcweir             // restrict word start to last script change position
814cdf0e10cSrcweir             sal_Int32 nScriptBegin = 0;
815cdf0e10cSrcweir             if ( aBound.startPos < nBegin )
816cdf0e10cSrcweir             {
817cdf0e10cSrcweir                 // search from nBegin backwards until the next script change
818cdf0e10cSrcweir                 aTmpWord = rText.Copy( static_cast<xub_StrLen>(aBound.startPos),
819cdf0e10cSrcweir                                        static_cast<xub_StrLen>(nBegin - aBound.startPos + 1) );
820cdf0e10cSrcweir                 nScriptBegin = aBound.startPos +
821cdf0e10cSrcweir                     pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, nBegin - aBound.startPos,
822cdf0e10cSrcweir                                                     nCurrScript );
823cdf0e10cSrcweir             }
824cdf0e10cSrcweir 
825cdf0e10cSrcweir             nBegin = (xub_StrLen)Max( aBound.startPos, nScriptBegin );
826cdf0e10cSrcweir 	        nLen = (xub_StrLen)(nEnd - nBegin);
827cdf0e10cSrcweir         }
828cdf0e10cSrcweir         else
829cdf0e10cSrcweir         {
830cdf0e10cSrcweir             const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( rText, aBound.startPos );
831cdf0e10cSrcweir             XubString aTmpWord = rText.Copy( static_cast<xub_StrLen>(aBound.startPos),
832cdf0e10cSrcweir                                              static_cast<xub_StrLen>(aBound.endPos - aBound.startPos) );
833cdf0e10cSrcweir             const sal_Int32 nScriptEnd = aBound.startPos +
834cdf0e10cSrcweir                 pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
835cdf0e10cSrcweir             const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
836cdf0e10cSrcweir             nBegin = (xub_StrLen)aBound.startPos;
837cdf0e10cSrcweir 	        nLen = (xub_StrLen)(nEnd - nBegin);
838cdf0e10cSrcweir         }
839cdf0e10cSrcweir     }
840cdf0e10cSrcweir 
841cdf0e10cSrcweir 	// optionally clip the result of getWordBoundaries:
842cdf0e10cSrcweir 	if ( bClip )
843cdf0e10cSrcweir 	{
844cdf0e10cSrcweir 		aBound.startPos = Max( (xub_StrLen)aBound.startPos, nStartPos );
845cdf0e10cSrcweir 		aBound.endPos = Min( (xub_StrLen)aBound.endPos, nEndPos );
846cdf0e10cSrcweir         nBegin = (xub_StrLen)aBound.startPos;
847cdf0e10cSrcweir 	    nLen = (xub_StrLen)(aBound.endPos - nBegin);
848cdf0e10cSrcweir 	}
849cdf0e10cSrcweir 
850cdf0e10cSrcweir     if( ! nLen )
851cdf0e10cSrcweir         return sal_False;
852cdf0e10cSrcweir 
853cdf0e10cSrcweir     aWord = rText.Copy( nBegin, nLen );
854cdf0e10cSrcweir 
855cdf0e10cSrcweir     return sal_True;
856cdf0e10cSrcweir }
857cdf0e10cSrcweir 
858cdf0e10cSrcweir 
Spell(SwSpellArgs * pArgs)859cdf0e10cSrcweir sal_uInt16 SwTxtNode::Spell(SwSpellArgs* pArgs)
860cdf0e10cSrcweir {
861cdf0e10cSrcweir 	// Die Aehnlichkeiten zu SwTxtFrm::_AutoSpell sind beabsichtigt ...
862cdf0e10cSrcweir 	// ACHTUNG: Ev. Bugs in beiden Routinen fixen!
863cdf0e10cSrcweir 
864cdf0e10cSrcweir 	uno::Reference<beans::XPropertySet> xProp( GetLinguPropertySet() );
865cdf0e10cSrcweir 
866cdf0e10cSrcweir 	xub_StrLen nBegin, nEnd;
867cdf0e10cSrcweir 
868cdf0e10cSrcweir     // modify string according to redline information and hidden text
869cdf0e10cSrcweir     const XubString aOldTxt( m_Text );
870cdf0e10cSrcweir     const bool bRestoreString =
871cdf0e10cSrcweir         lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
872cdf0e10cSrcweir 
873cdf0e10cSrcweir     if ( pArgs->pStartNode != this )
874cdf0e10cSrcweir 		nBegin = 0;
875cdf0e10cSrcweir 	else
876cdf0e10cSrcweir         nBegin = pArgs->pStartIdx->GetIndex();
877cdf0e10cSrcweir 
878cdf0e10cSrcweir     nEnd = ( pArgs->pEndNode != this )
879cdf0e10cSrcweir             ? m_Text.Len()
880cdf0e10cSrcweir             : pArgs->pEndIdx->GetIndex();
881cdf0e10cSrcweir 
882cdf0e10cSrcweir 	pArgs->xSpellAlt = NULL;
883cdf0e10cSrcweir 
884cdf0e10cSrcweir     // 4 cases:
885cdf0e10cSrcweir     //
886cdf0e10cSrcweir     // 1. IsWrongDirty = 0 and GetWrong = 0
887cdf0e10cSrcweir     //      Everything is checked and correct
888cdf0e10cSrcweir     // 2. IsWrongDirty = 0 and GetWrong = 1
889cdf0e10cSrcweir     //      Everything is checked and errors are identified in the wrong list
890cdf0e10cSrcweir     // 3. IsWrongDirty = 1 and GetWrong = 0
891cdf0e10cSrcweir     //      Nothing has been checked
892cdf0e10cSrcweir     // 4. IsWrongDirty = 1 and GetWrong = 1
893cdf0e10cSrcweir     //      Text has been checked but there is an invalid range in the wrong list
894cdf0e10cSrcweir     //
895cdf0e10cSrcweir     // Nothing has to be done for case 1.
896cdf0e10cSrcweir     if ( ( IsWrongDirty() || GetWrong() ) && m_Text.Len() )
897cdf0e10cSrcweir     {
898cdf0e10cSrcweir         if ( nBegin > m_Text.Len() )
899cdf0e10cSrcweir         {
900cdf0e10cSrcweir             nBegin = m_Text.Len();
901cdf0e10cSrcweir         }
902cdf0e10cSrcweir         if ( nEnd > m_Text.Len() )
903cdf0e10cSrcweir         {
904cdf0e10cSrcweir             nEnd = m_Text.Len();
905cdf0e10cSrcweir         }
906cdf0e10cSrcweir         //
907cdf0e10cSrcweir         if(!IsWrongDirty())
908cdf0e10cSrcweir         {
909cdf0e10cSrcweir             xub_StrLen nTemp = GetWrong()->NextWrong( nBegin );
910cdf0e10cSrcweir             if(nTemp > nEnd)
911cdf0e10cSrcweir             {
912cdf0e10cSrcweir                 // reset original text
913cdf0e10cSrcweir                 if ( bRestoreString )
914cdf0e10cSrcweir                 {
915cdf0e10cSrcweir                     m_Text = aOldTxt;
916cdf0e10cSrcweir                 }
917cdf0e10cSrcweir                 return 0;
918cdf0e10cSrcweir             }
919cdf0e10cSrcweir             if(nTemp > nBegin)
920cdf0e10cSrcweir                 nBegin = nTemp;
921cdf0e10cSrcweir 
922cdf0e10cSrcweir         }
923cdf0e10cSrcweir 
924cdf0e10cSrcweir         // In case 2. we pass the wrong list to the scanned, because only
925cdf0e10cSrcweir         // the words in the wrong list have to be checked
926cdf0e10cSrcweir         SwScanner aScanner( *this, m_Text, 0, 0,
927cdf0e10cSrcweir                             WordType::DICTIONARY_WORD,
928cdf0e10cSrcweir                             nBegin, nEnd );
929cdf0e10cSrcweir         while( !pArgs->xSpellAlt.is() && aScanner.NextWord() )
930cdf0e10cSrcweir 		{
931cdf0e10cSrcweir 			const XubString& rWord = aScanner.GetWord();
932cdf0e10cSrcweir 
933cdf0e10cSrcweir             // get next language for next word, consider language attributes
934cdf0e10cSrcweir             // within the word
935cdf0e10cSrcweir             LanguageType eActLang = aScanner.GetCurrentLanguage();
936cdf0e10cSrcweir 
937cdf0e10cSrcweir             if( rWord.Len() > 0 && LANGUAGE_NONE != eActLang )
938cdf0e10cSrcweir 			{
939cdf0e10cSrcweir 				if (pArgs->xSpeller.is())
940cdf0e10cSrcweir 				{
941cdf0e10cSrcweir 					SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
942cdf0e10cSrcweir 					pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, eActLang,
943cdf0e10cSrcweir 											Sequence< PropertyValue >() );
944cdf0e10cSrcweir 				}
945cdf0e10cSrcweir 				if( (pArgs->xSpellAlt).is() )
946cdf0e10cSrcweir 				{
947cdf0e10cSrcweir 					if( IsSymbol( aScanner.GetBegin() ) )
948cdf0e10cSrcweir 					{
949cdf0e10cSrcweir 						pArgs->xSpellAlt = NULL;
950cdf0e10cSrcweir 					}
951cdf0e10cSrcweir 					else
952cdf0e10cSrcweir 					{
953cdf0e10cSrcweir 						// make sure the selection build later from the
954cdf0e10cSrcweir 						// data below does not include footnotes and other
955cdf0e10cSrcweir 						// "in word" character to the left and right in order
956cdf0e10cSrcweir 						// to preserve those. Therefore count those "in words"
957cdf0e10cSrcweir 						// in order to modify the selection accordingly.
958cdf0e10cSrcweir 						const sal_Unicode* pChar = rWord.GetBuffer();
959cdf0e10cSrcweir 						xub_StrLen nLeft = 0;
960cdf0e10cSrcweir 						while (pChar && *pChar++ == CH_TXTATR_INWORD)
961cdf0e10cSrcweir 							++nLeft;
962cdf0e10cSrcweir 						pChar = rWord.Len() ? rWord.GetBuffer() + rWord.Len() - 1 : 0;
963cdf0e10cSrcweir 						xub_StrLen nRight = 0;
964cdf0e10cSrcweir 						while (pChar && *pChar-- == CH_TXTATR_INWORD)
965cdf0e10cSrcweir 							++nRight;
966cdf0e10cSrcweir 
967cdf0e10cSrcweir 						pArgs->pStartNode = this;
968cdf0e10cSrcweir 						pArgs->pEndNode = this;
969cdf0e10cSrcweir                         pArgs->pStartIdx->Assign(this, aScanner.GetEnd() - nRight );
970cdf0e10cSrcweir                         pArgs->pEndIdx->Assign(this, aScanner.GetBegin() + nLeft );
971cdf0e10cSrcweir 					}
972cdf0e10cSrcweir 				}
973cdf0e10cSrcweir 			}
974cdf0e10cSrcweir         }
975cdf0e10cSrcweir 	}
976cdf0e10cSrcweir 
977cdf0e10cSrcweir     // reset original text
978cdf0e10cSrcweir     if ( bRestoreString )
979cdf0e10cSrcweir     {
980cdf0e10cSrcweir         m_Text = aOldTxt;
981cdf0e10cSrcweir     }
982cdf0e10cSrcweir 
983cdf0e10cSrcweir     return pArgs->xSpellAlt.is() ? 1 : 0;
984cdf0e10cSrcweir }
985cdf0e10cSrcweir 
986cdf0e10cSrcweir 
SetLanguageAndFont(const SwPaM & rPaM,LanguageType nLang,sal_uInt16 nLangWhichId,const Font * pFont,sal_uInt16 nFontWhichId)987cdf0e10cSrcweir void SwTxtNode::SetLanguageAndFont( const SwPaM &rPaM,
988cdf0e10cSrcweir     LanguageType nLang, sal_uInt16 nLangWhichId,
989cdf0e10cSrcweir     const Font *pFont,  sal_uInt16 nFontWhichId )
990cdf0e10cSrcweir {
991cdf0e10cSrcweir     sal_uInt16 aRanges[] = {
992cdf0e10cSrcweir             nLangWhichId, nLangWhichId,
993cdf0e10cSrcweir             nFontWhichId, nFontWhichId,
994cdf0e10cSrcweir             0, 0, 0 };
995cdf0e10cSrcweir     if (!pFont)
996cdf0e10cSrcweir         aRanges[2] = aRanges[3] = 0;    // clear entries with font WhichId
997cdf0e10cSrcweir 
998cdf0e10cSrcweir     SwEditShell *pEditShell = GetDoc()->GetEditShell();
999cdf0e10cSrcweir     SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
1000cdf0e10cSrcweir     aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
1001cdf0e10cSrcweir 
1002cdf0e10cSrcweir     DBG_ASSERT( pFont, "target font missing?" );
1003cdf0e10cSrcweir     if (pFont)
1004cdf0e10cSrcweir     {
1005cdf0e10cSrcweir         SvxFontItem aFontItem = (SvxFontItem&) aSet.Get( nFontWhichId );
1006cdf0e10cSrcweir         aFontItem.SetFamilyName(   pFont->GetName());
1007cdf0e10cSrcweir         aFontItem.SetFamily(       pFont->GetFamily());
1008cdf0e10cSrcweir         aFontItem.SetStyleName(    pFont->GetStyleName());
1009cdf0e10cSrcweir         aFontItem.SetPitch(        pFont->GetPitch());
1010cdf0e10cSrcweir         aFontItem.SetCharSet( pFont->GetCharSet() );
1011cdf0e10cSrcweir         aSet.Put( aFontItem );
1012cdf0e10cSrcweir     }
1013cdf0e10cSrcweir 
1014cdf0e10cSrcweir     GetDoc()->InsertItemSet( rPaM, aSet, 0 );
1015cdf0e10cSrcweir     // SetAttr( aSet );    <- Does not set language attribute of empty paragraphs correctly,
1016cdf0e10cSrcweir     //                     <- because since there is no selection the flag to garbage
1017cdf0e10cSrcweir     //                     <- collect all attributes is set, and therefore attributes spanned
1018cdf0e10cSrcweir     //                     <- over empty selection are removed.
1019cdf0e10cSrcweir 
1020cdf0e10cSrcweir }
1021cdf0e10cSrcweir 
1022cdf0e10cSrcweir 
Convert(SwConversionArgs & rArgs)1023cdf0e10cSrcweir sal_uInt16 SwTxtNode::Convert( SwConversionArgs &rArgs )
1024cdf0e10cSrcweir {
1025cdf0e10cSrcweir     // get range of text within node to be converted
1026cdf0e10cSrcweir     // (either all the text or the the text within the selection
1027cdf0e10cSrcweir     // when the conversion was started)
1028cdf0e10cSrcweir     xub_StrLen nTextBegin, nTextEnd;
1029cdf0e10cSrcweir     //
1030cdf0e10cSrcweir     if ( rArgs.pStartNode != this )
1031cdf0e10cSrcweir 	{
1032cdf0e10cSrcweir         nTextBegin = 0;
1033cdf0e10cSrcweir 	}
1034cdf0e10cSrcweir     else
1035cdf0e10cSrcweir         nTextBegin = rArgs.pStartIdx->GetIndex();
1036cdf0e10cSrcweir     if (nTextBegin > m_Text.Len())
1037cdf0e10cSrcweir     {
1038cdf0e10cSrcweir         nTextBegin = m_Text.Len();
1039cdf0e10cSrcweir     }
1040cdf0e10cSrcweir 
1041cdf0e10cSrcweir     nTextEnd = ( rArgs.pEndNode != this )
1042cdf0e10cSrcweir         ?  m_Text.Len()
1043cdf0e10cSrcweir         :  ::std::min( rArgs.pEndIdx->GetIndex(), m_Text.Len() );
1044cdf0e10cSrcweir 
1045cdf0e10cSrcweir     rArgs.aConvText = rtl::OUString();
1046cdf0e10cSrcweir 
1047cdf0e10cSrcweir     // modify string according to redline information and hidden text
1048cdf0e10cSrcweir     const XubString aOldTxt( m_Text );
1049cdf0e10cSrcweir     const bool bRestoreString =
1050cdf0e10cSrcweir         lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
1051cdf0e10cSrcweir 
1052cdf0e10cSrcweir     sal_Bool    bFound  = sal_False;
1053cdf0e10cSrcweir     xub_StrLen  nBegin  = nTextBegin;
1054cdf0e10cSrcweir     xub_StrLen  nLen = 0;
1055cdf0e10cSrcweir 	LanguageType nLangFound = LANGUAGE_NONE;
1056cdf0e10cSrcweir     if (!m_Text.Len())
1057cdf0e10cSrcweir     {
1058cdf0e10cSrcweir         if (rArgs.bAllowImplicitChangesForNotConvertibleText)
1059cdf0e10cSrcweir         {
1060cdf0e10cSrcweir             // create SwPaM with mark & point spanning empty paragraph
1061cdf0e10cSrcweir             //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1062cdf0e10cSrcweir             SwPaM aCurPaM( *this, 0 );
1063cdf0e10cSrcweir 
1064cdf0e10cSrcweir             SetLanguageAndFont( aCurPaM,
1065cdf0e10cSrcweir                     rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
1066cdf0e10cSrcweir                     rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
1067cdf0e10cSrcweir         }
1068cdf0e10cSrcweir     }
1069cdf0e10cSrcweir     else
1070cdf0e10cSrcweir     {
1071cdf0e10cSrcweir         SwLanguageIterator aIter( *this, nBegin );
1072cdf0e10cSrcweir 
1073cdf0e10cSrcweir         // find non zero length text portion of appropriate language
1074cdf0e10cSrcweir         do {
1075cdf0e10cSrcweir 			nLangFound = aIter.GetLanguage();
1076cdf0e10cSrcweir             sal_Bool bLangOk =  (nLangFound == rArgs.nConvSrcLang) ||
1077cdf0e10cSrcweir                                 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
1078cdf0e10cSrcweir                                  editeng::HangulHanjaConversion::IsChinese( rArgs.nConvSrcLang ));
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir 			xub_StrLen nChPos = aIter.GetChgPos();
1081cdf0e10cSrcweir 			// the position at the end of the paragraph returns -1
1082cdf0e10cSrcweir 			// which becomes 65535 when converted to xub_StrLen,
1083cdf0e10cSrcweir 			// and thus must be cut to the end of the actual string.
1084cdf0e10cSrcweir 			if (nChPos == (xub_StrLen) -1)
1085cdf0e10cSrcweir             {
1086cdf0e10cSrcweir                 nChPos = m_Text.Len();
1087cdf0e10cSrcweir             }
1088cdf0e10cSrcweir 
1089cdf0e10cSrcweir 			nLen = nChPos - nBegin;
1090cdf0e10cSrcweir 			bFound = bLangOk && nLen > 0;
1091cdf0e10cSrcweir 			if (!bFound)
1092cdf0e10cSrcweir             {
1093cdf0e10cSrcweir                 // create SwPaM with mark & point spanning the attributed text
1094cdf0e10cSrcweir                 //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1095cdf0e10cSrcweir                 SwPaM aCurPaM( *this, nBegin );
1096cdf0e10cSrcweir                 aCurPaM.SetMark();
1097cdf0e10cSrcweir                 aCurPaM.GetPoint()->nContent = nBegin + nLen;
1098cdf0e10cSrcweir 
1099cdf0e10cSrcweir                 // check script type of selected text
1100cdf0e10cSrcweir                 SwEditShell *pEditShell = GetDoc()->GetEditShell();
1101cdf0e10cSrcweir                 pEditShell->Push();             // save current cursor on stack
1102cdf0e10cSrcweir                 pEditShell->SetSelection( aCurPaM );
1103cdf0e10cSrcweir                 sal_Bool bIsAsianScript = (SCRIPTTYPE_ASIAN == pEditShell->GetScriptType());
1104cdf0e10cSrcweir                 pEditShell->Pop( sal_False );   // restore cursor from stack
1105cdf0e10cSrcweir 
1106cdf0e10cSrcweir                 if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
1107cdf0e10cSrcweir                 {
1108cdf0e10cSrcweir                     SetLanguageAndFont( aCurPaM,
1109cdf0e10cSrcweir                             rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
1110cdf0e10cSrcweir                             rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
1111cdf0e10cSrcweir                 }
1112cdf0e10cSrcweir 				nBegin = nChPos;    // start of next language portion
1113cdf0e10cSrcweir             }
1114cdf0e10cSrcweir         } while (!bFound && aIter.Next());	/* loop while nothing was found and still sth is left to be searched */
1115cdf0e10cSrcweir     }
1116cdf0e10cSrcweir 
1117cdf0e10cSrcweir     // keep resulting text within selection / range of text to be converted
1118cdf0e10cSrcweir     if (nBegin < nTextBegin)
1119cdf0e10cSrcweir         nBegin = nTextBegin;
1120cdf0e10cSrcweir     if (nBegin + nLen > nTextEnd)
1121cdf0e10cSrcweir         nLen = nTextEnd - nBegin;
1122cdf0e10cSrcweir     sal_Bool bInSelection = nBegin < nTextEnd;
1123cdf0e10cSrcweir 
1124cdf0e10cSrcweir     if (bFound && bInSelection)     // convertible text found within selection/range?
1125cdf0e10cSrcweir     {
1126cdf0e10cSrcweir         const XubString aTxtPortion = m_Text.Copy( nBegin, nLen );
1127cdf0e10cSrcweir         DBG_ASSERT( m_Text.Len() > 0, "convertible text portion missing!" );
1128cdf0e10cSrcweir         rArgs.aConvText     = m_Text.Copy( nBegin, nLen );
1129cdf0e10cSrcweir 		rArgs.nConvTextLang = nLangFound;
1130cdf0e10cSrcweir 
1131cdf0e10cSrcweir         // position where to start looking in next iteration (after current ends)
1132cdf0e10cSrcweir 		rArgs.pStartNode = this;
1133cdf0e10cSrcweir         rArgs.pStartIdx->Assign(this, nBegin + nLen );
1134cdf0e10cSrcweir         // end position (when we have travelled over the whole document)
1135cdf0e10cSrcweir         rArgs.pEndNode = this;
1136cdf0e10cSrcweir         rArgs.pEndIdx->Assign(this, nBegin );
1137cdf0e10cSrcweir 	}
1138cdf0e10cSrcweir 
1139cdf0e10cSrcweir     // restore original text
1140cdf0e10cSrcweir     if ( bRestoreString )
1141cdf0e10cSrcweir     {
1142cdf0e10cSrcweir         m_Text = aOldTxt;
1143cdf0e10cSrcweir     }
1144cdf0e10cSrcweir 
1145cdf0e10cSrcweir     return rArgs.aConvText.getLength() ? 1 : 0;
1146cdf0e10cSrcweir }
1147cdf0e10cSrcweir 
1148cdf0e10cSrcweir // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
1149cdf0e10cSrcweir // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
_AutoSpell(const SwCntntNode * pActNode,const SwViewOption & rViewOpt,xub_StrLen nActPos)1150cdf0e10cSrcweir SwRect SwTxtFrm::_AutoSpell( const SwCntntNode* pActNode, const SwViewOption& rViewOpt, xub_StrLen nActPos )
1151cdf0e10cSrcweir {
1152cdf0e10cSrcweir     SwRect aRect;
1153cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1154cdf0e10cSrcweir     static sal_Bool bStop = sal_False;
1155cdf0e10cSrcweir     if ( bStop )
1156cdf0e10cSrcweir         return aRect;
1157cdf0e10cSrcweir #endif
1158cdf0e10cSrcweir     // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
1159cdf0e10cSrcweir     // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
1160cdf0e10cSrcweir     SwTxtNode *pNode = GetTxtNode();
1161cdf0e10cSrcweir     if( pNode != pActNode || !nActPos )
1162cdf0e10cSrcweir         nActPos = STRING_LEN;
1163cdf0e10cSrcweir 
1164cdf0e10cSrcweir     SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
1165cdf0e10cSrcweir 
1166cdf0e10cSrcweir     // modify string according to redline information and hidden text
1167cdf0e10cSrcweir     const XubString aOldTxt( pNode->GetTxt() );
1168cdf0e10cSrcweir     const bool bRestoreString =
1169cdf0e10cSrcweir             lcl_MaskRedlinesAndHiddenText( *pNode, pNode->m_Text,
1170cdf0e10cSrcweir                 0, pNode->GetTxt().Len() )     > 0;
1171cdf0e10cSrcweir 
1172cdf0e10cSrcweir     // a change of data indicates that at least one word has been modified
1173cdf0e10cSrcweir     const sal_Bool bRedlineChg =
1174cdf0e10cSrcweir         ( pNode->GetTxt().GetBuffer() != aOldTxt.GetBuffer() );
1175cdf0e10cSrcweir 
1176cdf0e10cSrcweir     xub_StrLen nBegin = 0;
1177cdf0e10cSrcweir     xub_StrLen nEnd = pNode->GetTxt().Len();
1178cdf0e10cSrcweir     xub_StrLen nInsertPos = 0;
1179cdf0e10cSrcweir     xub_StrLen nChgStart = STRING_LEN;
1180cdf0e10cSrcweir     xub_StrLen nChgEnd = 0;
1181cdf0e10cSrcweir     xub_StrLen nInvStart = STRING_LEN;
1182cdf0e10cSrcweir     xub_StrLen nInvEnd = 0;
1183cdf0e10cSrcweir 
1184cdf0e10cSrcweir     const sal_Bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
1185cdf0e10cSrcweir                                   rViewOpt.IsAutoCompleteWords();
1186cdf0e10cSrcweir 
1187cdf0e10cSrcweir     if( pNode->GetWrong() )
1188cdf0e10cSrcweir     {
1189cdf0e10cSrcweir         nBegin = pNode->GetWrong()->GetBeginInv();
1190cdf0e10cSrcweir         if( STRING_LEN != nBegin )
1191cdf0e10cSrcweir         {
1192cdf0e10cSrcweir             nEnd = pNode->GetWrong()->GetEndInv();
1193cdf0e10cSrcweir             if ( nEnd > pNode->GetTxt().Len() )
1194cdf0e10cSrcweir             {
1195cdf0e10cSrcweir                 nEnd = pNode->GetTxt().Len();
1196cdf0e10cSrcweir             }
1197cdf0e10cSrcweir         }
1198cdf0e10cSrcweir 
1199cdf0e10cSrcweir         // get word around nBegin, we start at nBegin - 1
1200cdf0e10cSrcweir         if ( STRING_LEN != nBegin )
1201cdf0e10cSrcweir         {
1202cdf0e10cSrcweir             if ( nBegin )
1203cdf0e10cSrcweir                 --nBegin;
1204cdf0e10cSrcweir 
1205cdf0e10cSrcweir             LanguageType eActLang = pNode->GetLang( nBegin );
1206cdf0e10cSrcweir             Boundary aBound =
1207cdf0e10cSrcweir                 pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetTxt(), nBegin,
1208cdf0e10cSrcweir                     pBreakIt->GetLocale( eActLang ),
1209cdf0e10cSrcweir                     WordType::DICTIONARY_WORD, sal_True );
1210cdf0e10cSrcweir             nBegin = xub_StrLen(aBound.startPos);
1211cdf0e10cSrcweir         }
1212cdf0e10cSrcweir 
1213cdf0e10cSrcweir         // get the position in the wrong list
1214cdf0e10cSrcweir         nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
1215cdf0e10cSrcweir 
1216cdf0e10cSrcweir         // sometimes we have to skip one entry
1217cdf0e10cSrcweir         if( nInsertPos < pNode->GetWrong()->Count() &&
1218cdf0e10cSrcweir             nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
1219cdf0e10cSrcweir                       pNode->GetWrong()->Len( nInsertPos ) )
1220cdf0e10cSrcweir                 nInsertPos++;
1221cdf0e10cSrcweir     }
1222cdf0e10cSrcweir 
1223cdf0e10cSrcweir     sal_Bool bFresh = nBegin < nEnd;
1224cdf0e10cSrcweir 
1225cdf0e10cSrcweir     if( nBegin < nEnd )
1226cdf0e10cSrcweir     {
1227cdf0e10cSrcweir         //! register listener to LinguServiceEvents now in order to get
1228cdf0e10cSrcweir         //! notified about relevant changes in the future
1229cdf0e10cSrcweir         SwModule *pModule = SW_MOD();
1230cdf0e10cSrcweir         if (!pModule->GetLngSvcEvtListener().is())
1231cdf0e10cSrcweir             pModule->CreateLngSvcEvtListener();
1232cdf0e10cSrcweir 
1233cdf0e10cSrcweir 		uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1234cdf0e10cSrcweir         SwDoc* pDoc = pNode->GetDoc();
1235cdf0e10cSrcweir 
1236cdf0e10cSrcweir         SwScanner aScanner( *pNode, pNode->GetTxt(), 0, 0,
1237cdf0e10cSrcweir                             WordType::DICTIONARY_WORD, nBegin, nEnd);
1238cdf0e10cSrcweir 
1239cdf0e10cSrcweir         while( aScanner.NextWord() )
1240cdf0e10cSrcweir         {
1241cdf0e10cSrcweir             const XubString& rWord = aScanner.GetWord();
1242cdf0e10cSrcweir             nBegin = aScanner.GetBegin();
1243cdf0e10cSrcweir             xub_StrLen nLen = aScanner.GetLen();
1244cdf0e10cSrcweir 
1245cdf0e10cSrcweir             // get next language for next word, consider language attributes
1246cdf0e10cSrcweir             // within the word
1247cdf0e10cSrcweir             LanguageType eActLang = aScanner.GetCurrentLanguage();
1248cdf0e10cSrcweir 
1249cdf0e10cSrcweir             sal_Bool bSpell = sal_True;
1250cdf0e10cSrcweir             bSpell = xSpell.is() ? xSpell->hasLanguage( eActLang ) : sal_False;
1251cdf0e10cSrcweir             if( bSpell && rWord.Len() > 0 )
1252cdf0e10cSrcweir             {
1253cdf0e10cSrcweir                 // check for: bAlter => xHyphWord.is()
1254cdf0e10cSrcweir                 DBG_ASSERT(!bSpell || xSpell.is(), "NULL pointer");
1255cdf0e10cSrcweir 
1256cdf0e10cSrcweir                 if( !xSpell->isValid( rWord, eActLang, Sequence< PropertyValue >() ) )
1257cdf0e10cSrcweir                 {
1258cdf0e10cSrcweir                     xub_StrLen nSmartTagStt = nBegin;
1259cdf0e10cSrcweir                     xub_StrLen nDummy = 1;
1260cdf0e10cSrcweir                     if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
1261cdf0e10cSrcweir                     {
1262cdf0e10cSrcweir                         if( !pNode->GetWrong() )
1263cdf0e10cSrcweir                         {
1264cdf0e10cSrcweir                             pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
1265cdf0e10cSrcweir                             pNode->GetWrong()->SetInvalid( 0, nEnd );
1266cdf0e10cSrcweir                         }
1267cdf0e10cSrcweir                         if( pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1268cdf0e10cSrcweir                             nBegin, nLen, nInsertPos, nActPos ) )
1269cdf0e10cSrcweir                             pNode->GetWrong()->Insert( rtl::OUString(), 0, nBegin, nLen, nInsertPos++ );
1270cdf0e10cSrcweir                         else
1271cdf0e10cSrcweir                         {
1272cdf0e10cSrcweir                             nInvStart = nBegin;
1273cdf0e10cSrcweir                             nInvEnd = nBegin + nLen;
1274cdf0e10cSrcweir                         }
1275cdf0e10cSrcweir                     }
1276cdf0e10cSrcweir                 }
1277cdf0e10cSrcweir                 else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.Len() )
1278cdf0e10cSrcweir                 {
1279cdf0e10cSrcweir                     if ( bRedlineChg )
1280cdf0e10cSrcweir                     {
1281cdf0e10cSrcweir                         XubString rNewWord( rWord );
1282cdf0e10cSrcweir                         rACW.InsertWord( rNewWord, *pDoc );
1283cdf0e10cSrcweir                     }
1284cdf0e10cSrcweir                     else
1285cdf0e10cSrcweir                         rACW.InsertWord( rWord, *pDoc );
1286cdf0e10cSrcweir                 }
1287cdf0e10cSrcweir             }
1288cdf0e10cSrcweir         }
1289cdf0e10cSrcweir     }
1290cdf0e10cSrcweir 
1291cdf0e10cSrcweir     // reset original text
1292cdf0e10cSrcweir     // i63141 before calling GetCharRect(..) with formatting!
1293cdf0e10cSrcweir     if ( bRestoreString )
1294cdf0e10cSrcweir     {
1295cdf0e10cSrcweir         pNode->m_Text = aOldTxt;
1296cdf0e10cSrcweir     }
1297cdf0e10cSrcweir     if( pNode->GetWrong() )
1298cdf0e10cSrcweir     {
1299cdf0e10cSrcweir         if( bFresh )
1300cdf0e10cSrcweir             pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1301cdf0e10cSrcweir                                       nEnd, 0, nInsertPos, nActPos );
1302cdf0e10cSrcweir 
1303cdf0e10cSrcweir         //
1304cdf0e10cSrcweir         // Calculate repaint area:
1305cdf0e10cSrcweir         //
1306cdf0e10cSrcweir         if( nChgStart < nChgEnd )
1307cdf0e10cSrcweir         {
1308cdf0e10cSrcweir             aRect = lcl_CalculateRepaintRect( *this, nChgStart, nChgEnd );
1309cdf0e10cSrcweir         }
1310cdf0e10cSrcweir 
1311cdf0e10cSrcweir         pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
1312cdf0e10cSrcweir         pNode->SetWrongDirty( STRING_LEN != pNode->GetWrong()->GetBeginInv() );
1313cdf0e10cSrcweir         if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
1314cdf0e10cSrcweir             pNode->SetWrong( NULL );
1315cdf0e10cSrcweir     }
1316cdf0e10cSrcweir     else
1317cdf0e10cSrcweir         pNode->SetWrongDirty( false );
1318cdf0e10cSrcweir 
1319cdf0e10cSrcweir     if( bAddAutoCmpl )
1320cdf0e10cSrcweir         pNode->SetAutoCompleteWordDirty( false );
1321cdf0e10cSrcweir 
1322cdf0e10cSrcweir     return aRect;
1323cdf0e10cSrcweir }
1324cdf0e10cSrcweir 
1325cdf0e10cSrcweir /** Function: SmartTagScan
1326cdf0e10cSrcweir 
1327cdf0e10cSrcweir     Function scans words in current text and checks them in the
1328cdf0e10cSrcweir     smarttag libraries. If the check returns true to bounds of the
1329cdf0e10cSrcweir     recognized words are stored into a list which is used later for drawing
1330cdf0e10cSrcweir     the underline.
1331cdf0e10cSrcweir 
1332cdf0e10cSrcweir     @param SwCntntNode* pActNode
1333cdf0e10cSrcweir 
1334cdf0e10cSrcweir     @param xub_StrLen nActPos
1335cdf0e10cSrcweir 
1336cdf0e10cSrcweir     @return SwRect: Repaint area
1337cdf0e10cSrcweir */
SmartTagScan(SwCntntNode *,xub_StrLen)1338cdf0e10cSrcweir SwRect SwTxtFrm::SmartTagScan( SwCntntNode* /*pActNode*/, xub_StrLen /*nActPos*/ )
1339cdf0e10cSrcweir {
1340cdf0e10cSrcweir     SwRect aRet;
1341cdf0e10cSrcweir     SwTxtNode *pNode = GetTxtNode();
1342cdf0e10cSrcweir     const rtl::OUString& rText = pNode->GetTxt();
1343cdf0e10cSrcweir 
1344cdf0e10cSrcweir     // Iterate over language portions
1345cdf0e10cSrcweir     SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
1346cdf0e10cSrcweir 
1347cdf0e10cSrcweir     SwWrongList* pSmartTagList = pNode->GetSmartTags();
1348cdf0e10cSrcweir 
1349cdf0e10cSrcweir     xub_StrLen nBegin = 0;
1350cdf0e10cSrcweir     xub_StrLen nEnd = static_cast< xub_StrLen >(rText.getLength());
1351cdf0e10cSrcweir 
1352cdf0e10cSrcweir     if ( pSmartTagList )
1353cdf0e10cSrcweir     {
1354cdf0e10cSrcweir         if ( pSmartTagList->GetBeginInv() != STRING_LEN )
1355cdf0e10cSrcweir         {
1356cdf0e10cSrcweir             nBegin = pSmartTagList->GetBeginInv();
1357cdf0e10cSrcweir             nEnd = Min( pSmartTagList->GetEndInv(), (xub_StrLen)rText.getLength() );
1358cdf0e10cSrcweir 
1359cdf0e10cSrcweir             if ( nBegin < nEnd )
1360cdf0e10cSrcweir             {
1361cdf0e10cSrcweir                 const LanguageType aCurrLang = pNode->GetLang( nBegin );
1362cdf0e10cSrcweir                 const com::sun::star::lang::Locale aCurrLocale = pBreakIt->GetLocale( aCurrLang );
1363cdf0e10cSrcweir                 nBegin = static_cast< xub_StrLen >(pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale ));
1364cdf0e10cSrcweir                 nEnd = static_cast< xub_StrLen >(Min( rText.getLength(), pBreakIt->GetBreakIter()->endOfSentence( rText, nEnd, aCurrLocale ) ));
1365cdf0e10cSrcweir             }
1366cdf0e10cSrcweir         }
1367cdf0e10cSrcweir     }
1368cdf0e10cSrcweir 
1369cdf0e10cSrcweir     const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
1370cdf0e10cSrcweir     sal_uInt16 nNumberOfRemovedEntries = 0;
1371cdf0e10cSrcweir     sal_uInt16 nNumberOfInsertedEntries = 0;
1372cdf0e10cSrcweir 
1373cdf0e10cSrcweir     // clear smart tag list between nBegin and nEnd:
1374cdf0e10cSrcweir     if ( 0 != nNumberOfEntries )
1375cdf0e10cSrcweir     {
1376cdf0e10cSrcweir         xub_StrLen nChgStart = STRING_LEN;
1377cdf0e10cSrcweir         xub_StrLen nChgEnd = 0;
1378cdf0e10cSrcweir         const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
1379cdf0e10cSrcweir         pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, STRING_LEN );
1380cdf0e10cSrcweir         nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
1381cdf0e10cSrcweir     }
1382cdf0e10cSrcweir 
1383cdf0e10cSrcweir     if ( nBegin < nEnd )
1384cdf0e10cSrcweir     {
1385cdf0e10cSrcweir         // Expand the string:
1386cdf0e10cSrcweir         rtl::OUString aExpandText;
1387cdf0e10cSrcweir         const ModelToViewHelper::ConversionMap* pConversionMap =
1388cdf0e10cSrcweir                 pNode->BuildConversionMap( aExpandText );
1389cdf0e10cSrcweir 
1390cdf0e10cSrcweir         // Ownership ov ConversionMap is passed to SwXTextMarkup object!
1391cdf0e10cSrcweir         Reference< com::sun::star::text::XTextMarkup > xTextMarkup =
1392cdf0e10cSrcweir              new SwXTextMarkup( *pNode, pConversionMap );
1393cdf0e10cSrcweir 
1394cdf0e10cSrcweir         Reference< ::com::sun::star::frame::XController > xController = pNode->GetDoc()->GetDocShell()->GetController();
1395cdf0e10cSrcweir 
1396bbac9d2cSJürgen Schmidt 	SwPosition start(*pNode, nBegin);
1397bbac9d2cSJürgen Schmidt 	SwPosition end  (*pNode, nEnd);
1398bbac9d2cSJürgen Schmidt         Reference< ::com::sun::star::text::XTextRange > xRange = SwXTextRange::CreateXTextRange(*pNode->GetDoc(), start, &end);
1399bbac9d2cSJürgen Schmidt 
1400bbac9d2cSJürgen Schmidt 	rSmartTagMgr.RecognizeTextRange(xRange, xTextMarkup, xController);
1401bbac9d2cSJürgen Schmidt 
1402bbac9d2cSJürgen Schmidt 
1403bbac9d2cSJürgen Schmidt 	xub_StrLen nLangBegin = nBegin;
1404cdf0e10cSrcweir         xub_StrLen nLangEnd = nEnd;
1405cdf0e10cSrcweir 
1406cdf0e10cSrcweir         // smart tag recognization has to be done for each language portion:
1407cdf0e10cSrcweir         SwLanguageIterator aIter( *pNode, nLangBegin );
1408cdf0e10cSrcweir 
1409cdf0e10cSrcweir         do
1410cdf0e10cSrcweir         {
1411cdf0e10cSrcweir             const LanguageType nLang = aIter.GetLanguage();
1412cdf0e10cSrcweir             const com::sun::star::lang::Locale aLocale = pBreakIt->GetLocale( nLang );
1413cdf0e10cSrcweir             nLangEnd = Min( nEnd, aIter.GetChgPos() );
1414cdf0e10cSrcweir 
1415cdf0e10cSrcweir             const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nLangBegin );
1416cdf0e10cSrcweir             const sal_uInt32 nExpandEnd   = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nLangEnd );
1417cdf0e10cSrcweir 
1418bbac9d2cSJürgen Schmidt             rSmartTagMgr.RecognizeString(aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
1419cdf0e10cSrcweir 
1420cdf0e10cSrcweir             nLangBegin = nLangEnd;
1421cdf0e10cSrcweir         }
1422cdf0e10cSrcweir         while ( aIter.Next() && nLangEnd < nEnd );
1423cdf0e10cSrcweir 
1424cdf0e10cSrcweir         pSmartTagList = pNode->GetSmartTags();
1425cdf0e10cSrcweir 
1426cdf0e10cSrcweir         const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
1427cdf0e10cSrcweir         nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
1428cdf0e10cSrcweir     }
1429cdf0e10cSrcweir 
1430cdf0e10cSrcweir     if( pSmartTagList )
1431cdf0e10cSrcweir 	{
1432cdf0e10cSrcweir         //
1433cdf0e10cSrcweir         // Update WrongList stuff
1434cdf0e10cSrcweir         //
1435cdf0e10cSrcweir         pSmartTagList->SetInvalid( STRING_LEN, 0 );
1436cdf0e10cSrcweir         pNode->SetSmartTagDirty( STRING_LEN != pSmartTagList->GetBeginInv() );
1437cdf0e10cSrcweir 
1438cdf0e10cSrcweir         if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
1439cdf0e10cSrcweir             pNode->SetSmartTags( NULL );
1440cdf0e10cSrcweir 
1441cdf0e10cSrcweir         //
1442cdf0e10cSrcweir         // Calculate repaint area:
1443cdf0e10cSrcweir         //
1444cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1445cdf0e10cSrcweir         const sal_uInt16 nNumberOfEntriesAfterRecognize2 = pSmartTagList->Count();
1446cdf0e10cSrcweir 		(void) nNumberOfEntriesAfterRecognize2;
1447cdf0e10cSrcweir #endif
1448cdf0e10cSrcweir         if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
1449cdf0e10cSrcweir                                 0 != nNumberOfInsertedEntries ) )
1450cdf0e10cSrcweir 		{
1451cdf0e10cSrcweir             aRet = lcl_CalculateRepaintRect( *this, nBegin, nEnd );
1452cdf0e10cSrcweir         }
1453cdf0e10cSrcweir     }
1454cdf0e10cSrcweir 	else
1455cdf0e10cSrcweir         pNode->SetSmartTagDirty( false );
1456cdf0e10cSrcweir 
1457cdf0e10cSrcweir     return aRet;
1458cdf0e10cSrcweir }
1459cdf0e10cSrcweir 
1460cdf0e10cSrcweir 
1461cdf0e10cSrcweir // Wird vom CollectAutoCmplWords gerufen
CollectAutoCmplWrds(SwCntntNode * pActNode,xub_StrLen nActPos)1462cdf0e10cSrcweir void SwTxtFrm::CollectAutoCmplWrds( SwCntntNode* pActNode, xub_StrLen nActPos )
1463cdf0e10cSrcweir {
1464cdf0e10cSrcweir 	SwTxtNode *pNode = GetTxtNode();
1465cdf0e10cSrcweir 	if( pNode != pActNode || !nActPos )
1466cdf0e10cSrcweir 		nActPos = STRING_LEN;
1467cdf0e10cSrcweir 
1468cdf0e10cSrcweir     SwDoc* pDoc = pNode->GetDoc();
1469cdf0e10cSrcweir     SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
1470cdf0e10cSrcweir 
1471cdf0e10cSrcweir 	xub_StrLen nBegin = 0;
1472cdf0e10cSrcweir     xub_StrLen nEnd = pNode->GetTxt().Len();
1473cdf0e10cSrcweir 	xub_StrLen nLen;
1474cdf0e10cSrcweir 	sal_Bool bACWDirty = sal_False, bAnyWrd = sal_False;
1475cdf0e10cSrcweir 
1476cdf0e10cSrcweir 
1477cdf0e10cSrcweir 	if( nBegin < nEnd )
1478cdf0e10cSrcweir 	{
1479cdf0e10cSrcweir         sal_uInt16 nCnt = 200;
1480cdf0e10cSrcweir         SwScanner aScanner( *pNode, pNode->GetTxt(), 0, 0,
1481cdf0e10cSrcweir                             WordType::DICTIONARY_WORD, nBegin, nEnd );
1482cdf0e10cSrcweir         while( aScanner.NextWord() )
1483cdf0e10cSrcweir 		{
1484cdf0e10cSrcweir 			nBegin = aScanner.GetBegin();
1485cdf0e10cSrcweir 			nLen = aScanner.GetLen();
1486cdf0e10cSrcweir 			if( rACW.GetMinWordLen() <= nLen )
1487cdf0e10cSrcweir 			{
1488cdf0e10cSrcweir 				const XubString& rWord = aScanner.GetWord();
1489cdf0e10cSrcweir 
1490cdf0e10cSrcweir 				if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
1491cdf0e10cSrcweir 				{
1492cdf0e10cSrcweir                     if( rACW.GetMinWordLen() <= rWord.Len() )
1493cdf0e10cSrcweir                         rACW.InsertWord( rWord, *pDoc );
1494cdf0e10cSrcweir                     bAnyWrd = sal_True;
1495cdf0e10cSrcweir 				}
1496cdf0e10cSrcweir 				else
1497cdf0e10cSrcweir 					bACWDirty = sal_True;
1498cdf0e10cSrcweir 			}
1499cdf0e10cSrcweir             if( !--nCnt )
1500cdf0e10cSrcweir             {
1501cdf0e10cSrcweir                 if ( Application::AnyInput( INPUT_ANY ) )
1502cdf0e10cSrcweir                     return;
1503cdf0e10cSrcweir                 nCnt = 100;
1504cdf0e10cSrcweir             }
1505cdf0e10cSrcweir 		}
1506cdf0e10cSrcweir 	}
1507cdf0e10cSrcweir 
1508cdf0e10cSrcweir 	if( bAnyWrd && !bACWDirty )
1509cdf0e10cSrcweir 		pNode->SetAutoCompleteWordDirty( sal_False );
1510cdf0e10cSrcweir }
1511cdf0e10cSrcweir 
1512cdf0e10cSrcweir 
1513cdf0e10cSrcweir /*************************************************************************
1514cdf0e10cSrcweir  *						SwTxtNode::Hyphenate
1515cdf0e10cSrcweir  *************************************************************************/
1516cdf0e10cSrcweir // Findet den TxtFrm und sucht dessen CalcHyph
1517cdf0e10cSrcweir 
Hyphenate(SwInterHyphInfo & rHyphInf)1518cdf0e10cSrcweir sal_Bool SwTxtNode::Hyphenate( SwInterHyphInfo &rHyphInf )
1519cdf0e10cSrcweir {
1520cdf0e10cSrcweir 	// Abkuerzung: am Absatz ist keine Sprache eingestellt:
1521cdf0e10cSrcweir     if ( LANGUAGE_NONE == sal_uInt16( GetSwAttrSet().GetLanguage().GetLanguage() )
1522cdf0e10cSrcweir          && USHRT_MAX == GetLang( 0, m_Text.Len() ) )
1523cdf0e10cSrcweir     {
1524cdf0e10cSrcweir 		if( !rHyphInf.IsCheck() )
1525cdf0e10cSrcweir 			rHyphInf.SetNoLang( sal_True );
1526cdf0e10cSrcweir 		return sal_False;
1527cdf0e10cSrcweir 	}
1528cdf0e10cSrcweir 
1529cdf0e10cSrcweir 	if( pLinguNode != this )
1530cdf0e10cSrcweir 	{
1531cdf0e10cSrcweir 		pLinguNode = this;
1532cdf0e10cSrcweir 		pLinguFrm = (SwTxtFrm*)getLayoutFrm( GetDoc()->GetCurrentLayout(), (Point*)(rHyphInf.GetCrsrPos()) );
1533cdf0e10cSrcweir 	}
1534cdf0e10cSrcweir 	SwTxtFrm *pFrm = pLinguFrm;
1535cdf0e10cSrcweir 	if( pFrm )
1536cdf0e10cSrcweir         pFrm = &(pFrm->GetFrmAtOfst( rHyphInf.nStart ));
1537cdf0e10cSrcweir 	else
1538cdf0e10cSrcweir 	{
1539cdf0e10cSrcweir 		// 4935: Seit der Trennung ueber Sonderbereiche sind Faelle
1540cdf0e10cSrcweir 		// moeglich, in denen kein Frame zum Node vorliegt.
1541cdf0e10cSrcweir 		// Also kein ASSERT!
1542cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1543cdf0e10cSrcweir 		ASSERT( pFrm, "!SwTxtNode::Hyphenate: can't find any frame" );
1544cdf0e10cSrcweir #endif
1545cdf0e10cSrcweir 		return sal_False;
1546cdf0e10cSrcweir 	}
1547cdf0e10cSrcweir 
1548cdf0e10cSrcweir 	while( pFrm )
1549cdf0e10cSrcweir 	{
1550cdf0e10cSrcweir 		if( pFrm->Hyphenate( rHyphInf ) )
1551cdf0e10cSrcweir 		{
1552cdf0e10cSrcweir 			// Das Layout ist nicht robust gegen "Direktformatierung"
1553cdf0e10cSrcweir 			// (7821, 7662, 7408); vgl. layact.cxx,
1554cdf0e10cSrcweir 			// SwLayAction::_TurboAction(), if( !pCnt->IsValid() ...
1555cdf0e10cSrcweir 			pFrm->SetCompletePaint();
1556cdf0e10cSrcweir 			return sal_True;
1557cdf0e10cSrcweir 		}
1558cdf0e10cSrcweir 		pFrm = (SwTxtFrm*)(pFrm->GetFollow());
1559cdf0e10cSrcweir 		if( pFrm )
1560cdf0e10cSrcweir 		{
1561cdf0e10cSrcweir 			rHyphInf.nLen = rHyphInf.nLen - (pFrm->GetOfst() - rHyphInf.nStart);
1562cdf0e10cSrcweir 			rHyphInf.nStart = pFrm->GetOfst();
1563cdf0e10cSrcweir 		}
1564cdf0e10cSrcweir 	}
1565cdf0e10cSrcweir 	return sal_False;
1566cdf0e10cSrcweir }
1567cdf0e10cSrcweir 
1568cdf0e10cSrcweir #ifdef LINGU_STATISTIK
1569cdf0e10cSrcweir 
1570cdf0e10cSrcweir // globale Variable
1571cdf0e10cSrcweir SwLinguStatistik aSwLinguStat;
1572cdf0e10cSrcweir 
1573cdf0e10cSrcweir 
Flush()1574cdf0e10cSrcweir void SwLinguStatistik::Flush()
1575cdf0e10cSrcweir {
1576cdf0e10cSrcweir 	if ( !nWords )
1577cdf0e10cSrcweir 		return ;
1578cdf0e10cSrcweir 
1579cdf0e10cSrcweir 	static char *pLogName = 0;
1580cdf0e10cSrcweir 	const sal_Bool bFirstOpen = pLogName ? sal_False : sal_True;
1581cdf0e10cSrcweir 	if( bFirstOpen )
1582cdf0e10cSrcweir 	{
1583cdf0e10cSrcweir 		char *pPath = getenv( "TEMP" );
1584cdf0e10cSrcweir 		char *pName = "swlingu.stk";
1585cdf0e10cSrcweir 		if( !pPath )
1586cdf0e10cSrcweir 			pLogName = pName;
1587cdf0e10cSrcweir 		else
1588cdf0e10cSrcweir 		{
1589cdf0e10cSrcweir 			const int nLen = strlen(pPath);
1590cdf0e10cSrcweir 			// fuer dieses new wird es kein delete geben.
1591cdf0e10cSrcweir 			pLogName = new char[nLen + strlen(pName) + 3];
1592cdf0e10cSrcweir 			if(nLen && (pPath[nLen-1] == '\\') || (pPath[nLen-1] == '/'))
1593cdf0e10cSrcweir 				snprintf( pLogName, sizeof(pLogName), "%s%s", pPath, pName );
1594cdf0e10cSrcweir 			else
1595cdf0e10cSrcweir 				snprintf( pLogName, sizeof(pLogName), "%s/%s", pPath, pName );
1596cdf0e10cSrcweir 		}
1597cdf0e10cSrcweir 	}
1598cdf0e10cSrcweir 	SvFileStream aStream( String::CreateFromAscii(pLogName), (bFirstOpen
1599cdf0e10cSrcweir 										? STREAM_WRITE | STREAM_TRUNC
1600cdf0e10cSrcweir 										: STREAM_WRITE ));
1601cdf0e10cSrcweir 
1602cdf0e10cSrcweir 	if( !aStream.GetError() )
1603cdf0e10cSrcweir 	{
1604cdf0e10cSrcweir 		if ( bFirstOpen )
1605cdf0e10cSrcweir 			aStream << "\nLinguistik-Statistik\n";
1606cdf0e10cSrcweir 		aStream << endl << ++nFlushCnt << ". Messung\n";
1607cdf0e10cSrcweir 		aStream << "Rechtschreibung\n";
1608cdf0e10cSrcweir 		aStream << "gepruefte Worte: \t" << nWords << endl;
1609cdf0e10cSrcweir 		aStream << "als fehlerhaft erkannt:\t" << nWrong << endl;
1610cdf0e10cSrcweir 		aStream << "Alternativvorschlaege:\t" << nAlter << endl;
1611cdf0e10cSrcweir 		if ( nWrong )
1612cdf0e10cSrcweir 			aStream << "Durchschnitt:\t\t" << nAlter*1.0 / nWrong << endl;
1613cdf0e10cSrcweir 		aStream << "Dauer (msec):\t\t" << nSpellTime << endl;
1614cdf0e10cSrcweir 		aStream << "\nThesaurus\n";
1615cdf0e10cSrcweir 		aStream << "Synonyme gesamt:\t" << nSynonym << endl;
1616cdf0e10cSrcweir 		if ( nSynonym )
1617cdf0e10cSrcweir 			aStream << "Synonym-Durchschnitt:\t" <<
1618cdf0e10cSrcweir 							nSynonym*1.0 / ( nWords - nNoSynonym ) << endl;
1619cdf0e10cSrcweir 		aStream << "ohne Synonyme:\t\t" << nNoSynonym << endl;
1620cdf0e10cSrcweir 		aStream << "Bedeutungen gesamt:\t" << nSynonym << endl;
1621cdf0e10cSrcweir 		aStream << "keine Bedeutungen:\t"<< nNoSynonym << endl;
1622cdf0e10cSrcweir 		aStream << "Dauer (msec):\t\t" << nTheTime << endl;
1623cdf0e10cSrcweir 		aStream << "\nHyphenator\n";
1624cdf0e10cSrcweir 		aStream << "Trennstellen gesamt:\t" << nHyphens << endl;
1625cdf0e10cSrcweir 		if ( nHyphens )
1626cdf0e10cSrcweir 			aStream << "Hyphen-Durchschnitt:\t" <<
1627cdf0e10cSrcweir 					nHyphens*1.0 / ( nWords - nNoHyph - nHyphErr ) << endl;
1628cdf0e10cSrcweir 		aStream << "keine Trennstellen:\t" << nNoHyph << endl;
1629cdf0e10cSrcweir 		aStream << "Trennung verweigert:\t" << nHyphErr << endl;
1630cdf0e10cSrcweir 		aStream << "Dauer (msec):\t\t" << nHyphTime << endl;
1631cdf0e10cSrcweir 		aStream << "---------------------------------------------\n";
1632cdf0e10cSrcweir 	}
1633cdf0e10cSrcweir 	nWords = nWrong = nAlter = nSynonym = nNoSynonym =
1634cdf0e10cSrcweir 	nHyphens = nNoHyph = nHyphErr = nSpellTime = nTheTime =
1635cdf0e10cSrcweir 	nHyphTime = 0;
1636cdf0e10cSrcweir 	//pThes = NULL;
1637cdf0e10cSrcweir }
1638cdf0e10cSrcweir 
1639cdf0e10cSrcweir #endif
1640cdf0e10cSrcweir 
164100a33fa1SHerbert Dürr namespace sw // #i120045# namespace to avoid XCode template-misoptimization
164200a33fa1SHerbert Dürr {
1643cdf0e10cSrcweir struct TransliterationChgData
1644cdf0e10cSrcweir {
1645cdf0e10cSrcweir     xub_StrLen              nStart;
1646cdf0e10cSrcweir     xub_StrLen              nLen;
1647cdf0e10cSrcweir     String                  sChanged;
1648cdf0e10cSrcweir     Sequence< sal_Int32 >   aOffsets;
1649cdf0e10cSrcweir };
165000a33fa1SHerbert Dürr }
165100a33fa1SHerbert Dürr using sw::TransliterationChgData;
1652cdf0e10cSrcweir 
1653cdf0e10cSrcweir // change text to Upper/Lower/Hiragana/Katagana/...
TransliterateText(utl::TransliterationWrapper & rTrans,xub_StrLen nStt,xub_StrLen nEnd,SwUndoTransliterate * pUndo)1654cdf0e10cSrcweir void SwTxtNode::TransliterateText(
1655cdf0e10cSrcweir     utl::TransliterationWrapper& rTrans,
1656cdf0e10cSrcweir     xub_StrLen nStt, xub_StrLen nEnd,
1657cdf0e10cSrcweir     SwUndoTransliterate* pUndo )
1658cdf0e10cSrcweir {
1659cdf0e10cSrcweir     if (nStt < nEnd && pBreakIt->GetBreakIter().is())
1660cdf0e10cSrcweir 	{
1661cdf0e10cSrcweir         // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
1662cdf0e10cSrcweir         // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
1663cdf0e10cSrcweir         // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
1664cdf0e10cSrcweir         // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
1665cdf0e10cSrcweir         // proper thing to do.
1666cdf0e10cSrcweir         const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
1667cdf0e10cSrcweir 
1668cdf0e10cSrcweir         //! In order to have less trouble with changing text size, e.g. because
1669cdf0e10cSrcweir         //! of ligatures or � (German small sz) being resolved, we need to process
1670cdf0e10cSrcweir         //! the text replacements from end to start.
1671cdf0e10cSrcweir         //! This way the offsets for the yet to be changed words will be
1672cdf0e10cSrcweir         //! left unchanged by the already replaced text.
1673cdf0e10cSrcweir         //! For this we temporarily save the changes to be done in this vector
1674cdf0e10cSrcweir         std::vector< TransliterationChgData >   aChanges;
1675cdf0e10cSrcweir         TransliterationChgData                  aChgData;
1676cdf0e10cSrcweir 
1677cdf0e10cSrcweir         if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::TITLE_CASE)
1678cdf0e10cSrcweir         {
1679cdf0e10cSrcweir             // for 'capitalize every word' we need to iterate over each word
1680cdf0e10cSrcweir 
1681cdf0e10cSrcweir             Boundary aSttBndry;
1682cdf0e10cSrcweir             Boundary aEndBndry;
1683cdf0e10cSrcweir             aSttBndry = pBreakIt->GetBreakIter()->getWordBoundary(
1684cdf0e10cSrcweir                         GetTxt(), nStt,
1685cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nStt ) ),
1686cdf0e10cSrcweir                         nWordType,
1687cdf0e10cSrcweir                         sal_True /*prefer forward direction*/);
1688cdf0e10cSrcweir             aEndBndry = pBreakIt->GetBreakIter()->getWordBoundary(
1689cdf0e10cSrcweir                         GetTxt(), nEnd,
1690cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nEnd ) ),
1691cdf0e10cSrcweir                         nWordType,
1692cdf0e10cSrcweir                         sal_False /*prefer backward direction*/);
1693cdf0e10cSrcweir 
1694cdf0e10cSrcweir             // prevent backtracking to the previous word if selection is at word boundary
1695cdf0e10cSrcweir             if (aSttBndry.endPos <= nStt)
1696cdf0e10cSrcweir             {
1697cdf0e10cSrcweir                 aSttBndry = pBreakIt->GetBreakIter()->nextWord(
1698cdf0e10cSrcweir                         GetTxt(), aSttBndry.endPos,
1699cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
1700cdf0e10cSrcweir                         nWordType);
1701cdf0e10cSrcweir             }
1702cdf0e10cSrcweir             // prevent advancing to the next word if selection is at word boundary
1703cdf0e10cSrcweir             if (aEndBndry.startPos >= nEnd)
1704cdf0e10cSrcweir             {
1705cdf0e10cSrcweir                 aEndBndry = pBreakIt->GetBreakIter()->previousWord(
1706cdf0e10cSrcweir                         GetTxt(), aEndBndry.startPos,
1707cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
1708cdf0e10cSrcweir                         nWordType);
1709cdf0e10cSrcweir             }
1710cdf0e10cSrcweir 
1711cdf0e10cSrcweir             Boundary aCurWordBndry( aSttBndry );
1712cdf0e10cSrcweir             while (aCurWordBndry.startPos <= aEndBndry.startPos)
1713cdf0e10cSrcweir             {
1714cdf0e10cSrcweir                 nStt = (xub_StrLen)aCurWordBndry.startPos;
1715cdf0e10cSrcweir                 nEnd = (xub_StrLen)aCurWordBndry.endPos;
1716cdf0e10cSrcweir                 sal_Int32 nLen = nEnd - nStt;
1717cdf0e10cSrcweir                 DBG_ASSERT( nLen > 0, "invalid word length of 0" );
1718cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1719cdf0e10cSrcweir                 String aText( GetTxt().Copy( nStt, nLen ) );
1720cdf0e10cSrcweir #endif
1721cdf0e10cSrcweir 
1722cdf0e10cSrcweir 		        Sequence <sal_Int32> aOffsets;
1723cdf0e10cSrcweir                 String sChgd( rTrans.transliterate( GetTxt(), GetLang( nStt ), nStt, nLen, &aOffsets ));
1724cdf0e10cSrcweir 
1725cdf0e10cSrcweir                 if (!m_Text.Equals( sChgd, nStt, nLen ))
1726cdf0e10cSrcweir                 {
1727cdf0e10cSrcweir                     aChgData.nStart     = nStt;
1728cdf0e10cSrcweir                     aChgData.nLen       = nLen;
1729cdf0e10cSrcweir                     aChgData.sChanged   = sChgd;
1730cdf0e10cSrcweir                     aChgData.aOffsets   = aOffsets;
1731cdf0e10cSrcweir                     aChanges.push_back( aChgData );
1732cdf0e10cSrcweir                 }
1733cdf0e10cSrcweir 
1734cdf0e10cSrcweir                 aCurWordBndry = pBreakIt->GetBreakIter()->nextWord(
1735cdf0e10cSrcweir                         GetTxt(), nEnd,
1736cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nEnd ) ),
1737cdf0e10cSrcweir                         nWordType);
1738cdf0e10cSrcweir             }
1739cdf0e10cSrcweir         }
1740cdf0e10cSrcweir         else if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::SENTENCE_CASE)
1741cdf0e10cSrcweir         {
1742cdf0e10cSrcweir             // for 'sentence case' we need to iterate sentence by sentence
1743cdf0e10cSrcweir 
1744cdf0e10cSrcweir             sal_Int32 nLastStart = pBreakIt->GetBreakIter()->beginOfSentence(
1745cdf0e10cSrcweir                     GetTxt(), nEnd,
1746cdf0e10cSrcweir                     pBreakIt->GetLocale( GetLang( nEnd ) ) );
1747cdf0e10cSrcweir             sal_Int32 nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
1748cdf0e10cSrcweir                     GetTxt(), nLastStart,
1749cdf0e10cSrcweir                     pBreakIt->GetLocale( GetLang( nLastStart ) ) );
1750cdf0e10cSrcweir 
1751cdf0e10cSrcweir             // extend nStt, nEnd to the current sentence boundaries
1752cdf0e10cSrcweir             sal_Int32 nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
1753cdf0e10cSrcweir                     GetTxt(), nStt,
1754cdf0e10cSrcweir                     pBreakIt->GetLocale( GetLang( nStt ) ) );
1755cdf0e10cSrcweir             sal_Int32 nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1756cdf0e10cSrcweir                     GetTxt(), nCurrentStart,
1757cdf0e10cSrcweir                     pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1758cdf0e10cSrcweir 
1759cdf0e10cSrcweir             // prevent backtracking to the previous sentence if selection starts at end of a sentence
1760cdf0e10cSrcweir             if (nCurrentEnd <= nStt)
1761cdf0e10cSrcweir             {
1762cdf0e10cSrcweir                 // now nCurrentStart is probably located on a non-letter word. (unless we
1763cdf0e10cSrcweir                 // are in Asian text with no spaces...)
1764cdf0e10cSrcweir                 // Thus to get the real sentence start we should locate the next real word,
1765cdf0e10cSrcweir                 // that is one found by DICTIONARY_WORD
1766cdf0e10cSrcweir                 i18n::Boundary aBndry = pBreakIt->GetBreakIter()->nextWord(
1767cdf0e10cSrcweir                         GetTxt(), nCurrentEnd,
1768cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1769cdf0e10cSrcweir                         i18n::WordType::DICTIONARY_WORD);
1770cdf0e10cSrcweir 
1771cdf0e10cSrcweir                 // now get new current sentence boundaries
1772cdf0e10cSrcweir                 nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
1773cdf0e10cSrcweir                         GetTxt(), aBndry.startPos,
1774cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1775cdf0e10cSrcweir                 nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1776cdf0e10cSrcweir                         GetTxt(), nCurrentStart,
1777cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
1778cdf0e10cSrcweir             }
1779cdf0e10cSrcweir             // prevent advancing to the next sentence if selection ends at start of a sentence
1780cdf0e10cSrcweir             if (nLastStart >= nEnd)
1781cdf0e10cSrcweir             {
1782cdf0e10cSrcweir                 // now nCurrentStart is probably located on a non-letter word. (unless we
1783cdf0e10cSrcweir                 // are in Asian text with no spaces...)
1784cdf0e10cSrcweir                 // Thus to get the real sentence start we should locate the previous real word,
1785cdf0e10cSrcweir                 // that is one found by DICTIONARY_WORD
1786cdf0e10cSrcweir                 i18n::Boundary aBndry = pBreakIt->GetBreakIter()->previousWord(
1787cdf0e10cSrcweir                         GetTxt(), nLastStart,
1788cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nLastStart) ),
1789cdf0e10cSrcweir                         i18n::WordType::DICTIONARY_WORD);
1790cdf0e10cSrcweir                 nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
1791cdf0e10cSrcweir                         GetTxt(), aBndry.startPos,
1792cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1793cdf0e10cSrcweir                 if (nCurrentEnd > nLastEnd)
1794cdf0e10cSrcweir                     nCurrentEnd = nLastEnd;
1795cdf0e10cSrcweir             }
1796cdf0e10cSrcweir 
1797cdf0e10cSrcweir             while (nCurrentStart < nLastEnd)
1798cdf0e10cSrcweir             {
1799cdf0e10cSrcweir                 sal_Int32 nLen = nCurrentEnd - nCurrentStart;
1800cdf0e10cSrcweir                 DBG_ASSERT( nLen > 0, "invalid word length of 0" );
1801cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1802cdf0e10cSrcweir                 String aText( GetTxt().Copy( nCurrentStart, nLen ) );
1803cdf0e10cSrcweir #endif
1804cdf0e10cSrcweir 
1805cdf0e10cSrcweir 		        Sequence <sal_Int32> aOffsets;
1806cdf0e10cSrcweir                 String sChgd( rTrans.transliterate( GetTxt(),
1807cdf0e10cSrcweir                         GetLang( nCurrentStart ), nCurrentStart, nLen, &aOffsets ));
1808cdf0e10cSrcweir 
1809cdf0e10cSrcweir                 if (!m_Text.Equals( sChgd, nStt, nLen ))
1810cdf0e10cSrcweir                 {
1811cdf0e10cSrcweir                     aChgData.nStart     = nCurrentStart;
1812cdf0e10cSrcweir                     aChgData.nLen       = nLen;
1813cdf0e10cSrcweir                     aChgData.sChanged   = sChgd;
1814cdf0e10cSrcweir                     aChgData.aOffsets   = aOffsets;
1815cdf0e10cSrcweir                     aChanges.push_back( aChgData );
1816cdf0e10cSrcweir                 }
1817cdf0e10cSrcweir 
1818cdf0e10cSrcweir                 Boundary aFirstWordBndry;
1819cdf0e10cSrcweir                 aFirstWordBndry = pBreakIt->GetBreakIter()->nextWord(
1820cdf0e10cSrcweir                         GetTxt(), nCurrentEnd,
1821cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1822cdf0e10cSrcweir                         nWordType);
1823cdf0e10cSrcweir                 nCurrentStart = aFirstWordBndry.startPos;
1824cdf0e10cSrcweir                 nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1825cdf0e10cSrcweir                         GetTxt(), nCurrentStart,
1826cdf0e10cSrcweir                         pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1827cdf0e10cSrcweir             }
1828cdf0e10cSrcweir         }
1829cdf0e10cSrcweir         else
1830cdf0e10cSrcweir         {
1831cdf0e10cSrcweir             // here we may transliterate over complete language portions...
1832cdf0e10cSrcweir 
1833cdf0e10cSrcweir 		    SwLanguageIterator* pIter;
1834cdf0e10cSrcweir 		    if( rTrans.needLanguageForTheMode() )
1835cdf0e10cSrcweir                 pIter = new SwLanguageIterator( *this, nStt );
1836cdf0e10cSrcweir 		    else
1837cdf0e10cSrcweir 			    pIter = 0;
1838cdf0e10cSrcweir 
1839cdf0e10cSrcweir 		    xub_StrLen nEndPos;
1840cdf0e10cSrcweir 		    sal_uInt16 nLang;
1841cdf0e10cSrcweir 		    do {
1842cdf0e10cSrcweir 			    if( pIter )
1843cdf0e10cSrcweir 			    {
1844cdf0e10cSrcweir 				    nLang = pIter->GetLanguage();
1845cdf0e10cSrcweir 				    nEndPos = pIter->GetChgPos();
1846cdf0e10cSrcweir 				    if( nEndPos > nEnd )
1847cdf0e10cSrcweir 					    nEndPos = nEnd;
1848cdf0e10cSrcweir 			    }
1849cdf0e10cSrcweir 			    else
1850cdf0e10cSrcweir 			    {
1851cdf0e10cSrcweir 				    nLang = LANGUAGE_SYSTEM;
1852cdf0e10cSrcweir 				    nEndPos = nEnd;
1853cdf0e10cSrcweir 			    }
1854cdf0e10cSrcweir                 xub_StrLen nLen = nEndPos - nStt;
1855cdf0e10cSrcweir 
1856cdf0e10cSrcweir 			    Sequence <sal_Int32> aOffsets;
1857cdf0e10cSrcweir                 String sChgd( rTrans.transliterate( m_Text, nLang, nStt, nLen, &aOffsets ));
1858cdf0e10cSrcweir 
1859cdf0e10cSrcweir                 if (!m_Text.Equals( sChgd, nStt, nLen ))
1860cdf0e10cSrcweir                 {
1861cdf0e10cSrcweir                     aChgData.nStart     = nStt;
1862cdf0e10cSrcweir                     aChgData.nLen       = nLen;
1863cdf0e10cSrcweir                     aChgData.sChanged   = sChgd;
1864cdf0e10cSrcweir                     aChgData.aOffsets   = aOffsets;
1865cdf0e10cSrcweir                     aChanges.push_back( aChgData );
1866cdf0e10cSrcweir                 }
1867cdf0e10cSrcweir 
1868cdf0e10cSrcweir                 nStt = nEndPos;
1869cdf0e10cSrcweir 		    } while( nEndPos < nEnd && pIter && pIter->Next() );
1870cdf0e10cSrcweir 		    delete pIter;
1871cdf0e10cSrcweir         }
1872cdf0e10cSrcweir 
1873cdf0e10cSrcweir         if (aChanges.size() > 0)
1874cdf0e10cSrcweir         {
1875cdf0e10cSrcweir             // now apply the changes from end to start to leave the offsets of the
1876cdf0e10cSrcweir             // yet unchanged text parts remain the same.
1877cdf0e10cSrcweir             for (size_t i = 0; i < aChanges.size(); ++i)
1878cdf0e10cSrcweir             {
1879cdf0e10cSrcweir                 TransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ];
1880cdf0e10cSrcweir                 if (pUndo)
1881cdf0e10cSrcweir                     pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
1882cdf0e10cSrcweir                 ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
1883cdf0e10cSrcweir             }
1884cdf0e10cSrcweir         }
1885cdf0e10cSrcweir     }
1886cdf0e10cSrcweir }
1887cdf0e10cSrcweir 
1888cdf0e10cSrcweir 
ReplaceTextOnly(xub_StrLen nPos,xub_StrLen nLen,const XubString & rText,const Sequence<sal_Int32> & rOffsets)1889cdf0e10cSrcweir void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
1890cdf0e10cSrcweir 								const XubString& rText,
1891cdf0e10cSrcweir 								const Sequence<sal_Int32>& rOffsets )
1892cdf0e10cSrcweir {
1893cdf0e10cSrcweir     m_Text.Replace( nPos, nLen, rText );
1894cdf0e10cSrcweir 
1895cdf0e10cSrcweir 	xub_StrLen nTLen = rText.Len();
1896cdf0e10cSrcweir 	const sal_Int32* pOffsets = rOffsets.getConstArray();
1897cdf0e10cSrcweir 	// now look for no 1-1 mapping -> move the indizies!
1898cdf0e10cSrcweir 	xub_StrLen nI, nMyOff;
1899cdf0e10cSrcweir 	for( nI = 0, nMyOff = nPos; nI < nTLen; ++nI, ++nMyOff )
1900cdf0e10cSrcweir 	{
1901cdf0e10cSrcweir 		xub_StrLen nOff = (xub_StrLen)pOffsets[ nI ];
1902cdf0e10cSrcweir 		if( nOff < nMyOff )
1903cdf0e10cSrcweir 		{
1904cdf0e10cSrcweir 			// something is inserted
1905cdf0e10cSrcweir 			xub_StrLen nCnt = 1;
1906cdf0e10cSrcweir 			while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
1907cdf0e10cSrcweir 				++nCnt;
1908cdf0e10cSrcweir 
1909cdf0e10cSrcweir 			Update( SwIndex( this, nMyOff ), nCnt, sal_False );
1910cdf0e10cSrcweir 			nMyOff = nOff;
1911cdf0e10cSrcweir 			//nMyOff -= nCnt;
1912cdf0e10cSrcweir 			nI += nCnt - 1;
1913cdf0e10cSrcweir 		}
1914cdf0e10cSrcweir 		else if( nOff > nMyOff )
1915cdf0e10cSrcweir 		{
1916cdf0e10cSrcweir 			// something is deleted
1917cdf0e10cSrcweir 			Update( SwIndex( this, nMyOff+1 ), nOff - nMyOff, sal_True );
1918cdf0e10cSrcweir 			nMyOff = nOff;
1919cdf0e10cSrcweir 		}
1920cdf0e10cSrcweir 	}
1921cdf0e10cSrcweir 	if( nMyOff < nLen )
1922cdf0e10cSrcweir 		// something is deleted at the end
1923cdf0e10cSrcweir 		Update( SwIndex( this, nMyOff ), nLen - nMyOff, sal_True );
1924cdf0e10cSrcweir 
1925cdf0e10cSrcweir 	// notify the layout!
1926cdf0e10cSrcweir 	SwDelTxt aDelHint( nPos, nTLen );
1927cdf0e10cSrcweir 	NotifyClients( 0, &aDelHint );
1928cdf0e10cSrcweir 
1929cdf0e10cSrcweir 	SwInsTxt aHint( nPos, nTLen );
1930cdf0e10cSrcweir 	NotifyClients( 0, &aHint );
1931cdf0e10cSrcweir }
1932cdf0e10cSrcweir 
CountWords(SwDocStat & rStat,xub_StrLen nStt,xub_StrLen nEnd) const1933cdf0e10cSrcweir void SwTxtNode::CountWords( SwDocStat& rStat,
1934cdf0e10cSrcweir                             xub_StrLen nStt, xub_StrLen nEnd ) const
1935cdf0e10cSrcweir {
1936cdf0e10cSrcweir     ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
1937cdf0e10cSrcweir     if( nStt < nEnd )
1938cdf0e10cSrcweir     {
1939cdf0e10cSrcweir         if ( !IsHidden() )
1940cdf0e10cSrcweir         {
1941cdf0e10cSrcweir             ++rStat.nPara;
1942cdf0e10cSrcweir             sal_uLong nTmpWords = 0;
1943cdf0e10cSrcweir             sal_uLong nTmpChars = 0;
1944cdf0e10cSrcweir 
1945cdf0e10cSrcweir             // Shortcut: Whole paragraph should be considered and cached values
1946cdf0e10cSrcweir             // are valid:
1947cdf0e10cSrcweir             if ( 0 == nStt && GetTxt().Len() == nEnd && !IsWordCountDirty() )
1948cdf0e10cSrcweir             {
1949cdf0e10cSrcweir                 nTmpWords = GetParaNumberOfWords();
1950cdf0e10cSrcweir                 nTmpChars = GetParaNumberOfChars();
1951cdf0e10cSrcweir             }
1952cdf0e10cSrcweir             else
1953cdf0e10cSrcweir             {
1954cdf0e10cSrcweir                 String aOldStr( m_Text );
1955cdf0e10cSrcweir                 String& rCastStr = const_cast<String&>(m_Text);
1956cdf0e10cSrcweir 
1957cdf0e10cSrcweir                 // fills the deleted redlines and hidden ranges with cChar:
1958cdf0e10cSrcweir                 const xub_Unicode cChar(' ');
1959cdf0e10cSrcweir                 const sal_uInt16 nNumOfMaskedChars =
1960cdf0e10cSrcweir                         lcl_MaskRedlinesAndHiddenText( *this, rCastStr, nStt, nEnd, cChar, false );
1961cdf0e10cSrcweir 
1962cdf0e10cSrcweir                 // expand fields
1963cdf0e10cSrcweir                 rtl::OUString aExpandText;
1964cdf0e10cSrcweir                 const ModelToViewHelper::ConversionMap* pConversionMap =
1965cdf0e10cSrcweir                         BuildConversionMap( aExpandText );
1966cdf0e10cSrcweir 
1967cdf0e10cSrcweir                 const sal_uInt32 nExpandBegin = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nStt );
1968cdf0e10cSrcweir                 const sal_uInt32 nExpandEnd   = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nEnd );
196936b7696bSYang Shih-Ching                 aExpandText = aExpandText.copy( nExpandBegin, nExpandEnd - nExpandBegin );
1970cdf0e10cSrcweir 
1971cdf0e10cSrcweir                 const bool bCount = aExpandText.getLength() > 0;
1972cdf0e10cSrcweir 
1973cdf0e10cSrcweir                 // count words in 'regular' text:
1974cdf0e10cSrcweir                 if( bCount && pBreakIt->GetBreakIter().is() )
1975cdf0e10cSrcweir                 {
197636b7696bSYang Shih-Ching                     // split into different script languages
197736b7696bSYang Shih-Ching                     sal_Int32 nScriptBegin = 0;
197836b7696bSYang Shih-Ching                     while ( nScriptBegin < aExpandText.getLength() )
1979cdf0e10cSrcweir                     {
198036b7696bSYang Shih-Ching                         const sal_Int16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( aExpandText, nScriptBegin );
198136b7696bSYang Shih-Ching                         const sal_Int32 nScriptEnd = pBreakIt->GetBreakIter()->endOfScript( aExpandText, nScriptBegin, nCurrScript );
198236b7696bSYang Shih-Ching                         rtl::OUString aScriptText = aExpandText.copy( nScriptBegin, nScriptEnd - nScriptBegin );
198336b7696bSYang Shih-Ching 
198436b7696bSYang Shih-Ching                         // Asian languages count words as characters
198536b7696bSYang Shih-Ching                         if ( nCurrScript == ::com::sun::star::i18n::ScriptType::ASIAN )
198636b7696bSYang Shih-Ching                         {
198736b7696bSYang Shih-Ching                             // substract white spaces
198836b7696bSYang Shih-Ching                             sal_Int32 nSpaceCount = 0;
198936b7696bSYang Shih-Ching                             sal_Int32 nSpacePos = 0;
199036b7696bSYang Shih-Ching 
199136b7696bSYang Shih-Ching                             // substract normal white spaces
199236b7696bSYang Shih-Ching                             nSpacePos = -1;
199336b7696bSYang Shih-Ching                             while ( ( nSpacePos = aScriptText.indexOf( ' ', nSpacePos + 1 ) ) != -1 )
199436b7696bSYang Shih-Ching                             {
199536b7696bSYang Shih-Ching                                 nSpaceCount++;
199636b7696bSYang Shih-Ching                             }
199736b7696bSYang Shih-Ching                             // substract Asian full-width white spaces
199836b7696bSYang Shih-Ching                             nSpacePos = -1;
199936b7696bSYang Shih-Ching                             while ( ( nSpacePos = aScriptText.indexOf( 12288, nSpacePos + 1 ) ) != -1 )
200036b7696bSYang Shih-Ching                             {
200136b7696bSYang Shih-Ching                                 nSpaceCount++;
200236b7696bSYang Shih-Ching                             }
200336b7696bSYang Shih-Ching                             nTmpWords += nScriptEnd - nScriptBegin - nSpaceCount;
200436b7696bSYang Shih-Ching                         }
200536b7696bSYang Shih-Ching                         else
200636b7696bSYang Shih-Ching                         {
200736b7696bSYang Shih-Ching                             const String aScannerText( aScriptText );
200836b7696bSYang Shih-Ching                             SwScanner aScanner( *this, aScannerText, 0, pConversionMap,
200936b7696bSYang Shih-Ching                                                 i18n::WordType::WORD_COUNT,
201036b7696bSYang Shih-Ching                                                 (xub_StrLen)0, (xub_StrLen)aScriptText.getLength() );
201136b7696bSYang Shih-Ching 
201236b7696bSYang Shih-Ching                             const rtl::OUString aBreakWord( CH_TXTATR_BREAKWORD );
201336b7696bSYang Shih-Ching 
201436b7696bSYang Shih-Ching                             while ( aScanner.NextWord() )
201536b7696bSYang Shih-Ching                             {
201636b7696bSYang Shih-Ching                                 if ( aScanner.GetLen() > 1 ||
201736b7696bSYang Shih-Ching                                      CH_TXTATR_BREAKWORD != aScriptText.match(aBreakWord, aScanner.GetBegin() ) )
201836b7696bSYang Shih-Ching                                     ++nTmpWords;
201936b7696bSYang Shih-Ching                             }
202036b7696bSYang Shih-Ching                         }
202136b7696bSYang Shih-Ching                         nScriptBegin = nScriptEnd;
2022cdf0e10cSrcweir                     }
2023cdf0e10cSrcweir                 }
2024cdf0e10cSrcweir 
2025cdf0e10cSrcweir                 ASSERT( aExpandText.getLength() >= nNumOfMaskedChars,
2026cdf0e10cSrcweir                         "More characters hidden that characters in string!" )
2027cdf0e10cSrcweir                 nTmpChars = nExpandEnd - nExpandBegin - nNumOfMaskedChars;
2028cdf0e10cSrcweir 
2029cdf0e10cSrcweir                 // count words in numbering string:
2030cdf0e10cSrcweir                 if ( nStt == 0 && bCount )
2031cdf0e10cSrcweir                 {
2032cdf0e10cSrcweir                     // add numbering label
2033cdf0e10cSrcweir                     const String aNumString = GetNumString();
2034cdf0e10cSrcweir                     const xub_StrLen nNumStringLen = aNumString.Len();
2035cdf0e10cSrcweir                     if ( nNumStringLen > 0 )
2036cdf0e10cSrcweir                     {
2037cdf0e10cSrcweir                         LanguageType aLanguage = GetLang( 0 );
2038cdf0e10cSrcweir 
2039cdf0e10cSrcweir                         SwScanner aScanner( *this, aNumString, &aLanguage, 0,
2040cdf0e10cSrcweir                                             i18n::WordType::WORD_COUNT,
2041cdf0e10cSrcweir                                             0, nNumStringLen );
2042cdf0e10cSrcweir 
2043cdf0e10cSrcweir                         while ( aScanner.NextWord() )
2044cdf0e10cSrcweir                             ++nTmpWords;
2045cdf0e10cSrcweir 
2046cdf0e10cSrcweir                         nTmpChars += nNumStringLen;
2047cdf0e10cSrcweir                     }
2048cdf0e10cSrcweir                     else if ( HasBullet() )
2049cdf0e10cSrcweir                     {
2050cdf0e10cSrcweir                         ++nTmpWords;
2051cdf0e10cSrcweir                         ++nTmpChars;
2052cdf0e10cSrcweir                     }
2053cdf0e10cSrcweir                 }
2054cdf0e10cSrcweir 
2055cdf0e10cSrcweir                 delete pConversionMap;
2056cdf0e10cSrcweir 
2057cdf0e10cSrcweir                 rCastStr = aOldStr;
2058cdf0e10cSrcweir 
2059cdf0e10cSrcweir                 // If the whole paragraph has been calculated, update cached
2060cdf0e10cSrcweir                 // values:
2061cdf0e10cSrcweir                 if ( 0 == nStt && GetTxt().Len() == nEnd )
2062cdf0e10cSrcweir                 {
2063cdf0e10cSrcweir                     SetParaNumberOfWords( nTmpWords );
2064cdf0e10cSrcweir                     SetParaNumberOfChars( nTmpChars );
2065cdf0e10cSrcweir                     SetWordCountDirty( false );
2066cdf0e10cSrcweir                 }
2067cdf0e10cSrcweir             }
2068cdf0e10cSrcweir 
2069cdf0e10cSrcweir             rStat.nWord += nTmpWords;
2070cdf0e10cSrcweir             rStat.nChar += nTmpChars;
2071cdf0e10cSrcweir         }
2072cdf0e10cSrcweir     }
2073cdf0e10cSrcweir }
2074cdf0e10cSrcweir 
2075cdf0e10cSrcweir //
2076cdf0e10cSrcweir // Paragraph statistics start
2077cdf0e10cSrcweir //
2078cdf0e10cSrcweir struct SwParaIdleData_Impl
2079cdf0e10cSrcweir {
2080cdf0e10cSrcweir     SwWrongList* pWrong;            // for spell checking
2081cdf0e10cSrcweir     SwGrammarMarkUp* pGrammarCheck;     // for grammar checking /  proof reading
2082cdf0e10cSrcweir     SwWrongList* pSmartTags;
2083cdf0e10cSrcweir     sal_uLong nNumberOfWords;
2084cdf0e10cSrcweir     sal_uLong nNumberOfChars;
2085cdf0e10cSrcweir     bool bWordCountDirty        : 1;
2086cdf0e10cSrcweir     bool bWrongDirty            : 1;    // Ist das Wrong-Feld auf invalid?
2087cdf0e10cSrcweir     bool bGrammarCheckDirty     : 1;
2088cdf0e10cSrcweir     bool bSmartTagDirty         : 1;
2089cdf0e10cSrcweir     bool bAutoComplDirty        : 1;    // die ACompl-Liste muss angepasst werden
2090cdf0e10cSrcweir 
SwParaIdleData_ImplSwParaIdleData_Impl2091cdf0e10cSrcweir     SwParaIdleData_Impl() :
2092cdf0e10cSrcweir         pWrong              ( 0 ),
2093cdf0e10cSrcweir         pGrammarCheck       ( 0 ),
2094cdf0e10cSrcweir         pSmartTags          ( 0 ),
2095cdf0e10cSrcweir         nNumberOfWords      ( 0 ),
2096cdf0e10cSrcweir         nNumberOfChars      ( 0 ),
2097cdf0e10cSrcweir         bWordCountDirty     ( true ),
2098cdf0e10cSrcweir         bWrongDirty         ( true ),
2099cdf0e10cSrcweir         bGrammarCheckDirty  ( true ),
2100cdf0e10cSrcweir         bSmartTagDirty      ( true ),
2101cdf0e10cSrcweir         bAutoComplDirty     ( true ) {};
2102cdf0e10cSrcweir };
2103cdf0e10cSrcweir 
InitSwParaStatistics(bool bNew)2104cdf0e10cSrcweir void SwTxtNode::InitSwParaStatistics( bool bNew )
2105cdf0e10cSrcweir {
2106cdf0e10cSrcweir     if ( bNew )
2107cdf0e10cSrcweir     {
2108cdf0e10cSrcweir         m_pParaIdleData_Impl = new SwParaIdleData_Impl;
2109cdf0e10cSrcweir     }
2110cdf0e10cSrcweir     else if ( m_pParaIdleData_Impl )
2111cdf0e10cSrcweir     {
2112cdf0e10cSrcweir         delete m_pParaIdleData_Impl->pWrong;
2113cdf0e10cSrcweir         delete m_pParaIdleData_Impl->pGrammarCheck;
2114cdf0e10cSrcweir         delete m_pParaIdleData_Impl->pSmartTags;
2115cdf0e10cSrcweir         delete m_pParaIdleData_Impl;
2116cdf0e10cSrcweir         m_pParaIdleData_Impl = 0;
2117cdf0e10cSrcweir     }
2118cdf0e10cSrcweir }
2119cdf0e10cSrcweir 
SetWrong(SwWrongList * pNew,bool bDelete)2120cdf0e10cSrcweir void SwTxtNode::SetWrong( SwWrongList* pNew, bool bDelete )
2121cdf0e10cSrcweir {
2122cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2123cdf0e10cSrcweir     {
2124cdf0e10cSrcweir         if ( bDelete )
2125cdf0e10cSrcweir         {
2126cdf0e10cSrcweir             delete m_pParaIdleData_Impl->pWrong;
2127cdf0e10cSrcweir         }
2128cdf0e10cSrcweir         m_pParaIdleData_Impl->pWrong = pNew;
2129cdf0e10cSrcweir     }
2130cdf0e10cSrcweir }
2131cdf0e10cSrcweir 
GetWrong()2132cdf0e10cSrcweir SwWrongList* SwTxtNode::GetWrong()
2133cdf0e10cSrcweir {
2134cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
2135cdf0e10cSrcweir }
2136cdf0e10cSrcweir 
2137cdf0e10cSrcweir // --> OD 2008-05-27 #i71360#
GetWrong() const2138cdf0e10cSrcweir const SwWrongList* SwTxtNode::GetWrong() const
2139cdf0e10cSrcweir {
2140cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
2141cdf0e10cSrcweir }
2142cdf0e10cSrcweir // <--
2143cdf0e10cSrcweir 
2144cdf0e10cSrcweir 
SetGrammarCheck(SwGrammarMarkUp * pNew,bool bDelete)2145cdf0e10cSrcweir void SwTxtNode::SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete )
2146cdf0e10cSrcweir {
2147cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2148cdf0e10cSrcweir     {
2149cdf0e10cSrcweir         if ( bDelete )
2150cdf0e10cSrcweir         {
2151cdf0e10cSrcweir             delete m_pParaIdleData_Impl->pGrammarCheck;
2152cdf0e10cSrcweir         }
2153cdf0e10cSrcweir         m_pParaIdleData_Impl->pGrammarCheck = pNew;
2154cdf0e10cSrcweir     }
2155cdf0e10cSrcweir }
2156cdf0e10cSrcweir 
GetGrammarCheck()2157cdf0e10cSrcweir SwGrammarMarkUp* SwTxtNode::GetGrammarCheck()
2158cdf0e10cSrcweir {
2159cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : 0;
2160cdf0e10cSrcweir }
2161cdf0e10cSrcweir 
SetSmartTags(SwWrongList * pNew,bool bDelete)2162cdf0e10cSrcweir void SwTxtNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
2163cdf0e10cSrcweir {
2164cdf0e10cSrcweir     ASSERT( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
2165cdf0e10cSrcweir             "Weird - we have a smart tag list without any recognizers?" )
2166cdf0e10cSrcweir 
2167cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2168cdf0e10cSrcweir     {
2169cdf0e10cSrcweir         if ( bDelete )
2170cdf0e10cSrcweir         {
2171cdf0e10cSrcweir             delete m_pParaIdleData_Impl->pSmartTags;
2172cdf0e10cSrcweir         }
2173cdf0e10cSrcweir         m_pParaIdleData_Impl->pSmartTags = pNew;
2174cdf0e10cSrcweir     }
2175cdf0e10cSrcweir }
2176cdf0e10cSrcweir 
GetSmartTags()2177cdf0e10cSrcweir SwWrongList* SwTxtNode::GetSmartTags()
2178cdf0e10cSrcweir {
2179cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : 0;
2180cdf0e10cSrcweir }
2181cdf0e10cSrcweir 
SetParaNumberOfWords(sal_uLong nNew) const2182cdf0e10cSrcweir void SwTxtNode::SetParaNumberOfWords( sal_uLong nNew ) const
2183cdf0e10cSrcweir {
2184cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2185cdf0e10cSrcweir     {
2186cdf0e10cSrcweir         m_pParaIdleData_Impl->nNumberOfWords = nNew;
2187cdf0e10cSrcweir     }
2188cdf0e10cSrcweir }
GetParaNumberOfWords() const2189cdf0e10cSrcweir sal_uLong SwTxtNode::GetParaNumberOfWords() const
2190cdf0e10cSrcweir {
2191cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfWords : 0;
2192cdf0e10cSrcweir }
SetParaNumberOfChars(sal_uLong nNew) const2193cdf0e10cSrcweir void SwTxtNode::SetParaNumberOfChars( sal_uLong nNew ) const
2194cdf0e10cSrcweir {
2195cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2196cdf0e10cSrcweir     {
2197cdf0e10cSrcweir         m_pParaIdleData_Impl->nNumberOfChars = nNew;
2198cdf0e10cSrcweir     }
2199cdf0e10cSrcweir }
GetParaNumberOfChars() const2200cdf0e10cSrcweir sal_uLong SwTxtNode::GetParaNumberOfChars() const
2201cdf0e10cSrcweir {
2202cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfChars : 0;
2203cdf0e10cSrcweir }
SetWordCountDirty(bool bNew) const2204cdf0e10cSrcweir void SwTxtNode::SetWordCountDirty( bool bNew ) const
2205cdf0e10cSrcweir {
2206cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2207cdf0e10cSrcweir     {
2208cdf0e10cSrcweir         m_pParaIdleData_Impl->bWordCountDirty = bNew;
2209cdf0e10cSrcweir     }
2210cdf0e10cSrcweir }
IsWordCountDirty() const2211cdf0e10cSrcweir bool SwTxtNode::IsWordCountDirty() const
2212cdf0e10cSrcweir {
2213cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWordCountDirty : 0;
2214cdf0e10cSrcweir }
SetWrongDirty(bool bNew) const2215cdf0e10cSrcweir void SwTxtNode::SetWrongDirty( bool bNew ) const
2216cdf0e10cSrcweir {
2217cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2218cdf0e10cSrcweir     {
2219cdf0e10cSrcweir         m_pParaIdleData_Impl->bWrongDirty = bNew;
2220cdf0e10cSrcweir     }
2221cdf0e10cSrcweir }
IsWrongDirty() const2222cdf0e10cSrcweir bool SwTxtNode::IsWrongDirty() const
2223cdf0e10cSrcweir {
2224cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWrongDirty : 0;
2225cdf0e10cSrcweir }
SetGrammarCheckDirty(bool bNew) const2226cdf0e10cSrcweir void SwTxtNode::SetGrammarCheckDirty( bool bNew ) const
2227cdf0e10cSrcweir {
2228cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2229cdf0e10cSrcweir     {
2230cdf0e10cSrcweir         m_pParaIdleData_Impl->bGrammarCheckDirty = bNew;
2231cdf0e10cSrcweir     }
2232cdf0e10cSrcweir }
IsGrammarCheckDirty() const2233cdf0e10cSrcweir bool SwTxtNode::IsGrammarCheckDirty() const
2234cdf0e10cSrcweir {
2235cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bGrammarCheckDirty : 0;
2236cdf0e10cSrcweir }
SetSmartTagDirty(bool bNew) const2237cdf0e10cSrcweir void SwTxtNode::SetSmartTagDirty( bool bNew ) const
2238cdf0e10cSrcweir {
2239cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2240cdf0e10cSrcweir     {
2241cdf0e10cSrcweir         m_pParaIdleData_Impl->bSmartTagDirty = bNew;
2242cdf0e10cSrcweir     }
2243cdf0e10cSrcweir }
IsSmartTagDirty() const2244cdf0e10cSrcweir bool SwTxtNode::IsSmartTagDirty() const
2245cdf0e10cSrcweir {
2246cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bSmartTagDirty : 0;
2247cdf0e10cSrcweir }
SetAutoCompleteWordDirty(bool bNew) const2248cdf0e10cSrcweir void SwTxtNode::SetAutoCompleteWordDirty( bool bNew ) const
2249cdf0e10cSrcweir {
2250cdf0e10cSrcweir     if ( m_pParaIdleData_Impl )
2251cdf0e10cSrcweir     {
2252cdf0e10cSrcweir         m_pParaIdleData_Impl->bAutoComplDirty = bNew;
2253cdf0e10cSrcweir     }
2254cdf0e10cSrcweir }
IsAutoCompleteWordDirty() const2255cdf0e10cSrcweir bool SwTxtNode::IsAutoCompleteWordDirty() const
2256cdf0e10cSrcweir {
2257cdf0e10cSrcweir     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bAutoComplDirty : 0;
2258cdf0e10cSrcweir }
2259cdf0e10cSrcweir //
2260cdf0e10cSrcweir // Paragraph statistics end
2261cdf0e10cSrcweir //
226291100364SJian Hong Cheng 
226391100364SJian Hong Cheng //Bug 120881:Modify here for Directly Page Numbering
HasPageNumberField()226491100364SJian Hong Cheng sal_Bool SwTxtFrm::HasPageNumberField()
226591100364SJian Hong Cheng {
226691100364SJian Hong Cheng 	return GetRegisteredIn()?((SwTxtNode*)GetRegisteredIn())->HasPageNumberField():false;
226791100364SJian Hong Cheng }
226891100364SJian Hong Cheng //Bug 120881(End)
226991100364SJian Hong Cheng 
2270