Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <hintids.hxx>
22 : #include <vcl/svapp.hxx>
23 : #include <svl/itemiter.hxx>
24 : #include <editeng/splwrap.hxx>
25 : #include <editeng/langitem.hxx>
26 : #include <editeng/fontitem.hxx>
27 : #include <editeng/scripttypeitem.hxx>
28 : #include <editeng/hangulhanja.hxx>
29 : #include <SwSmartTagMgr.hxx>
30 : #include <linguistic/lngprops.hxx>
31 : #include <officecfg/Office/Writer.hxx>
32 : #include <unotools/transliterationwrapper.hxx>
33 : #include <unotools/charclass.hxx>
34 : #include <dlelstnr.hxx>
35 : #include <swmodule.hxx>
36 : #include <splargs.hxx>
37 : #include <viewopt.hxx>
38 : #include <acmplwrd.hxx>
39 : #include <doc.hxx> // GetDoc()
40 : #include <docsh.hxx>
41 : #include <txtfld.hxx>
42 : #include <fmtfld.hxx>
43 : #include <txatbase.hxx>
44 : #include <charatr.hxx>
45 : #include <fldbas.hxx>
46 : #include <pam.hxx>
47 : #include <hints.hxx>
48 : #include <ndtxt.hxx>
49 : #include <txtfrm.hxx>
50 : #include <SwGrammarMarkUp.hxx>
51 :
52 : #include <txttypes.hxx>
53 : #include <breakit.hxx>
54 : #include <crstate.hxx>
55 : #include <UndoOverwrite.hxx>
56 : #include <txatritr.hxx>
57 : #include <redline.hxx> // SwRedline
58 : #include <docary.hxx> // SwRedlineTbl
59 : #include <scriptinfo.hxx>
60 : #include <docstat.hxx>
61 : #include <editsh.hxx>
62 : #include <unotextmarkup.hxx>
63 : #include <txtatr.hxx>
64 : #include <fmtautofmt.hxx>
65 : #include <istyleaccess.hxx>
66 : #include <unicode/uchar.h>
67 :
68 : #include <unomid.h>
69 :
70 : #include <com/sun/star/beans/XPropertySet.hpp>
71 : #include <com/sun/star/i18n/WordType.hpp>
72 : #include <com/sun/star/i18n/ScriptType.hpp>
73 : #include <com/sun/star/i18n/TransliterationModules.hpp>
74 : #include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
75 :
76 : #include <vector>
77 :
78 : using rtl::OUString;
79 : using namespace ::com::sun::star;
80 : using namespace ::com::sun::star::frame;
81 : using namespace ::com::sun::star::i18n;
82 : using namespace ::com::sun::star::beans;
83 : using namespace ::com::sun::star::uno;
84 : using namespace ::com::sun::star::linguistic2;
85 : using namespace ::com::sun::star::smarttags;
86 :
87 : // Wir ersparen uns in Hyphenate ein GetFrm()
88 : // Achtung: in edlingu.cxx stehen die Variablen!
89 : extern const SwTxtNode *pLinguNode;
90 : extern SwTxtFrm *pLinguFrm;
91 :
92 : /*
93 : * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
94 : * only for deleted redlines
95 : */
96 :
97 500 : static sal_uInt16 lcl_MaskRedlines( const SwTxtNode& rNode, XubString& rText,
98 : const xub_StrLen nStt, const xub_StrLen nEnd,
99 : const sal_Unicode cChar )
100 : {
101 500 : sal_uInt16 nNumOfMaskedRedlines = 0;
102 :
103 500 : const SwDoc& rDoc = *rNode.GetDoc();
104 500 : sal_uInt16 nAct = rDoc.GetRedlinePos( rNode, USHRT_MAX );
105 :
106 500 : for ( ; nAct < rDoc.GetRedlineTbl().size(); nAct++ )
107 : {
108 0 : const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
109 :
110 0 : if ( pRed->Start()->nNode > rNode.GetIndex() )
111 0 : break;
112 :
113 0 : if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
114 : {
115 : xub_StrLen nRedlineEnd;
116 : xub_StrLen nRedlineStart;
117 :
118 0 : pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
119 :
120 0 : if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
121 0 : continue;
122 :
123 0 : while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
124 : {
125 0 : if ( nRedlineStart >= nStt && nRedlineStart < nEnd )
126 : {
127 0 : rText.SetChar( nRedlineStart, cChar );
128 0 : ++nNumOfMaskedRedlines;
129 : }
130 0 : ++nRedlineStart;
131 : }
132 : }
133 : }
134 :
135 500 : return nNumOfMaskedRedlines;
136 : }
137 :
138 : /*
139 : * Used for spell checking. Deleted redlines and hidden characters are masked
140 : */
141 :
142 500 : static sal_uInt16 lcl_MaskRedlinesAndHiddenText( const SwTxtNode& rNode, XubString& rText,
143 : const xub_StrLen nStt, const xub_StrLen nEnd,
144 : const sal_Unicode cChar = CH_TXTATR_INWORD,
145 : bool bCheckShowHiddenChar = true )
146 : {
147 500 : sal_uInt16 nRedlinesMasked = 0;
148 500 : sal_uInt16 nHiddenCharsMasked = 0;
149 :
150 500 : const SwDoc& rDoc = *rNode.GetDoc();
151 500 : const bool bShowChg = 0 != IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
152 :
153 : // If called from word count or from spell checking, deleted redlines
154 : // should be masked:
155 500 : if ( bShowChg )
156 : {
157 500 : nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
158 : }
159 :
160 500 : const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.get(IDocumentSettingAccess::HTML_MODE))->IsShowHiddenChar();
161 :
162 : // If called from word count, we want to mask the hidden ranges even
163 : // if they are visible:
164 500 : if ( !bCheckShowHiddenChar || bHideHidden )
165 : {
166 : nHiddenCharsMasked =
167 500 : SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
168 : }
169 :
170 500 : return nRedlinesMasked + nHiddenCharsMasked;
171 : }
172 :
173 : /*
174 : * Used for spell checking. Calculates a rectangle for repaint.
175 : */
176 :
177 0 : static SwRect lcl_CalculateRepaintRect( SwTxtFrm& rTxtFrm, xub_StrLen nChgStart, xub_StrLen nChgEnd )
178 : {
179 0 : SwRect aRect;
180 :
181 0 : SwTxtNode *pNode = rTxtFrm.GetTxtNode();
182 :
183 0 : SwNodeIndex aNdIdx( *pNode );
184 0 : SwPosition aPos( aNdIdx, SwIndex( pNode, nChgEnd ) );
185 0 : SwCrsrMoveState aTmpState( MV_NONE );
186 0 : aTmpState.b2Lines = sal_True;
187 0 : rTxtFrm.GetCharRect( aRect, aPos, &aTmpState );
188 : // information about end of repaint area
189 0 : Sw2LinesPos* pEnd2Pos = aTmpState.p2Lines;
190 :
191 0 : const SwTxtFrm *pEndFrm = &rTxtFrm;
192 :
193 0 : while( pEndFrm->HasFollow() &&
194 0 : nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
195 0 : pEndFrm = pEndFrm->GetFollow();
196 :
197 0 : if ( pEnd2Pos )
198 : {
199 : // we are inside a special portion, take left border
200 0 : SWRECTFN( pEndFrm )
201 0 : (aRect.*fnRect->fnSetTop)( (pEnd2Pos->aLine.*fnRect->fnGetTop)() );
202 0 : if ( pEndFrm->IsRightToLeft() )
203 0 : (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetLeft)() );
204 : else
205 0 : (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetRight)() );
206 0 : (aRect.*fnRect->fnSetWidth)( 1 );
207 0 : (aRect.*fnRect->fnSetHeight)( (pEnd2Pos->aLine.*fnRect->fnGetHeight)() );
208 0 : delete pEnd2Pos;
209 : }
210 :
211 0 : aTmpState.p2Lines = NULL;
212 0 : SwRect aTmp;
213 0 : aPos = SwPosition( aNdIdx, SwIndex( pNode, nChgStart ) );
214 0 : rTxtFrm.GetCharRect( aTmp, aPos, &aTmpState );
215 :
216 : // i63141: GetCharRect(..) could cause a formatting,
217 : // during the formatting SwTxtFrms could be joined, deleted, created...
218 : // => we have to reinit pStartFrm and pEndFrm after the formatting
219 0 : const SwTxtFrm* pStartFrm = &rTxtFrm;
220 0 : while( pStartFrm->HasFollow() &&
221 0 : nChgStart >= pStartFrm->GetFollow()->GetOfst() )
222 0 : pStartFrm = pStartFrm->GetFollow();
223 0 : pEndFrm = pStartFrm;
224 0 : while( pEndFrm->HasFollow() &&
225 0 : nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
226 0 : pEndFrm = pEndFrm->GetFollow();
227 :
228 : // information about start of repaint area
229 0 : Sw2LinesPos* pSt2Pos = aTmpState.p2Lines;
230 0 : if ( pSt2Pos )
231 : {
232 : // we are inside a special portion, take right border
233 0 : SWRECTFN( pStartFrm )
234 0 : (aTmp.*fnRect->fnSetTop)( (pSt2Pos->aLine.*fnRect->fnGetTop)() );
235 0 : if ( pStartFrm->IsRightToLeft() )
236 0 : (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
237 : else
238 0 : (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
239 0 : (aTmp.*fnRect->fnSetWidth)( 1 );
240 0 : (aTmp.*fnRect->fnSetHeight)( (pSt2Pos->aLine.*fnRect->fnGetHeight)() );
241 0 : delete pSt2Pos;
242 : }
243 :
244 0 : bool bSameFrame = true;
245 :
246 0 : if( rTxtFrm.HasFollow() )
247 : {
248 0 : if( pEndFrm != pStartFrm )
249 : {
250 0 : bSameFrame = false;
251 0 : SwRect aStFrm( pStartFrm->PaintArea() );
252 : {
253 0 : SWRECTFN( pStartFrm )
254 0 : (aTmp.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
255 0 : (aTmp.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
256 0 : (aTmp.*fnRect->fnSetBottom)( (aStFrm.*fnRect->fnGetBottom)() );
257 : }
258 0 : aStFrm = pEndFrm->PaintArea();
259 : {
260 0 : SWRECTFN( pEndFrm )
261 0 : (aRect.*fnRect->fnSetTop)( (aStFrm.*fnRect->fnGetTop)() );
262 0 : (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
263 0 : (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
264 : }
265 0 : aRect.Union( aTmp );
266 0 : while( true )
267 : {
268 0 : pStartFrm = pStartFrm->GetFollow();
269 0 : if( pStartFrm == pEndFrm )
270 0 : break;
271 0 : aRect.Union( pStartFrm->PaintArea() );
272 : }
273 : }
274 : }
275 0 : if( bSameFrame )
276 : {
277 0 : SWRECTFN( pStartFrm )
278 0 : if( (aTmp.*fnRect->fnGetTop)() == (aRect.*fnRect->fnGetTop)() )
279 0 : (aRect.*fnRect->fnSetLeft)( (aTmp.*fnRect->fnGetLeft)() );
280 : else
281 : {
282 0 : SwRect aStFrm( pStartFrm->PaintArea() );
283 0 : (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
284 0 : (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
285 0 : (aRect.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetTop)() );
286 : }
287 :
288 0 : if( aTmp.Height() > aRect.Height() )
289 0 : aRect.Height( aTmp.Height() );
290 : }
291 :
292 0 : return aRect;
293 : }
294 :
295 : /*
296 : * Used for automatic styles. Used during RstAttr.
297 : */
298 :
299 1844 : static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
300 : const SfxItemSet* pSet1,
301 : sal_uInt16 nWhichId,
302 : const SfxItemSet& rSet2,
303 : boost::shared_ptr<SfxItemSet>& pStyleHandle )
304 : {
305 1844 : bool bRet = false;
306 :
307 1844 : SfxItemSet* pNewSet = 0;
308 :
309 1844 : if ( !pSet1 )
310 : {
311 : OSL_ENSURE( nWhichId, "lcl_HaveCommonAttributes not used correctly" );
312 0 : if ( SFX_ITEM_SET == rSet2.GetItemState( nWhichId, sal_False ) )
313 : {
314 0 : pNewSet = rSet2.Clone( sal_True );
315 0 : pNewSet->ClearItem( nWhichId );
316 : }
317 : }
318 1844 : else if ( pSet1->Count() )
319 : {
320 1844 : SfxItemIter aIter( *pSet1 );
321 1844 : const SfxPoolItem* pItem = aIter.GetCurItem();
322 0 : while( true )
323 : {
324 1844 : if ( SFX_ITEM_SET == rSet2.GetItemState( pItem->Which(), sal_False ) )
325 : {
326 472 : if ( !pNewSet )
327 472 : pNewSet = rSet2.Clone( sal_True );
328 472 : pNewSet->ClearItem( pItem->Which() );
329 : }
330 :
331 1844 : if( aIter.IsAtEnd() )
332 1844 : break;
333 :
334 0 : pItem = aIter.NextItem();
335 1844 : }
336 : }
337 :
338 1844 : if ( pNewSet )
339 : {
340 472 : if ( pNewSet->Count() )
341 429 : pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
342 472 : delete pNewSet;
343 472 : bRet = true;
344 : }
345 :
346 1844 : return bRet;
347 : }
348 :
349 : /*
350 : * void SwTxtNode::RstAttr(const SwIndex &rIdx, sal_uInt16 nLen)
351 : *
352 : * Deletes all attributes, starting at position rIdx, for length nLen.
353 : */
354 :
355 : /* 5 cases:
356 : * 1) The attribute is completely in the deletion range:
357 : * -> delete it
358 : * 2) The end of the attribute is in the deletion range:
359 : * -> delete it, then re-insert it with new end
360 : * 3) The start of the attribute is in the deletion range:
361 : * -> delete it, then re-insert it with new start
362 : * 4) The attribute contains the deletion range:
363 : * Split, i.e.,
364 : * -> Delete, re-insert from old start to start of deletion range
365 : * -> insert new attribute from end of deletion range to old end
366 : * 5) The attribute is outside the deletion range
367 : * -> nothing to do
368 : */
369 :
370 1422 : void SwTxtNode::RstAttr(const SwIndex &rIdx, xub_StrLen nLen, sal_uInt16 nWhich,
371 : const SfxItemSet* pSet, sal_Bool bInclRefToxMark )
372 : {
373 : // Attribute?
374 1422 : if ( !GetpSwpHints() )
375 1422 : return;
376 :
377 1422 : sal_uInt16 i = 0;
378 1422 : xub_StrLen nStt = rIdx.GetIndex();
379 1422 : xub_StrLen nEnd = nStt + nLen;
380 : xub_StrLen nAttrStart;
381 : SwTxtAttr *pHt;
382 :
383 1422 : bool bChanged = false;
384 :
385 : // nMin and nMax initialized to maximum / minimum (inverse)
386 1422 : xub_StrLen nMin = m_Text.Len();
387 1422 : xub_StrLen nMax = nStt;
388 :
389 1422 : const bool bNoLen = !nMin;
390 :
391 : // We have to remember the "new" attributes, which have
392 : // been introduced by splitting surrounding attributes (case 4).
393 : // They may not be forgotten inside the "Forget" function
394 : //std::vector< const SwTxtAttr* > aNewAttributes;
395 :
396 : // iterate over attribute array until start of attribute is behind
397 : // deletion range
398 6636 : while ((i < m_pSwpHints->Count()) &&
399 1896 : ((( nAttrStart = *(*m_pSwpHints)[i]->GetStart()) < nEnd ) || nLen==0) )
400 : {
401 1896 : pHt = m_pSwpHints->GetTextHint(i);
402 :
403 : // attributes without end stay in!
404 1896 : xub_StrLen * const pAttrEnd = pHt->GetEnd();
405 1896 : if ( !pAttrEnd /*|| pHt->HasDummyChar()*/ ) // see bInclRefToxMark
406 : {
407 47 : i++;
408 47 : continue;
409 : }
410 :
411 : // Default behavior is to process all attributes:
412 1849 : bool bSkipAttr = false;
413 1849 : boost::shared_ptr<SfxItemSet> pStyleHandle;
414 :
415 : // 1. case: We want to reset only the attributes listed in pSet:
416 1849 : if ( pSet )
417 : {
418 1849 : bSkipAttr = SFX_ITEM_SET != pSet->GetItemState( pHt->Which(), sal_False );
419 1849 : if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
420 : {
421 : // if the current attribute is an autostyle, we have to check if the autostyle
422 : // and pSet have any attributes in common. If so, pStyleHandle will contain
423 : // a handle to AutoStyle / pSet:
424 1844 : bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
425 : }
426 : }
427 0 : else if ( nWhich )
428 : {
429 : // 2. case: We want to reset only the attributes with WhichId nWhich:
430 0 : bSkipAttr = nWhich != pHt->Which();
431 0 : if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
432 : {
433 0 : bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), 0, nWhich, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
434 : }
435 : }
436 0 : else if ( !bInclRefToxMark )
437 : {
438 : // 3. case: Reset all attributes except from ref/toxmarks:
439 : // skip hints with CH_TXTATR here
440 : // (deleting those is ONLY allowed for UNDO!)
441 0 : bSkipAttr = RES_TXTATR_REFMARK == pHt->Which()
442 0 : || RES_TXTATR_TOXMARK == pHt->Which()
443 0 : || RES_TXTATR_META == pHt->Which()
444 0 : || RES_TXTATR_METAFIELD == pHt->Which();
445 : }
446 :
447 1849 : if ( bSkipAttr )
448 : {
449 1375 : i++;
450 1375 : continue;
451 : }
452 :
453 474 : if( nStt <= nAttrStart ) // Faelle: 1,3,5
454 : {
455 474 : if( nEnd > nAttrStart
456 : || ( nEnd == *pAttrEnd && nEnd==nAttrStart ) )
457 : {
458 : // Faelle: 1,3
459 474 : if ( nMin > nAttrStart )
460 474 : nMin = nAttrStart;
461 474 : if ( nMax < *pAttrEnd )
462 458 : nMax = *pAttrEnd;
463 : // Falls wir nur ein nichtaufgespanntes Attribut entfernen,
464 : // tun wir mal so, als ob sich nichts geaendert hat.
465 474 : bChanged = bChanged || nEnd > nAttrStart || bNoLen;
466 474 : if( *pAttrEnd <= nEnd ) // Fall: 1
467 : {
468 474 : const xub_StrLen nAttrEnd = *pAttrEnd;
469 :
470 474 : m_pSwpHints->DeleteAtPos(i);
471 474 : DestroyAttr( pHt );
472 :
473 474 : if ( pStyleHandle.get() )
474 : {
475 429 : SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
476 858 : *pStyleHandle, nAttrStart, nAttrEnd );
477 429 : InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
478 : }
479 :
480 : // if the last attribute is a Field, the HintsArray is
481 : // deleted!
482 474 : if ( !m_pSwpHints )
483 : break;
484 :
485 : //JP 26.11.96:
486 : // beim DeleteAtPos wird ein Resort ausgefuehrt!!
487 : // darum muessen wir wieder bei 0 anfangen!!!
488 : // ueber den Fall 3 koennen Attribute nach hinten
489 : // verschoben worden sein; damit stimmt jetzt das i
490 : // nicht mehr!!!
491 474 : i = 0;
492 :
493 474 : continue;
494 : }
495 : else // Fall: 3
496 : {
497 0 : m_pSwpHints->NoteInHistory( pHt );
498 0 : *pHt->GetStart() = nEnd;
499 0 : m_pSwpHints->NoteInHistory( pHt, sal_True );
500 :
501 0 : if ( pStyleHandle.get() && nAttrStart < nEnd )
502 : {
503 0 : SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
504 0 : *pStyleHandle, nAttrStart, nEnd );
505 0 : InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
506 : }
507 :
508 0 : bChanged = true;
509 : }
510 : }
511 : }
512 : else // Faelle: 2,4,5
513 0 : if( *pAttrEnd > nStt ) // Faelle: 2,4
514 : {
515 0 : if( *pAttrEnd < nEnd ) // Fall: 2
516 : {
517 0 : if ( nMin > nAttrStart )
518 0 : nMin = nAttrStart;
519 0 : if ( nMax < *pAttrEnd )
520 0 : nMax = *pAttrEnd;
521 0 : bChanged = true;
522 :
523 0 : const xub_StrLen nAttrEnd = *pAttrEnd;
524 :
525 0 : m_pSwpHints->NoteInHistory( pHt );
526 0 : *pAttrEnd = nStt;
527 0 : m_pSwpHints->NoteInHistory( pHt, sal_True );
528 :
529 0 : if ( pStyleHandle.get() )
530 : {
531 0 : SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
532 0 : *pStyleHandle, nStt, nAttrEnd );
533 0 : InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
534 : }
535 : }
536 0 : else if( nLen ) // Fall: 4
537 : { // bei Lange 0 werden beide Hints vom Insert(Ht)
538 : // wieder zu einem zusammengezogen !!!!
539 0 : if ( nMin > nAttrStart )
540 0 : nMin = nAttrStart;
541 0 : if ( nMax < *pAttrEnd )
542 0 : nMax = *pAttrEnd;
543 0 : bChanged = true;
544 0 : xub_StrLen nTmpEnd = *pAttrEnd;
545 0 : m_pSwpHints->NoteInHistory( pHt );
546 0 : *pAttrEnd = nStt;
547 0 : m_pSwpHints->NoteInHistory( pHt, sal_True );
548 :
549 0 : if ( pStyleHandle.get() && nStt < nEnd )
550 : {
551 0 : SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
552 0 : *pStyleHandle, nStt, nEnd );
553 0 : InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
554 : }
555 :
556 0 : if( nEnd < nTmpEnd )
557 : {
558 0 : SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
559 0 : pHt->GetAttr(), nEnd, nTmpEnd );
560 0 : if ( pNew )
561 : {
562 0 : SwTxtCharFmt* pCharFmt = dynamic_cast<SwTxtCharFmt*>(pHt);
563 0 : if ( pCharFmt )
564 0 : static_cast<SwTxtCharFmt*>(pNew)->SetSortNumber( pCharFmt->GetSortNumber() );
565 :
566 : InsertHint( pNew,
567 0 : nsSetAttrMode::SETATTR_NOHINTADJUST );
568 : }
569 :
570 : // jetzt kein i+1, weil das eingefuegte Attribut
571 : // ein anderes auf die Position geschoben hat !
572 0 : continue;
573 : }
574 : }
575 : }
576 0 : ++i;
577 1849 : }
578 :
579 1422 : TryDeleteSwpHints();
580 1422 : if (bChanged)
581 : {
582 474 : if ( HasHints() )
583 : {
584 429 : m_pSwpHints->Resort();
585 : }
586 : //TxtFrm's reagieren auf aHint, andere auf aNew
587 474 : SwUpdateAttr aHint( nMin, nMax, 0 );
588 474 : NotifyClients( 0, &aHint );
589 474 : SwFmtChg aNew( GetFmtColl() );
590 474 : NotifyClients( 0, &aNew );
591 : }
592 : }
593 :
594 : /*************************************************************************
595 : * SwTxtNode::GetCurWord()
596 : *
597 : * Aktuelles Wort zurueckliefern:
598 : * Wir suchen immer von links nach rechts, es wird also das Wort
599 : * vor nPos gesucht. Es sei denn, wir befinden uns am Anfang des
600 : * Absatzes, dann wird das erste Wort zurueckgeliefert.
601 : * Wenn dieses erste Wort nur aus Whitespaces besteht, returnen wir
602 : * einen leeren String.
603 : *************************************************************************/
604 :
605 0 : XubString SwTxtNode::GetCurWord( xub_StrLen nPos ) const
606 : {
607 : OSL_ENSURE( nPos <= m_Text.Len(), "SwTxtNode::GetCurWord: invalid index." );
608 :
609 0 : if (!m_Text.Len())
610 0 : return m_Text;
611 :
612 0 : Boundary aBndry;
613 0 : const uno::Reference< XBreakIterator > &rxBreak = pBreakIt->GetBreakIter();
614 0 : if (rxBreak.is())
615 : {
616 0 : sal_Int16 nWordType = WordType::DICTIONARY_WORD;
617 0 : lang::Locale aLocale( pBreakIt->GetLocale( GetLang( nPos ) ) );
618 : #if OSL_DEBUG_LEVEL > 1
619 : sal_Bool bBegin = rxBreak->isBeginWord( m_Text, nPos, aLocale, nWordType );
620 : sal_Bool bEnd = rxBreak->isEndWord ( m_Text, nPos, aLocale, nWordType );
621 : (void)bBegin;
622 : (void)bEnd;
623 : #endif
624 : aBndry =
625 0 : rxBreak->getWordBoundary( m_Text, nPos, aLocale, nWordType, sal_True );
626 :
627 : // if no word was found use previous word (if any)
628 0 : if (aBndry.startPos == aBndry.endPos)
629 : {
630 0 : aBndry = rxBreak->previousWord( m_Text, nPos, aLocale, nWordType );
631 0 : }
632 : }
633 :
634 : // check if word was found and if it uses a symbol font, if so
635 : // enforce returning an empty string
636 0 : if (aBndry.endPos != aBndry.startPos && IsSymbol( (xub_StrLen)aBndry.startPos ))
637 0 : aBndry.endPos = aBndry.startPos;
638 :
639 : return m_Text.Copy( static_cast<xub_StrLen>(aBndry.startPos),
640 0 : static_cast<xub_StrLen>(aBndry.endPos - aBndry.startPos) );
641 : }
642 :
643 523 : SwScanner::SwScanner( const SwTxtNode& rNd, const rtl::OUString& rTxt,
644 : const LanguageType* pLang, const ModelToViewHelper& rConvMap,
645 : sal_uInt16 nType, sal_Int32 nStart, sal_Int32 nEnde, sal_Bool bClp )
646 : : rNode( rNd )
647 : , aPreDashReplacementText(rTxt)
648 : , pLanguage( pLang )
649 : , rConversionMap( rConvMap )
650 : , nLen( 0 )
651 : , nOverriddenDashCount( 0 )
652 : , nWordType( nType )
653 523 : , bClip( bClp )
654 : {
655 : OSL_ENSURE( !aPreDashReplacementText.isEmpty(), "SwScanner: EmptyString" );
656 523 : nStartPos = nBegin = nStart;
657 523 : nEndPos = nEnde;
658 :
659 : //MSWord f.e has special emdash and endash behaviour in that they break
660 : //words for the purposes of word counting, while a hyphen etc. doesn't.
661 : //
662 : //The default configuration treats emdash/endash as a word break, but
663 : //additional ones can be added in under tools->options
664 523 : if (nWordType == i18n::WordType::WORD_COUNT)
665 : {
666 : rtl::OUString sDashes = officecfg::Office::Writer::WordCount::AdditionalSeperators::get();
667 221 : rtl::OUStringBuffer aBuf(aPreDashReplacementText);
668 5296 : for (sal_Int32 i = nStartPos; i < nEndPos; ++i)
669 : {
670 5075 : sal_Unicode cChar = aBuf[i];
671 5075 : if (sDashes.indexOf(cChar) != -1)
672 : {
673 3 : aBuf[i] = ' ';
674 3 : ++nOverriddenDashCount;
675 : }
676 : }
677 221 : aText = aBuf.makeStringAndClear();
678 : }
679 : else
680 302 : aText = aPreDashReplacementText;
681 :
682 : assert(aPreDashReplacementText.getLength() == aText.getLength());
683 :
684 523 : if ( pLanguage )
685 : {
686 14 : aCurrLang = *pLanguage;
687 : }
688 : else
689 : {
690 509 : ModelToViewHelper::ModelPosition aModelBeginPos = rConversionMap.ConvertToModelPosition( nBegin );
691 509 : const sal_Int32 nModelBeginPos = aModelBeginPos.mnPos;
692 509 : aCurrLang = rNd.GetLang( nModelBeginPos );
693 : }
694 523 : }
695 :
696 : namespace
697 : {
698 : //fdo#45271 for Asian words count characters instead of words
699 676 : sal_Int32 forceEachAsianCodePointToWord(const rtl::OUString &rText, sal_Int32 nBegin, sal_Int32 nLen)
700 : {
701 676 : if (nLen > 1)
702 : {
703 527 : const uno::Reference< XBreakIterator > &rxBreak = pBreakIt->GetBreakIter();
704 :
705 527 : sal_uInt16 nCurrScript = rxBreak->getScriptType( rText, nBegin );
706 :
707 527 : sal_Int32 indexUtf16 = nBegin;
708 527 : rText.iterateCodePoints(&indexUtf16, 1);
709 :
710 : //First character is Asian, consider it a word :-(
711 527 : if (nCurrScript == i18n::ScriptType::ASIAN)
712 : {
713 7 : nLen = indexUtf16 - nBegin;
714 7 : return nLen;
715 : }
716 :
717 : //First character was not Asian, consider appearance of any Asian character
718 : //to be the end of the word
719 4953 : while (indexUtf16 < nBegin + nLen)
720 : {
721 3913 : nCurrScript = rxBreak->getScriptType( rText, indexUtf16 );
722 3913 : if (nCurrScript == i18n::ScriptType::ASIAN)
723 : {
724 0 : nLen = indexUtf16 - nBegin;
725 0 : return nLen;
726 : }
727 3913 : rText.iterateCodePoints(&indexUtf16, 1);
728 527 : }
729 : }
730 669 : return nLen;
731 : }
732 : }
733 :
734 1792 : sal_Bool SwScanner::NextWord()
735 : {
736 1792 : nBegin = nBegin + nLen;
737 1792 : Boundary aBound;
738 :
739 1792 : CharClass& rCC = GetAppCharClass();
740 1792 : LanguageTag aOldLanguageTag = rCC.getLanguageTag();
741 :
742 0 : while ( true )
743 : {
744 : // skip non-letter characters:
745 6525 : while ( nBegin < aText.getLength() )
746 : {
747 4211 : if ( !u_isspace( aText[nBegin] ) )
748 : {
749 3279 : if ( !pLanguage )
750 : {
751 3265 : const sal_uInt16 nNextScriptType = pBreakIt->GetBreakIter()->getScriptType( aText, nBegin );
752 3265 : ModelToViewHelper::ModelPosition aModelBeginPos = rConversionMap.ConvertToModelPosition( nBegin );
753 3265 : const sal_Int32 nBeginModelPos = aModelBeginPos.mnPos;
754 3265 : aCurrLang = rNode.GetLang( nBeginModelPos, 1, nNextScriptType );
755 : }
756 :
757 3279 : if ( nWordType != i18n::WordType::WORD_COUNT )
758 : {
759 2603 : rCC.setLanguageTag( LanguageTag( pBreakIt->GetLocale( aCurrLang )) );
760 2603 : if ( rCC.isLetterNumeric(rtl::OUString(aText[nBegin])) )
761 594 : break;
762 : }
763 : else
764 676 : break;
765 : }
766 2941 : ++nBegin;
767 : }
768 :
769 1792 : if ( nBegin >= aText.getLength() || nBegin >= nEndPos )
770 522 : return sal_False;
771 :
772 : // get the word boundaries
773 2540 : aBound = pBreakIt->GetBreakIter()->getWordBoundary( aText, nBegin,
774 1270 : pBreakIt->GetLocale( aCurrLang ), nWordType, sal_True );
775 : OSL_ENSURE( aBound.endPos >= aBound.startPos, "broken aBound result" );
776 :
777 : // we don't want to include preceeding text
778 1270 : if (aBound.startPos < nBegin)
779 6 : aBound.startPos = nBegin;
780 :
781 : //no word boundaries could be found
782 1270 : if(aBound.endPos == aBound.startPos)
783 0 : return sal_False;
784 :
785 : //if a word before is found it has to be searched for the next
786 1270 : if(aBound.endPos == nBegin)
787 0 : ++nBegin;
788 : else
789 1270 : break;
790 : } // end while( true )
791 :
792 1270 : rCC.setLanguageTag( aOldLanguageTag );
793 :
794 : // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
795 1270 : if ( nWordType == i18n::WordType::WORD_COUNT )
796 : {
797 676 : nBegin = Max(aBound.startPos, nBegin);
798 676 : nLen = 0;
799 676 : if (aBound.endPos > nBegin)
800 676 : nLen = aBound.endPos - nBegin;
801 : }
802 : else
803 : {
804 : // we have to differenciate between these cases:
805 594 : if ( aBound.startPos <= nBegin )
806 : {
807 : OSL_ENSURE( aBound.endPos >= nBegin, "Unexpected aBound result" );
808 :
809 : // restrict boundaries to script boundaries and nEndPos
810 554 : const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( aText, nBegin );
811 554 : rtl::OUString aTmpWord = aText.copy( nBegin, aBound.endPos - nBegin );
812 : const sal_Int32 nScriptEnd = nBegin +
813 554 : pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
814 554 : const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
815 :
816 : // restrict word start to last script change position
817 554 : sal_Int32 nScriptBegin = 0;
818 554 : if ( aBound.startPos < nBegin )
819 : {
820 : // search from nBegin backwards until the next script change
821 : aTmpWord = aText.copy( aBound.startPos,
822 0 : nBegin - aBound.startPos + 1 );
823 : nScriptBegin = aBound.startPos +
824 0 : pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, nBegin - aBound.startPos,
825 0 : nCurrScript );
826 : }
827 :
828 554 : nBegin = Max( aBound.startPos, nScriptBegin );
829 554 : nLen = nEnd - nBegin;
830 : }
831 : else
832 : {
833 40 : const sal_uInt16 nCurrScript = pBreakIt->GetBreakIter()->getScriptType( aText, aBound.startPos );
834 : rtl::OUString aTmpWord = aText.copy( aBound.startPos,
835 40 : aBound.endPos - aBound.startPos );
836 : const sal_Int32 nScriptEnd = aBound.startPos +
837 40 : pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
838 40 : const sal_Int32 nEnd = Min( aBound.endPos, nScriptEnd );
839 40 : nBegin = aBound.startPos;
840 40 : nLen = nEnd - nBegin;
841 : }
842 : }
843 :
844 : // optionally clip the result of getWordBoundaries:
845 1270 : if ( bClip )
846 : {
847 676 : aBound.startPos = Max( aBound.startPos, nStartPos );
848 676 : aBound.endPos = Min( aBound.endPos, nEndPos );
849 676 : nBegin = aBound.startPos;
850 676 : nLen = aBound.endPos - nBegin;
851 : }
852 :
853 1270 : if( ! nLen )
854 0 : return sal_False;
855 :
856 1270 : if ( nWordType == i18n::WordType::WORD_COUNT )
857 676 : nLen = forceEachAsianCodePointToWord(aText, nBegin, nLen);
858 :
859 1270 : aWord = aPreDashReplacementText.copy( nBegin, nLen );
860 :
861 1270 : return sal_True;
862 : }
863 :
864 0 : sal_uInt16 SwTxtNode::Spell(SwSpellArgs* pArgs)
865 : {
866 : // Die Aehnlichkeiten zu SwTxtFrm::_AutoSpell sind beabsichtigt ...
867 : // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
868 :
869 0 : uno::Reference<beans::XPropertySet> xProp( GetLinguPropertySet() );
870 :
871 : xub_StrLen nBegin, nEnd;
872 :
873 : // modify string according to redline information and hidden text
874 0 : const XubString aOldTxt( m_Text );
875 : const bool bRestoreString =
876 0 : lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
877 :
878 0 : if ( pArgs->pStartNode != this )
879 0 : nBegin = 0;
880 : else
881 0 : nBegin = pArgs->pStartIdx->GetIndex();
882 :
883 : nEnd = ( pArgs->pEndNode != this )
884 0 : ? m_Text.Len()
885 0 : : pArgs->pEndIdx->GetIndex();
886 :
887 0 : pArgs->xSpellAlt = NULL;
888 :
889 : // 4 cases:
890 : //
891 : // 1. IsWrongDirty = 0 and GetWrong = 0
892 : // Everything is checked and correct
893 : // 2. IsWrongDirty = 0 and GetWrong = 1
894 : // Everything is checked and errors are identified in the wrong list
895 : // 3. IsWrongDirty = 1 and GetWrong = 0
896 : // Nothing has been checked
897 : // 4. IsWrongDirty = 1 and GetWrong = 1
898 : // Text has been checked but there is an invalid range in the wrong list
899 : //
900 : // Nothing has to be done for case 1.
901 0 : if ( ( IsWrongDirty() || GetWrong() ) && m_Text.Len() )
902 : {
903 0 : if ( nBegin > m_Text.Len() )
904 : {
905 0 : nBegin = m_Text.Len();
906 : }
907 0 : if ( nEnd > m_Text.Len() )
908 : {
909 0 : nEnd = m_Text.Len();
910 : }
911 : //
912 0 : if(!IsWrongDirty())
913 : {
914 0 : xub_StrLen nTemp = GetWrong()->NextWrong( nBegin );
915 0 : if(nTemp > nEnd)
916 : {
917 : // reset original text
918 0 : if ( bRestoreString )
919 : {
920 0 : m_Text = aOldTxt;
921 : }
922 0 : return 0;
923 : }
924 0 : if(nTemp > nBegin)
925 0 : nBegin = nTemp;
926 :
927 : }
928 :
929 : // In case 2. we pass the wrong list to the scanned, because only
930 : // the words in the wrong list have to be checked
931 : SwScanner aScanner( *this, m_Text, 0, ModelToViewHelper(),
932 : WordType::DICTIONARY_WORD,
933 0 : nBegin, nEnd );
934 0 : while( !pArgs->xSpellAlt.is() && aScanner.NextWord() )
935 : {
936 0 : const XubString& rWord = aScanner.GetWord();
937 :
938 : // get next language for next word, consider language attributes
939 : // within the word
940 0 : LanguageType eActLang = aScanner.GetCurrentLanguage();
941 :
942 0 : if( rWord.Len() > 0 && LANGUAGE_NONE != eActLang )
943 : {
944 0 : if (pArgs->xSpeller.is())
945 : {
946 0 : SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
947 0 : pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, eActLang,
948 0 : Sequence< PropertyValue >() );
949 : }
950 0 : if( (pArgs->xSpellAlt).is() )
951 : {
952 0 : if( IsSymbol( aScanner.GetBegin() ) )
953 : {
954 0 : pArgs->xSpellAlt = NULL;
955 : }
956 : else
957 : {
958 : // make sure the selection build later from the data
959 : // below does not include "in word" character to the
960 : // left and right in order to preserve those. Therefore
961 : // count those "in words" in order to modify the
962 : // selection accordingly.
963 0 : const sal_Unicode* pChar = rWord.GetBuffer();
964 0 : xub_StrLen nLeft = 0;
965 0 : while (pChar && *pChar++ == CH_TXTATR_INWORD)
966 0 : ++nLeft;
967 0 : pChar = rWord.Len() ? rWord.GetBuffer() + rWord.Len() - 1 : 0;
968 0 : xub_StrLen nRight = 0;
969 0 : while (pChar && *pChar-- == CH_TXTATR_INWORD)
970 0 : ++nRight;
971 :
972 0 : pArgs->pStartNode = this;
973 0 : pArgs->pEndNode = this;
974 0 : pArgs->pStartIdx->Assign(this, aScanner.GetEnd() - nRight );
975 0 : pArgs->pEndIdx->Assign(this, aScanner.GetBegin() + nLeft );
976 : }
977 : }
978 : }
979 0 : }
980 : }
981 :
982 : // reset original text
983 0 : if ( bRestoreString )
984 : {
985 0 : m_Text = aOldTxt;
986 : }
987 :
988 0 : return pArgs->xSpellAlt.is() ? 1 : 0;
989 : }
990 :
991 0 : void SwTxtNode::SetLanguageAndFont( const SwPaM &rPaM,
992 : LanguageType nLang, sal_uInt16 nLangWhichId,
993 : const Font *pFont, sal_uInt16 nFontWhichId )
994 : {
995 : sal_uInt16 aRanges[] = {
996 : nLangWhichId, nLangWhichId,
997 : nFontWhichId, nFontWhichId,
998 0 : 0, 0, 0 };
999 0 : if (!pFont)
1000 0 : aRanges[2] = aRanges[3] = 0; // clear entries with font WhichId
1001 :
1002 0 : SwEditShell *pEditShell = GetDoc()->GetEditShell();
1003 0 : SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
1004 0 : aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
1005 :
1006 : OSL_ENSURE( pFont, "target font missing?" );
1007 0 : if (pFont)
1008 : {
1009 0 : SvxFontItem aFontItem = (SvxFontItem&) aSet.Get( nFontWhichId );
1010 0 : aFontItem.SetFamilyName( pFont->GetName());
1011 0 : aFontItem.SetFamily( pFont->GetFamily());
1012 0 : aFontItem.SetStyleName( pFont->GetStyleName());
1013 0 : aFontItem.SetPitch( pFont->GetPitch());
1014 0 : aFontItem.SetCharSet( pFont->GetCharSet() );
1015 0 : aSet.Put( aFontItem );
1016 : }
1017 :
1018 0 : GetDoc()->InsertItemSet( rPaM, aSet, 0 );
1019 : // SetAttr( aSet ); <- Does not set language attribute of empty paragraphs correctly,
1020 : // <- because since there is no selection the flag to garbage
1021 : // <- collect all attributes is set, and therefore attributes spanned
1022 : // <- over empty selection are removed.
1023 :
1024 0 : }
1025 :
1026 0 : sal_uInt16 SwTxtNode::Convert( SwConversionArgs &rArgs )
1027 : {
1028 : // get range of text within node to be converted
1029 : // (either all the text or the the text within the selection
1030 : // when the conversion was started)
1031 : xub_StrLen nTextBegin, nTextEnd;
1032 : //
1033 0 : if ( rArgs.pStartNode != this )
1034 : {
1035 0 : nTextBegin = 0;
1036 : }
1037 : else
1038 0 : nTextBegin = rArgs.pStartIdx->GetIndex();
1039 0 : if (nTextBegin > m_Text.Len())
1040 : {
1041 0 : nTextBegin = m_Text.Len();
1042 : }
1043 :
1044 : nTextEnd = ( rArgs.pEndNode != this )
1045 0 : ? m_Text.Len()
1046 0 : : ::std::min( rArgs.pEndIdx->GetIndex(), m_Text.Len() );
1047 :
1048 0 : rArgs.aConvText = rtl::OUString();
1049 :
1050 : // modify string according to redline information and hidden text
1051 0 : const XubString aOldTxt( m_Text );
1052 : const bool bRestoreString =
1053 0 : lcl_MaskRedlinesAndHiddenText( *this, m_Text, 0, m_Text.Len() ) > 0;
1054 :
1055 0 : bool bFound = false;
1056 0 : xub_StrLen nBegin = nTextBegin;
1057 0 : xub_StrLen nLen = 0;
1058 0 : LanguageType nLangFound = LANGUAGE_NONE;
1059 0 : if (!m_Text.Len())
1060 : {
1061 0 : if (rArgs.bAllowImplicitChangesForNotConvertibleText)
1062 : {
1063 : // create SwPaM with mark & point spanning empty paragraph
1064 : //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1065 0 : SwPaM aCurPaM( *this, 0 );
1066 :
1067 : SetLanguageAndFont( aCurPaM,
1068 : rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
1069 0 : rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
1070 : }
1071 : }
1072 : else
1073 : {
1074 0 : SwLanguageIterator aIter( *this, nBegin );
1075 :
1076 : // find non zero length text portion of appropriate language
1077 0 : do {
1078 0 : nLangFound = aIter.GetLanguage();
1079 : bool bLangOk = (nLangFound == rArgs.nConvSrcLang) ||
1080 0 : (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
1081 0 : editeng::HangulHanjaConversion::IsChinese( rArgs.nConvSrcLang ));
1082 :
1083 0 : xub_StrLen nChPos = aIter.GetChgPos();
1084 : // the position at the end of the paragraph returns -1
1085 : // which becomes 65535 when converted to xub_StrLen,
1086 : // and thus must be cut to the end of the actual string.
1087 0 : if (nChPos == (xub_StrLen) -1)
1088 : {
1089 0 : nChPos = m_Text.Len();
1090 : }
1091 :
1092 0 : nLen = nChPos - nBegin;
1093 0 : bFound = bLangOk && nLen > 0;
1094 0 : if (!bFound)
1095 : {
1096 : // create SwPaM with mark & point spanning the attributed text
1097 : //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1098 0 : SwPaM aCurPaM( *this, nBegin );
1099 0 : aCurPaM.SetMark();
1100 0 : aCurPaM.GetPoint()->nContent = nBegin + nLen;
1101 :
1102 : // check script type of selected text
1103 0 : SwEditShell *pEditShell = GetDoc()->GetEditShell();
1104 0 : pEditShell->Push(); // save current cursor on stack
1105 0 : pEditShell->SetSelection( aCurPaM );
1106 0 : bool bIsAsianScript = (SCRIPTTYPE_ASIAN == pEditShell->GetScriptType());
1107 0 : pEditShell->Pop( sal_False ); // restore cursor from stack
1108 :
1109 0 : if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
1110 : {
1111 : SetLanguageAndFont( aCurPaM,
1112 : rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
1113 0 : rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
1114 : }
1115 0 : nBegin = nChPos; // start of next language portion
1116 : }
1117 0 : } while (!bFound && aIter.Next()); /* loop while nothing was found and still sth is left to be searched */
1118 : }
1119 :
1120 : // keep resulting text within selection / range of text to be converted
1121 0 : if (nBegin < nTextBegin)
1122 0 : nBegin = nTextBegin;
1123 0 : if (nBegin + nLen > nTextEnd)
1124 0 : nLen = nTextEnd - nBegin;
1125 0 : bool bInSelection = nBegin < nTextEnd;
1126 :
1127 0 : if (bFound && bInSelection) // convertible text found within selection/range?
1128 : {
1129 : OSL_ENSURE( m_Text.Len() > 0, "convertible text portion missing!" );
1130 0 : rArgs.aConvText = m_Text.Copy( nBegin, nLen );
1131 0 : rArgs.nConvTextLang = nLangFound;
1132 :
1133 : // position where to start looking in next iteration (after current ends)
1134 0 : rArgs.pStartNode = this;
1135 0 : rArgs.pStartIdx->Assign(this, nBegin + nLen );
1136 : // end position (when we have travelled over the whole document)
1137 0 : rArgs.pEndNode = this;
1138 0 : rArgs.pEndIdx->Assign(this, nBegin );
1139 : }
1140 :
1141 : // restore original text
1142 0 : if ( bRestoreString )
1143 : {
1144 0 : m_Text = aOldTxt;
1145 : }
1146 :
1147 0 : return rArgs.aConvText.isEmpty() ? 0 : 1;
1148 : }
1149 :
1150 : // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
1151 : // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
1152 500 : SwRect SwTxtFrm::_AutoSpell( const SwCntntNode* pActNode, const SwViewOption& rViewOpt, xub_StrLen nActPos )
1153 : {
1154 500 : SwRect aRect;
1155 : #if OSL_DEBUG_LEVEL > 1
1156 : static bool bStop = false;
1157 : if ( bStop )
1158 : return aRect;
1159 : #endif
1160 : // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
1161 : // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
1162 500 : SwTxtNode *pNode = GetTxtNode();
1163 500 : if( pNode != pActNode || !nActPos )
1164 500 : nActPos = STRING_LEN;
1165 :
1166 500 : SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
1167 :
1168 : // modify string according to redline information and hidden text
1169 500 : const XubString aOldTxt( pNode->GetTxt() );
1170 : const bool bRestoreString =
1171 : lcl_MaskRedlinesAndHiddenText( *pNode, pNode->m_Text,
1172 500 : 0, pNode->GetTxt().Len() ) > 0;
1173 :
1174 : // a change of data indicates that at least one word has been modified
1175 : const bool bRedlineChg =
1176 500 : ( pNode->GetTxt().GetBuffer() != aOldTxt.GetBuffer() );
1177 :
1178 500 : xub_StrLen nBegin = 0;
1179 500 : xub_StrLen nEnd = pNode->GetTxt().Len();
1180 500 : xub_StrLen nInsertPos = 0;
1181 500 : xub_StrLen nChgStart = STRING_LEN;
1182 500 : xub_StrLen nChgEnd = 0;
1183 500 : xub_StrLen nInvStart = STRING_LEN;
1184 500 : xub_StrLen nInvEnd = 0;
1185 :
1186 500 : const bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
1187 500 : rViewOpt.IsAutoCompleteWords();
1188 :
1189 500 : if( pNode->GetWrong() )
1190 : {
1191 0 : nBegin = pNode->GetWrong()->GetBeginInv();
1192 0 : if( STRING_LEN != nBegin )
1193 : {
1194 0 : nEnd = pNode->GetWrong()->GetEndInv();
1195 0 : if ( nEnd > pNode->GetTxt().Len() )
1196 : {
1197 0 : nEnd = pNode->GetTxt().Len();
1198 : }
1199 : }
1200 :
1201 : // get word around nBegin, we start at nBegin - 1
1202 0 : if ( STRING_LEN != nBegin )
1203 : {
1204 0 : if ( nBegin )
1205 0 : --nBegin;
1206 :
1207 0 : LanguageType eActLang = pNode->GetLang( nBegin );
1208 : Boundary aBound =
1209 0 : pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetTxt(), nBegin,
1210 0 : pBreakIt->GetLocale( eActLang ),
1211 0 : WordType::DICTIONARY_WORD, sal_True );
1212 0 : nBegin = xub_StrLen(aBound.startPos);
1213 : }
1214 :
1215 : // get the position in the wrong list
1216 0 : nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
1217 :
1218 : // sometimes we have to skip one entry
1219 0 : if( nInsertPos < pNode->GetWrong()->Count() &&
1220 0 : nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
1221 0 : pNode->GetWrong()->Len( nInsertPos ) )
1222 0 : nInsertPos++;
1223 : }
1224 :
1225 500 : bool bFresh = nBegin < nEnd;
1226 :
1227 500 : if( nBegin < nEnd )
1228 : {
1229 : //! register listener to LinguServiceEvents now in order to get
1230 : //! notified about relevant changes in the future
1231 301 : SwModule *pModule = SW_MOD();
1232 301 : if (!pModule->GetLngSvcEvtListener().is())
1233 5 : pModule->CreateLngSvcEvtListener();
1234 :
1235 301 : uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1236 301 : SwDoc* pDoc = pNode->GetDoc();
1237 :
1238 301 : SwScanner aScanner( *pNode, pNode->GetTxt(), 0, ModelToViewHelper(),
1239 602 : WordType::DICTIONARY_WORD, nBegin, nEnd);
1240 :
1241 1194 : while( aScanner.NextWord() )
1242 : {
1243 592 : const XubString& rWord = aScanner.GetWord();
1244 592 : nBegin = aScanner.GetBegin();
1245 592 : xub_StrLen nLen = aScanner.GetLen();
1246 :
1247 : // get next language for next word, consider language attributes
1248 : // within the word
1249 592 : LanguageType eActLang = aScanner.GetCurrentLanguage();
1250 :
1251 592 : sal_Bool bSpell = sal_True;
1252 592 : bSpell = xSpell.is() ? xSpell->hasLanguage( eActLang ) : sal_False;
1253 592 : if( bSpell && rWord.Len() > 0 )
1254 : {
1255 : // check for: bAlter => xHyphWord.is()
1256 : OSL_ENSURE(!bSpell || xSpell.is(), "NULL pointer");
1257 :
1258 0 : if( !xSpell->isValid( rWord, eActLang, Sequence< PropertyValue >() ) )
1259 : {
1260 0 : xub_StrLen nSmartTagStt = nBegin;
1261 0 : xub_StrLen nDummy = 1;
1262 0 : if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
1263 : {
1264 0 : if( !pNode->GetWrong() )
1265 : {
1266 0 : pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
1267 0 : pNode->GetWrong()->SetInvalid( 0, nEnd );
1268 : }
1269 0 : if( pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1270 0 : nBegin, nLen, nInsertPos, nActPos ) )
1271 0 : pNode->GetWrong()->Insert( rtl::OUString(), 0, nBegin, nLen, nInsertPos++ );
1272 : else
1273 : {
1274 0 : nInvStart = nBegin;
1275 0 : nInvEnd = nBegin + nLen;
1276 : }
1277 : }
1278 : }
1279 0 : else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.Len() )
1280 : {
1281 0 : if ( bRedlineChg )
1282 : {
1283 0 : XubString rNewWord( rWord );
1284 0 : rACW.InsertWord( rNewWord, *pDoc );
1285 : }
1286 : else
1287 0 : rACW.InsertWord( rWord, *pDoc );
1288 : }
1289 : }
1290 893 : }
1291 : }
1292 :
1293 : // reset original text
1294 : // i63141 before calling GetCharRect(..) with formatting!
1295 500 : if ( bRestoreString )
1296 : {
1297 0 : pNode->m_Text = aOldTxt;
1298 : }
1299 500 : if( pNode->GetWrong() )
1300 : {
1301 0 : if( bFresh )
1302 : pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1303 0 : nEnd, 0, nInsertPos, nActPos );
1304 :
1305 : //
1306 : // Calculate repaint area:
1307 : //
1308 0 : if( nChgStart < nChgEnd )
1309 : {
1310 0 : aRect = lcl_CalculateRepaintRect( *this, nChgStart, nChgEnd );
1311 : }
1312 :
1313 0 : pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
1314 0 : pNode->SetWrongDirty( STRING_LEN != pNode->GetWrong()->GetBeginInv() );
1315 0 : if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
1316 0 : pNode->SetWrong( NULL );
1317 : }
1318 : else
1319 500 : pNode->SetWrongDirty( false );
1320 :
1321 500 : if( bAddAutoCmpl )
1322 500 : pNode->SetAutoCompleteWordDirty( false );
1323 :
1324 500 : return aRect;
1325 : }
1326 :
1327 : /** Function: SmartTagScan
1328 :
1329 : Function scans words in current text and checks them in the
1330 : smarttag libraries. If the check returns true to bounds of the
1331 : recognized words are stored into a list which is used later for drawing
1332 : the underline.
1333 :
1334 : @param SwCntntNode* pActNode
1335 :
1336 : @param xub_StrLen nActPos
1337 :
1338 : @return SwRect: Repaint area
1339 : */
1340 0 : SwRect SwTxtFrm::SmartTagScan( SwCntntNode* /*pActNode*/, xub_StrLen /*nActPos*/ )
1341 : {
1342 0 : SwRect aRet;
1343 0 : SwTxtNode *pNode = GetTxtNode();
1344 0 : const rtl::OUString& rText = pNode->GetTxt();
1345 :
1346 : // Iterate over language portions
1347 0 : SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
1348 :
1349 0 : SwWrongList* pSmartTagList = pNode->GetSmartTags();
1350 :
1351 0 : xub_StrLen nBegin = 0;
1352 0 : xub_StrLen nEnd = static_cast< xub_StrLen >(rText.getLength());
1353 :
1354 0 : if ( pSmartTagList )
1355 : {
1356 0 : if ( pSmartTagList->GetBeginInv() != STRING_LEN )
1357 : {
1358 0 : nBegin = pSmartTagList->GetBeginInv();
1359 0 : nEnd = Min( pSmartTagList->GetEndInv(), (xub_StrLen)rText.getLength() );
1360 :
1361 0 : if ( nBegin < nEnd )
1362 : {
1363 0 : const LanguageType aCurrLang = pNode->GetLang( nBegin );
1364 0 : const com::sun::star::lang::Locale aCurrLocale = pBreakIt->GetLocale( aCurrLang );
1365 0 : nBegin = static_cast< xub_StrLen >(pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale ));
1366 0 : nEnd = static_cast< xub_StrLen >(Min( rText.getLength(), pBreakIt->GetBreakIter()->endOfSentence( rText, nEnd, aCurrLocale ) ));
1367 : }
1368 : }
1369 : }
1370 :
1371 0 : const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
1372 0 : sal_uInt16 nNumberOfRemovedEntries = 0;
1373 0 : sal_uInt16 nNumberOfInsertedEntries = 0;
1374 :
1375 : // clear smart tag list between nBegin and nEnd:
1376 0 : if ( 0 != nNumberOfEntries )
1377 : {
1378 0 : xub_StrLen nChgStart = STRING_LEN;
1379 0 : xub_StrLen nChgEnd = 0;
1380 0 : const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
1381 0 : pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, STRING_LEN );
1382 0 : nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
1383 : }
1384 :
1385 0 : if ( nBegin < nEnd )
1386 : {
1387 : // Expand the string:
1388 0 : const ModelToViewHelper aConversionMap(*pNode);
1389 0 : rtl::OUString aExpandText = aConversionMap.getViewText();
1390 :
1391 : // Ownership ov ConversionMap is passed to SwXTextMarkup object!
1392 : com::sun::star::uno::Reference< com::sun::star::text::XTextMarkup > xTextMarkup =
1393 0 : new SwXTextMarkup( *pNode, aConversionMap );
1394 :
1395 0 : com::sun::star::uno::Reference< ::com::sun::star::frame::XController > xController = pNode->GetDoc()->GetDocShell()->GetController();
1396 :
1397 0 : xub_StrLen nLangBegin = nBegin;
1398 0 : xub_StrLen nLangEnd = nEnd;
1399 :
1400 : // smart tag recognization has to be done for each language portion:
1401 0 : SwLanguageIterator aIter( *pNode, nLangBegin );
1402 :
1403 0 : do
1404 : {
1405 0 : const LanguageType nLang = aIter.GetLanguage();
1406 0 : const com::sun::star::lang::Locale aLocale = pBreakIt->GetLocale( nLang );
1407 0 : nLangEnd = Min( nEnd, aIter.GetChgPos() );
1408 :
1409 0 : const sal_uInt32 nExpandBegin = aConversionMap.ConvertToViewPosition( nLangBegin );
1410 0 : const sal_uInt32 nExpandEnd = aConversionMap.ConvertToViewPosition( nLangEnd );
1411 :
1412 0 : rSmartTagMgr.Recognize( aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
1413 :
1414 0 : nLangBegin = nLangEnd;
1415 : }
1416 0 : while ( aIter.Next() && nLangEnd < nEnd );
1417 :
1418 0 : pSmartTagList = pNode->GetSmartTags();
1419 :
1420 0 : const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
1421 0 : nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
1422 : }
1423 :
1424 0 : if( pSmartTagList )
1425 : {
1426 : //
1427 : // Update WrongList stuff
1428 : //
1429 0 : pSmartTagList->SetInvalid( STRING_LEN, 0 );
1430 0 : pNode->SetSmartTagDirty( STRING_LEN != pSmartTagList->GetBeginInv() );
1431 :
1432 0 : if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
1433 0 : pNode->SetSmartTags( NULL );
1434 :
1435 : //
1436 : // Calculate repaint area:
1437 : //
1438 : #if OSL_DEBUG_LEVEL > 1
1439 : const sal_uInt16 nNumberOfEntriesAfterRecognize2 = pSmartTagList->Count();
1440 : (void) nNumberOfEntriesAfterRecognize2;
1441 : #endif
1442 0 : if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
1443 : 0 != nNumberOfInsertedEntries ) )
1444 : {
1445 0 : aRet = lcl_CalculateRepaintRect( *this, nBegin, nEnd );
1446 : }
1447 : }
1448 : else
1449 0 : pNode->SetSmartTagDirty( false );
1450 :
1451 0 : return aRet;
1452 : }
1453 :
1454 : // Wird vom CollectAutoCmplWords gerufen
1455 0 : void SwTxtFrm::CollectAutoCmplWrds( SwCntntNode* pActNode, xub_StrLen nActPos )
1456 : {
1457 0 : SwTxtNode *pNode = GetTxtNode();
1458 0 : if( pNode != pActNode || !nActPos )
1459 0 : nActPos = STRING_LEN;
1460 :
1461 0 : SwDoc* pDoc = pNode->GetDoc();
1462 0 : SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
1463 :
1464 0 : xub_StrLen nBegin = 0;
1465 0 : xub_StrLen nEnd = pNode->GetTxt().Len();
1466 : xub_StrLen nLen;
1467 0 : bool bACWDirty = false, bAnyWrd = false;
1468 :
1469 0 : if( nBegin < nEnd )
1470 : {
1471 0 : sal_uInt16 nCnt = 200;
1472 0 : SwScanner aScanner( *pNode, pNode->GetTxt(), 0, ModelToViewHelper(),
1473 0 : WordType::DICTIONARY_WORD, nBegin, nEnd );
1474 0 : while( aScanner.NextWord() )
1475 : {
1476 0 : nBegin = aScanner.GetBegin();
1477 0 : nLen = aScanner.GetLen();
1478 0 : if( rACW.GetMinWordLen() <= nLen )
1479 : {
1480 0 : const XubString& rWord = aScanner.GetWord();
1481 :
1482 0 : if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
1483 : {
1484 0 : if( rACW.GetMinWordLen() <= rWord.Len() )
1485 0 : rACW.InsertWord( rWord, *pDoc );
1486 0 : bAnyWrd = true;
1487 : }
1488 : else
1489 0 : bACWDirty = true;
1490 : }
1491 0 : if( !--nCnt )
1492 : {
1493 0 : if ( Application::AnyInput( VCL_INPUT_ANY ) )
1494 0 : return;
1495 0 : nCnt = 100;
1496 : }
1497 0 : }
1498 : }
1499 :
1500 0 : if( bAnyWrd && !bACWDirty )
1501 0 : pNode->SetAutoCompleteWordDirty( sal_False );
1502 : }
1503 :
1504 : /*************************************************************************
1505 : * SwTxtNode::Hyphenate
1506 : *************************************************************************/
1507 : // Findet den TxtFrm und sucht dessen CalcHyph
1508 :
1509 0 : sal_Bool SwTxtNode::Hyphenate( SwInterHyphInfo &rHyphInf )
1510 : {
1511 : // Abkuerzung: am Absatz ist keine Sprache eingestellt:
1512 0 : if ( LANGUAGE_NONE == sal_uInt16( GetSwAttrSet().GetLanguage().GetLanguage() )
1513 0 : && USHRT_MAX == GetLang( 0, m_Text.Len() ) )
1514 : {
1515 0 : if( !rHyphInf.IsCheck() )
1516 0 : rHyphInf.SetNoLang( sal_True );
1517 0 : return sal_False;
1518 : }
1519 :
1520 0 : if( pLinguNode != this )
1521 : {
1522 0 : pLinguNode = this;
1523 0 : pLinguFrm = (SwTxtFrm*)getLayoutFrm( GetDoc()->GetCurrentLayout(), (Point*)(rHyphInf.GetCrsrPos()) );
1524 : }
1525 0 : SwTxtFrm *pFrm = pLinguFrm;
1526 0 : if( pFrm )
1527 0 : pFrm = &(pFrm->GetFrmAtOfst( rHyphInf.nStart ));
1528 : else
1529 : {
1530 : // 4935: Seit der Trennung ueber Sonderbereiche sind Faelle
1531 : // moeglich, in denen kein Frame zum Node vorliegt.
1532 : // Also keinOSL_ENSURE
1533 : OSL_ENSURE( pFrm, "!SwTxtNode::Hyphenate: can't find any frame" );
1534 0 : return sal_False;
1535 : }
1536 :
1537 0 : while( pFrm )
1538 : {
1539 0 : if( pFrm->Hyphenate( rHyphInf ) )
1540 : {
1541 : // Das Layout ist nicht robust gegen "Direktformatierung"
1542 : // (7821, 7662, 7408); vgl. layact.cxx,
1543 : // SwLayAction::_TurboAction(), if( !pCnt->IsValid() ...
1544 0 : pFrm->SetCompletePaint();
1545 0 : return sal_True;
1546 : }
1547 0 : pFrm = (SwTxtFrm*)(pFrm->GetFollow());
1548 0 : if( pFrm )
1549 : {
1550 0 : rHyphInf.nLen = rHyphInf.nLen - (pFrm->GetOfst() - rHyphInf.nStart);
1551 0 : rHyphInf.nStart = pFrm->GetOfst();
1552 : }
1553 : }
1554 0 : return sal_False;
1555 : }
1556 :
1557 : namespace
1558 : {
1559 0 : struct swTransliterationChgData
1560 : {
1561 : xub_StrLen nStart;
1562 : xub_StrLen nLen;
1563 : String sChanged;
1564 : Sequence< sal_Int32 > aOffsets;
1565 : };
1566 : }
1567 :
1568 : // change text to Upper/Lower/Hiragana/Katagana/...
1569 0 : void SwTxtNode::TransliterateText(
1570 : utl::TransliterationWrapper& rTrans,
1571 : xub_StrLen nStt, xub_StrLen nEnd,
1572 : SwUndoTransliterate* pUndo )
1573 : {
1574 0 : if (nStt < nEnd && pBreakIt->GetBreakIter().is())
1575 : {
1576 : // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
1577 : // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
1578 : // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
1579 : // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
1580 : // proper thing to do.
1581 0 : const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
1582 :
1583 : //! In order to have less trouble with changing text size, e.g. because
1584 : //! of ligatures or � (German small sz) being resolved, we need to process
1585 : //! the text replacements from end to start.
1586 : //! This way the offsets for the yet to be changed words will be
1587 : //! left unchanged by the already replaced text.
1588 : //! For this we temporarily save the changes to be done in this vector
1589 0 : std::vector< swTransliterationChgData > aChanges;
1590 0 : swTransliterationChgData aChgData;
1591 :
1592 0 : if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::TITLE_CASE)
1593 : {
1594 : // for 'capitalize every word' we need to iterate over each word
1595 :
1596 0 : Boundary aSttBndry;
1597 0 : Boundary aEndBndry;
1598 0 : aSttBndry = pBreakIt->GetBreakIter()->getWordBoundary(
1599 0 : GetTxt(), nStt,
1600 0 : pBreakIt->GetLocale( GetLang( nStt ) ),
1601 : nWordType,
1602 0 : sal_True /*prefer forward direction*/);
1603 0 : aEndBndry = pBreakIt->GetBreakIter()->getWordBoundary(
1604 0 : GetTxt(), nEnd,
1605 0 : pBreakIt->GetLocale( GetLang( nEnd ) ),
1606 : nWordType,
1607 0 : sal_False /*prefer backward direction*/);
1608 :
1609 : // prevent backtracking to the previous word if selection is at word boundary
1610 0 : if (aSttBndry.endPos <= nStt)
1611 : {
1612 0 : aSttBndry = pBreakIt->GetBreakIter()->nextWord(
1613 0 : GetTxt(), aSttBndry.endPos,
1614 0 : pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
1615 0 : nWordType);
1616 : }
1617 : // prevent advancing to the next word if selection is at word boundary
1618 0 : if (aEndBndry.startPos >= nEnd)
1619 : {
1620 0 : aEndBndry = pBreakIt->GetBreakIter()->previousWord(
1621 0 : GetTxt(), aEndBndry.startPos,
1622 0 : pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
1623 0 : nWordType);
1624 : }
1625 :
1626 0 : Boundary aCurWordBndry( aSttBndry );
1627 0 : while (aCurWordBndry.startPos <= aEndBndry.startPos)
1628 : {
1629 0 : nStt = (xub_StrLen)aCurWordBndry.startPos;
1630 0 : nEnd = (xub_StrLen)aCurWordBndry.endPos;
1631 0 : sal_Int32 nLen = nEnd - nStt;
1632 : OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1633 :
1634 0 : Sequence <sal_Int32> aOffsets;
1635 0 : String sChgd( rTrans.transliterate( GetTxt(), GetLang( nStt ), nStt, nLen, &aOffsets ));
1636 :
1637 0 : if (!m_Text.Equals( sChgd, nStt, nLen ))
1638 : {
1639 0 : aChgData.nStart = nStt;
1640 0 : aChgData.nLen = nLen;
1641 0 : aChgData.sChanged = sChgd;
1642 0 : aChgData.aOffsets = aOffsets;
1643 0 : aChanges.push_back( aChgData );
1644 : }
1645 :
1646 0 : aCurWordBndry = pBreakIt->GetBreakIter()->nextWord(
1647 0 : GetTxt(), nEnd,
1648 0 : pBreakIt->GetLocale( GetLang( nEnd ) ),
1649 0 : nWordType);
1650 0 : }
1651 : }
1652 0 : else if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::SENTENCE_CASE)
1653 : {
1654 : // for 'sentence case' we need to iterate sentence by sentence
1655 :
1656 0 : sal_Int32 nLastStart = pBreakIt->GetBreakIter()->beginOfSentence(
1657 0 : GetTxt(), nEnd,
1658 0 : pBreakIt->GetLocale( GetLang( nEnd ) ) );
1659 0 : sal_Int32 nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
1660 0 : GetTxt(), nLastStart,
1661 0 : pBreakIt->GetLocale( GetLang( nLastStart ) ) );
1662 :
1663 : // extend nStt, nEnd to the current sentence boundaries
1664 0 : sal_Int32 nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
1665 0 : GetTxt(), nStt,
1666 0 : pBreakIt->GetLocale( GetLang( nStt ) ) );
1667 0 : sal_Int32 nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1668 0 : GetTxt(), nCurrentStart,
1669 0 : pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1670 :
1671 : // prevent backtracking to the previous sentence if selection starts at end of a sentence
1672 0 : if (nCurrentEnd <= nStt)
1673 : {
1674 : // now nCurrentStart is probably located on a non-letter word. (unless we
1675 : // are in Asian text with no spaces...)
1676 : // Thus to get the real sentence start we should locate the next real word,
1677 : // that is one found by DICTIONARY_WORD
1678 0 : i18n::Boundary aBndry = pBreakIt->GetBreakIter()->nextWord(
1679 0 : GetTxt(), nCurrentEnd,
1680 0 : pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1681 0 : i18n::WordType::DICTIONARY_WORD);
1682 :
1683 : // now get new current sentence boundaries
1684 0 : nCurrentStart = pBreakIt->GetBreakIter()->beginOfSentence(
1685 0 : GetTxt(), aBndry.startPos,
1686 0 : pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1687 0 : nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1688 0 : GetTxt(), nCurrentStart,
1689 0 : pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
1690 : }
1691 : // prevent advancing to the next sentence if selection ends at start of a sentence
1692 0 : if (nLastStart >= nEnd)
1693 : {
1694 : // now nCurrentStart is probably located on a non-letter word. (unless we
1695 : // are in Asian text with no spaces...)
1696 : // Thus to get the real sentence start we should locate the previous real word,
1697 : // that is one found by DICTIONARY_WORD
1698 0 : i18n::Boundary aBndry = pBreakIt->GetBreakIter()->previousWord(
1699 0 : GetTxt(), nLastStart,
1700 0 : pBreakIt->GetLocale( GetLang( nLastStart) ),
1701 0 : i18n::WordType::DICTIONARY_WORD);
1702 0 : nLastEnd = pBreakIt->GetBreakIter()->endOfSentence(
1703 0 : GetTxt(), aBndry.startPos,
1704 0 : pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1705 0 : if (nCurrentEnd > nLastEnd)
1706 0 : nCurrentEnd = nLastEnd;
1707 : }
1708 :
1709 0 : while (nCurrentStart < nLastEnd)
1710 : {
1711 0 : sal_Int32 nLen = nCurrentEnd - nCurrentStart;
1712 : OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1713 :
1714 0 : Sequence <sal_Int32> aOffsets;
1715 0 : String sChgd( rTrans.transliterate( GetTxt(),
1716 0 : GetLang( nCurrentStart ), nCurrentStart, nLen, &aOffsets ));
1717 :
1718 0 : if (!m_Text.Equals( sChgd, nStt, nLen ))
1719 : {
1720 0 : aChgData.nStart = nCurrentStart;
1721 0 : aChgData.nLen = nLen;
1722 0 : aChgData.sChanged = sChgd;
1723 0 : aChgData.aOffsets = aOffsets;
1724 0 : aChanges.push_back( aChgData );
1725 : }
1726 :
1727 0 : Boundary aFirstWordBndry;
1728 0 : aFirstWordBndry = pBreakIt->GetBreakIter()->nextWord(
1729 0 : GetTxt(), nCurrentEnd,
1730 0 : pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1731 0 : nWordType);
1732 0 : nCurrentStart = aFirstWordBndry.startPos;
1733 0 : nCurrentEnd = pBreakIt->GetBreakIter()->endOfSentence(
1734 0 : GetTxt(), nCurrentStart,
1735 0 : pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1736 0 : }
1737 : }
1738 : else
1739 : {
1740 : // here we may transliterate over complete language portions...
1741 :
1742 : SwLanguageIterator* pIter;
1743 0 : if( rTrans.needLanguageForTheMode() )
1744 0 : pIter = new SwLanguageIterator( *this, nStt );
1745 : else
1746 0 : pIter = 0;
1747 :
1748 : xub_StrLen nEndPos;
1749 : sal_uInt16 nLang;
1750 0 : do {
1751 0 : if( pIter )
1752 : {
1753 0 : nLang = pIter->GetLanguage();
1754 0 : nEndPos = pIter->GetChgPos();
1755 0 : if( nEndPos > nEnd )
1756 0 : nEndPos = nEnd;
1757 : }
1758 : else
1759 : {
1760 0 : nLang = LANGUAGE_SYSTEM;
1761 0 : nEndPos = nEnd;
1762 : }
1763 0 : xub_StrLen nLen = nEndPos - nStt;
1764 :
1765 0 : Sequence <sal_Int32> aOffsets;
1766 0 : String sChgd( rTrans.transliterate( m_Text, nLang, nStt, nLen, &aOffsets ));
1767 :
1768 0 : if (!m_Text.Equals( sChgd, nStt, nLen ))
1769 : {
1770 0 : aChgData.nStart = nStt;
1771 0 : aChgData.nLen = nLen;
1772 0 : aChgData.sChanged = sChgd;
1773 0 : aChgData.aOffsets = aOffsets;
1774 0 : aChanges.push_back( aChgData );
1775 : }
1776 :
1777 0 : nStt = nEndPos;
1778 0 : } while( nEndPos < nEnd && pIter && pIter->Next() );
1779 0 : delete pIter;
1780 : }
1781 :
1782 0 : if (!aChanges.empty())
1783 : {
1784 : // now apply the changes from end to start to leave the offsets of the
1785 : // yet unchanged text parts remain the same.
1786 0 : for (size_t i = 0; i < aChanges.size(); ++i)
1787 : {
1788 0 : swTransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ];
1789 0 : if (pUndo)
1790 0 : pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
1791 0 : ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
1792 : }
1793 0 : }
1794 : }
1795 0 : }
1796 :
1797 0 : void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
1798 : const XubString& rText,
1799 : const Sequence<sal_Int32>& rOffsets )
1800 : {
1801 0 : m_Text.Replace( nPos, nLen, rText );
1802 :
1803 0 : xub_StrLen nTLen = rText.Len();
1804 0 : const sal_Int32* pOffsets = rOffsets.getConstArray();
1805 : // now look for no 1-1 mapping -> move the indizies!
1806 : xub_StrLen nI, nMyOff;
1807 0 : for( nI = 0, nMyOff = nPos; nI < nTLen; ++nI, ++nMyOff )
1808 : {
1809 0 : xub_StrLen nOff = (xub_StrLen)pOffsets[ nI ];
1810 0 : if( nOff < nMyOff )
1811 : {
1812 : // something is inserted
1813 0 : xub_StrLen nCnt = 1;
1814 0 : while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
1815 0 : ++nCnt;
1816 :
1817 0 : Update( SwIndex( this, nMyOff ), nCnt, sal_False );
1818 0 : nMyOff = nOff;
1819 : //nMyOff -= nCnt;
1820 0 : nI += nCnt - 1;
1821 : }
1822 0 : else if( nOff > nMyOff )
1823 : {
1824 : // something is deleted
1825 0 : Update( SwIndex( this, nMyOff+1 ), nOff - nMyOff, sal_True );
1826 0 : nMyOff = nOff;
1827 : }
1828 : }
1829 0 : if( nMyOff < nLen )
1830 : // something is deleted at the end
1831 0 : Update( SwIndex( this, nMyOff ), nLen - nMyOff, sal_True );
1832 :
1833 : // notify the layout!
1834 0 : SwDelTxt aDelHint( nPos, nTLen );
1835 0 : NotifyClients( 0, &aDelHint );
1836 :
1837 0 : SwInsTxt aHint( nPos, nTLen );
1838 0 : NotifyClients( 0, &aHint );
1839 0 : }
1840 :
1841 528 : void SwTxtNode::CountWords( SwDocStat& rStat,
1842 : xub_StrLen nStt, xub_StrLen nEnd ) const
1843 : {
1844 528 : if( nStt > nEnd )
1845 : { // bad call
1846 : return;
1847 : }
1848 528 : if (IsInRedlines())
1849 : { //not counting txtnodes used to hold deleted redline content
1850 : return;
1851 : }
1852 527 : bool bCountAll = ( (0 == nStt) && (GetTxt().Len() == nEnd) );
1853 527 : ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
1854 527 : if ( IsHidden() )
1855 : { // not counting hidden paras
1856 : return;
1857 : }
1858 : // count words in numbering string if started at beginning of para:
1859 527 : bool bCountNumbering = nStt == 0;
1860 527 : bool bHasBullet = false, bHasNumbering = false;
1861 527 : rtl::OUString sNumString;
1862 527 : if (bCountNumbering)
1863 : {
1864 527 : sNumString = GetNumString();
1865 527 : bHasNumbering = !sNumString.isEmpty();
1866 527 : if (!bHasNumbering)
1867 513 : bHasBullet = HasBullet();
1868 527 : bCountNumbering = bHasNumbering || bHasBullet;
1869 : }
1870 :
1871 527 : if( nStt == nEnd && !bCountNumbering)
1872 : { // unnumbered empty node or empty selection
1873 : return;
1874 : }
1875 :
1876 : // count of non-empty paras
1877 318 : ++rStat.nPara;
1878 :
1879 : // Shortcut when counting whole paragraph and current count is clean
1880 318 : if ( bCountAll && !IsWordCountDirty() )
1881 : {
1882 : // accumulate into DocStat record to return the values
1883 0 : rStat.nWord += GetParaNumberOfWords();
1884 0 : rStat.nAsianWord += GetParaNumberOfAsianWords();
1885 0 : rStat.nChar += GetParaNumberOfChars();
1886 0 : rStat.nCharExcludingSpaces += GetParaNumberOfCharsExcludingSpaces();
1887 : return;
1888 : }
1889 :
1890 : // ConversionMap to expand fields, remove invisible and redline deleted text for scanner
1891 318 : const ModelToViewHelper aConversionMap(*this, EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED);
1892 318 : rtl::OUString aExpandText = aConversionMap.getViewText();
1893 :
1894 : // map start and end points onto the ConversionMap
1895 318 : const sal_uInt32 nExpandBegin = aConversionMap.ConvertToViewPosition( nStt );
1896 318 : const sal_uInt32 nExpandEnd = aConversionMap.ConvertToViewPosition( nEnd );
1897 :
1898 318 : if (aExpandText.isEmpty() && !bCountNumbering)
1899 : {
1900 : OSL_ENSURE(aExpandText.getLength() >= 0, "Node text expansion error: length < 0." );
1901 : return;
1902 : }
1903 :
1904 : //do the count
1905 : // all counts exclude hidden paras and hidden+redlined within para
1906 : // definition of space/white chars in SwScanner (and BreakIter!)
1907 : // uses both u_isspace and BreakIter getWordBoundary in SwScanner
1908 207 : sal_uInt32 nTmpWords = 0; // count of all words
1909 207 : sal_uInt32 nTmpAsianWords = 0; //count of all Asian codepoints
1910 207 : sal_uInt32 nTmpChars = 0; // count of all chars
1911 207 : sal_uInt32 nTmpCharsExcludingSpaces = 0; // all non-white chars
1912 :
1913 : // count words in masked and expanded text:
1914 207 : if (!aExpandText.isEmpty())
1915 : {
1916 207 : if (pBreakIt->GetBreakIter().is())
1917 : {
1918 : // zero is NULL for pLanguage -----------v last param = true for clipping
1919 : SwScanner aScanner( *this, aExpandText, 0, aConversionMap, i18n::WordType::WORD_COUNT,
1920 207 : nExpandBegin, nExpandEnd, true );
1921 :
1922 : // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
1923 207 : const rtl::OUString aBreakWord( CH_TXTATR_BREAKWORD );
1924 :
1925 1076 : while ( aScanner.NextWord() )
1926 : {
1927 : // 1 is len(CH_TXTATR_BREAKWORD) : match returns length of match
1928 662 : if( 1 != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
1929 : {
1930 662 : ++nTmpWords;
1931 662 : const rtl::OUString &rWord = aScanner.GetWord();
1932 662 : if (pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
1933 49 : ++nTmpAsianWords;
1934 662 : nTmpCharsExcludingSpaces += pBreakIt->getGraphemeCount(rWord);
1935 : }
1936 : }
1937 :
1938 207 : nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
1939 : }
1940 :
1941 207 : nTmpChars = pBreakIt->getGraphemeCount(aExpandText, nExpandBegin, nExpandEnd);
1942 : }
1943 :
1944 : // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
1945 : // nor for mid-word selection - set scanner bClip = true at creation
1946 :
1947 : // count outline number label - ? no expansion into map
1948 : // always counts all of number-ish label
1949 207 : if (bHasNumbering) // count words in numbering string
1950 : {
1951 14 : LanguageType aLanguage = GetLang( 0 );
1952 :
1953 : SwScanner aScanner( *this, sNumString, &aLanguage, ModelToViewHelper(),
1954 14 : i18n::WordType::WORD_COUNT, 0, sNumString.getLength(), true );
1955 :
1956 42 : while ( aScanner.NextWord() )
1957 : {
1958 14 : ++nTmpWords;
1959 14 : const rtl::OUString &rWord = aScanner.GetWord();
1960 14 : if (pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
1961 0 : ++nTmpAsianWords;
1962 14 : nTmpCharsExcludingSpaces += pBreakIt->getGraphemeCount(rWord);
1963 : }
1964 :
1965 14 : nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
1966 14 : nTmpChars += pBreakIt->getGraphemeCount(sNumString);
1967 : }
1968 193 : else if ( bHasBullet )
1969 : {
1970 2 : ++nTmpWords;
1971 2 : ++nTmpChars;
1972 2 : ++nTmpCharsExcludingSpaces;
1973 : }
1974 :
1975 : // If counting the whole para then update cached values and mark clean
1976 207 : if ( bCountAll )
1977 : {
1978 207 : SetParaNumberOfWords( nTmpWords );
1979 207 : SetParaNumberOfAsianWords( nTmpAsianWords );
1980 207 : SetParaNumberOfChars( nTmpChars );
1981 207 : SetParaNumberOfCharsExcludingSpaces( nTmpCharsExcludingSpaces );
1982 207 : SetWordCountDirty( false );
1983 : }
1984 : // accumulate into DocStat record to return the values
1985 207 : rStat.nWord += nTmpWords;
1986 207 : rStat.nAsianWord += nTmpAsianWords;
1987 207 : rStat.nChar += nTmpChars;
1988 207 : rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
1989 : }
1990 :
1991 : //
1992 : // Paragraph statistics start
1993 : //
1994 : struct SwParaIdleData_Impl
1995 : {
1996 : SwWrongList* pWrong; // for spell checking
1997 : SwGrammarMarkUp* pGrammarCheck; // for grammar checking / proof reading
1998 : SwWrongList* pSmartTags;
1999 : sal_uLong nNumberOfWords;
2000 : sal_uLong nNumberOfAsianWords;
2001 : sal_uLong nNumberOfChars;
2002 : sal_uLong nNumberOfCharsExcludingSpaces;
2003 : bool bWordCountDirty;
2004 : bool bWrongDirty; // Ist das Wrong-Feld auf invalid?
2005 : bool bGrammarCheckDirty;
2006 : bool bSmartTagDirty;
2007 : bool bAutoComplDirty; // die ACompl-Liste muss angepasst werden
2008 :
2009 4651 : SwParaIdleData_Impl() :
2010 : pWrong ( 0 ),
2011 : pGrammarCheck ( 0 ),
2012 : pSmartTags ( 0 ),
2013 : nNumberOfWords ( 0 ),
2014 : nNumberOfAsianWords ( 0 ),
2015 : nNumberOfChars ( 0 ),
2016 : nNumberOfCharsExcludingSpaces ( 0 ),
2017 : bWordCountDirty ( true ),
2018 : bWrongDirty ( true ),
2019 : bGrammarCheckDirty ( true ),
2020 : bSmartTagDirty ( true ),
2021 4651 : bAutoComplDirty ( true ) {};
2022 : };
2023 :
2024 8360 : void SwTxtNode::InitSwParaStatistics( bool bNew )
2025 : {
2026 8360 : if ( bNew )
2027 : {
2028 4651 : m_pParaIdleData_Impl = new SwParaIdleData_Impl;
2029 : }
2030 3709 : else if ( m_pParaIdleData_Impl )
2031 : {
2032 3709 : delete m_pParaIdleData_Impl->pWrong;
2033 3709 : delete m_pParaIdleData_Impl->pGrammarCheck;
2034 3709 : delete m_pParaIdleData_Impl->pSmartTags;
2035 3709 : delete m_pParaIdleData_Impl;
2036 3709 : m_pParaIdleData_Impl = 0;
2037 : }
2038 8360 : }
2039 :
2040 1011 : void SwTxtNode::SetWrong( SwWrongList* pNew, bool bDelete )
2041 : {
2042 1011 : if ( m_pParaIdleData_Impl )
2043 : {
2044 855 : if ( bDelete )
2045 : {
2046 276 : delete m_pParaIdleData_Impl->pWrong;
2047 : }
2048 855 : m_pParaIdleData_Impl->pWrong = pNew;
2049 : }
2050 1011 : }
2051 :
2052 2908 : SwWrongList* SwTxtNode::GetWrong()
2053 : {
2054 2908 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
2055 : }
2056 :
2057 : // #i71360#
2058 0 : const SwWrongList* SwTxtNode::GetWrong() const
2059 : {
2060 0 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
2061 : }
2062 :
2063 1011 : void SwTxtNode::SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete )
2064 : {
2065 1011 : if ( m_pParaIdleData_Impl )
2066 : {
2067 855 : if ( bDelete )
2068 : {
2069 276 : delete m_pParaIdleData_Impl->pGrammarCheck;
2070 : }
2071 855 : m_pParaIdleData_Impl->pGrammarCheck = pNew;
2072 : }
2073 1011 : }
2074 :
2075 1908 : SwGrammarMarkUp* SwTxtNode::GetGrammarCheck()
2076 : {
2077 1908 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : 0;
2078 : }
2079 :
2080 1011 : void SwTxtNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
2081 : {
2082 : OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
2083 : "Weird - we have a smart tag list without any recognizers?" );
2084 :
2085 1011 : if ( m_pParaIdleData_Impl )
2086 : {
2087 855 : if ( bDelete )
2088 : {
2089 276 : delete m_pParaIdleData_Impl->pSmartTags;
2090 : }
2091 855 : m_pParaIdleData_Impl->pSmartTags = pNew;
2092 : }
2093 1011 : }
2094 :
2095 1908 : SwWrongList* SwTxtNode::GetSmartTags()
2096 : {
2097 1908 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : 0;
2098 : }
2099 :
2100 207 : void SwTxtNode::SetParaNumberOfWords( sal_uLong nNew ) const
2101 : {
2102 207 : if ( m_pParaIdleData_Impl )
2103 : {
2104 207 : m_pParaIdleData_Impl->nNumberOfWords = nNew;
2105 : }
2106 207 : }
2107 :
2108 0 : sal_uLong SwTxtNode::GetParaNumberOfWords() const
2109 : {
2110 0 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfWords : 0;
2111 : }
2112 :
2113 207 : void SwTxtNode::SetParaNumberOfAsianWords( sal_uLong nNew ) const
2114 : {
2115 207 : if ( m_pParaIdleData_Impl )
2116 : {
2117 207 : m_pParaIdleData_Impl->nNumberOfAsianWords = nNew;
2118 : }
2119 207 : }
2120 :
2121 0 : sal_uLong SwTxtNode::GetParaNumberOfAsianWords() const
2122 : {
2123 0 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfAsianWords : 0;
2124 : }
2125 :
2126 207 : void SwTxtNode::SetParaNumberOfChars( sal_uLong nNew ) const
2127 : {
2128 207 : if ( m_pParaIdleData_Impl )
2129 : {
2130 207 : m_pParaIdleData_Impl->nNumberOfChars = nNew;
2131 : }
2132 207 : }
2133 :
2134 0 : sal_uLong SwTxtNode::GetParaNumberOfChars() const
2135 : {
2136 0 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfChars : 0;
2137 : }
2138 :
2139 3101 : void SwTxtNode::SetWordCountDirty( bool bNew ) const
2140 : {
2141 3101 : if ( m_pParaIdleData_Impl )
2142 : {
2143 2945 : m_pParaIdleData_Impl->bWordCountDirty = bNew;
2144 : }
2145 3101 : }
2146 :
2147 0 : sal_uLong SwTxtNode::GetParaNumberOfCharsExcludingSpaces() const
2148 : {
2149 0 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces : 0;
2150 : }
2151 :
2152 207 : void SwTxtNode::SetParaNumberOfCharsExcludingSpaces( sal_uLong nNew ) const
2153 : {
2154 207 : if ( m_pParaIdleData_Impl )
2155 : {
2156 207 : m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces = nNew;
2157 : }
2158 207 : }
2159 :
2160 1346 : bool SwTxtNode::IsWordCountDirty() const
2161 : {
2162 1346 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWordCountDirty : 0;
2163 : }
2164 1475 : void SwTxtNode::SetWrongDirty( bool bNew ) const
2165 : {
2166 1475 : if ( m_pParaIdleData_Impl )
2167 : {
2168 1319 : m_pParaIdleData_Impl->bWrongDirty = bNew;
2169 : }
2170 1475 : }
2171 3628 : bool SwTxtNode::IsWrongDirty() const
2172 : {
2173 3628 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWrongDirty : 0;
2174 : }
2175 975 : void SwTxtNode::SetGrammarCheckDirty( bool bNew ) const
2176 : {
2177 975 : if ( m_pParaIdleData_Impl )
2178 : {
2179 819 : m_pParaIdleData_Impl->bGrammarCheckDirty = bNew;
2180 : }
2181 975 : }
2182 2815 : bool SwTxtNode::IsGrammarCheckDirty() const
2183 : {
2184 2815 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bGrammarCheckDirty : 0;
2185 : }
2186 975 : void SwTxtNode::SetSmartTagDirty( bool bNew ) const
2187 : {
2188 975 : if ( m_pParaIdleData_Impl )
2189 : {
2190 819 : m_pParaIdleData_Impl->bSmartTagDirty = bNew;
2191 : }
2192 975 : }
2193 273 : bool SwTxtNode::IsSmartTagDirty() const
2194 : {
2195 273 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bSmartTagDirty : 0;
2196 : }
2197 49112 : void SwTxtNode::SetAutoCompleteWordDirty( bool bNew ) const
2198 : {
2199 49112 : if ( m_pParaIdleData_Impl )
2200 : {
2201 48956 : m_pParaIdleData_Impl->bAutoComplDirty = bNew;
2202 : }
2203 49112 : }
2204 3355 : bool SwTxtNode::IsAutoCompleteWordDirty() const
2205 : {
2206 3355 : return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bAutoComplDirty : 0;
2207 : }
2208 : //
2209 : // Paragraph statistics end
2210 : //
2211 :
2212 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|