LibreOffice Module sw (master) 1
txtedt.cxx
Go to the documentation of this file.
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#include <config_wasm_strip.h>
21
22#include <hintids.hxx>
23#include <utility>
24#include <vcl/svapp.hxx>
25#include <svl/itemiter.hxx>
27#include <editeng/splwrap.hxx>
28#include <editeng/langitem.hxx>
29#include <editeng/fontitem.hxx>
32#include <SwSmartTagMgr.hxx>
33#include <o3tl/safeint.hxx>
34#include <osl/diagnose.h>
35#include <officecfg/Office/Writer.hxx>
38#include <sal/log.hxx>
39#include <swmodule.hxx>
40#include <splargs.hxx>
41#include <viewopt.hxx>
42#include <acmplwrd.hxx>
43#include <doc.hxx>
46#include <docsh.hxx>
47#include <txtfld.hxx>
48#include <txatbase.hxx>
49#include <charatr.hxx>
50#include <pam.hxx>
51#include <hints.hxx>
52#include <ndtxt.hxx>
53#include <txtfrm.hxx>
54#include <SwGrammarMarkUp.hxx>
55#include <rootfrm.hxx>
56#include <swscanner.hxx>
57
58#include <breakit.hxx>
59#include <UndoOverwrite.hxx>
60#include <txatritr.hxx>
61#include <redline.hxx>
62#include <docary.hxx>
63#include <scriptinfo.hxx>
64#include <docstat.hxx>
65#include <editsh.hxx>
66#include <unotextmarkup.hxx>
67#include <txtatr.hxx>
68#include <fmtautofmt.hxx>
69#include <istyleaccess.hxx>
70#include <unicode/uchar.h>
72
73#include <com/sun/star/i18n/WordType.hpp>
74#include <com/sun/star/i18n/ScriptType.hpp>
75#include <com/sun/star/i18n/XBreakIterator.hpp>
76
77#include <vector>
78
79#include <unotextrange.hxx>
80
81using namespace ::com::sun::star;
82using namespace ::com::sun::star::frame;
83using namespace ::com::sun::star::i18n;
84using namespace ::com::sun::star::beans;
85using namespace ::com::sun::star::uno;
86using namespace ::com::sun::star::linguistic2;
87using namespace ::com::sun::star::smarttags;
88
89namespace
90{
91 void DetectAndMarkMissingDictionaries( SwDoc& rDoc,
92 const uno::Reference< XSpellChecker1 >& xSpell,
93 const LanguageType eActLang )
94 {
95 if( xSpell.is() && !xSpell->hasLanguage( eActLang.get() ) )
96 rDoc.SetMissingDictionaries( true );
97 else
98 rDoc.SetMissingDictionaries( false );
99 }
100}
101
102static bool lcl_HasComments(const SwTextNode& rNode)
103{
104 sal_Int32 nPosition = rNode.GetText().indexOf(CH_TXTATR_INWORD);
105 while (nPosition != -1)
106 {
107 const SwTextAttr* pAttr = rNode.GetTextAttrForCharAt(nPosition);
108 if (pAttr && pAttr->Which() == RES_TXTATR_ANNOTATION)
109 return true;
110 nPosition = rNode.GetText().indexOf(CH_TXTATR_INWORD, nPosition + 1);
111 }
112 return false;
113}
114
115// possible delimiter characters within URLs for word breaking
116static bool lcl_IsDelim( const sal_Unicode c )
117{
118 return '#' == c || '$' == c || '%' == c || '&' == c || '+' == c ||
119 ',' == c || '-' == c || '.' == c || '/' == c || ':' == c ||
120 ';' == c || '=' == c || '?' == c || '@' == c || '_' == c;
121}
122
123// allow to check normal text with hyperlink by recognizing (parts of) URLs
124static bool lcl_IsURL(std::u16string_view rWord,
125 SwTextNode &rNode, sal_Int32 nBegin, sal_Int32 nLen)
126{
127 // not a text with hyperlink
128 if ( !rNode.GetTextAttrAt(nBegin, RES_TXTATR_INETFMT) )
129 return false;
130
131 // there is a dot in the word, which is not a period ("example.org")
132 const size_t nPosAt = rWord.find('.');
133 if (nPosAt != std::u16string_view::npos && nPosAt < rWord.length() - 1)
134 return true;
135
136 // an e-mail address ("user@example")
137 if ( rWord.find('@') != std::u16string_view::npos )
138 return true;
139
140 const OUString& rText = rNode.GetText();
141
142 // scheme (e.g. "http" in "http://" or "mailto" in "mailto:address"):
143 // word is followed by 1) ':' + an alphanumeric character; 2) or ':' + a delimiter
144 if ( nBegin + nLen + 2 <= rText.getLength() && ':' == rText[nBegin + nLen] )
145 {
146 sal_Unicode c = rText[nBegin + nLen + 1];
147 if ( u_isalnum(c) || lcl_IsDelim(c) )
148 return true;
149 }
150
151 // path, query, fragment (e.g. "path" in "example.org/path"):
152 // word is preceded by 1) an alphanumeric character + a delimiter; 2) or two delimiters
153 if ( 2 <= nBegin && lcl_IsDelim(rText[nBegin - 1]) )
154 {
155 sal_Unicode c = rText[nBegin - 2];
156 if ( u_isalnum(c) || lcl_IsDelim(c) )
157 return true;
158 }
159
160 return false;
161}
162
163/*
164 * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
165 * only for deleted redlines
166 */
167
168static sal_Int32
169lcl_MaskRedlines( const SwTextNode& rNode, OUStringBuffer& rText,
170 sal_Int32 nStt, sal_Int32 nEnd,
171 const sal_Unicode cChar )
172{
173 sal_Int32 nNumOfMaskedRedlines = 0;
174
175 const SwDoc& rDoc = rNode.GetDoc();
176
177 for ( SwRedlineTable::size_type nAct = rDoc.getIDocumentRedlineAccess().GetRedlinePos( rNode, RedlineType::Any ); nAct < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); ++nAct )
178 {
179 const SwRangeRedline* pRed = rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
180
181 if ( pRed->Start()->GetNode() > rNode )
182 break;
183
184 if( RedlineType::Delete == pRed->GetType() )
185 {
186 sal_Int32 nRedlineEnd;
187 sal_Int32 nRedlineStart;
188
189 pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
190
191 if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
192 continue;
193
194 while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
195 {
196 if (nRedlineStart >= nStt)
197 {
198 rText[nRedlineStart] = cChar;
199 ++nNumOfMaskedRedlines;
200 }
201 ++nRedlineStart;
202 }
203 }
204 }
205
206 return nNumOfMaskedRedlines;
207}
208
212static bool
213lcl_MaskRedlinesAndHiddenText( const SwTextNode& rNode, OUStringBuffer& rText,
214 sal_Int32 nStt, sal_Int32 nEnd,
215 const sal_Unicode cChar = CH_TXTATR_INWORD )
216{
217 sal_Int32 nRedlinesMasked = 0;
218 sal_Int32 nHiddenCharsMasked = 0;
219
220 const SwDoc& rDoc = rNode.GetDoc();
222
223 // If called from word count or from spell checking, deleted redlines
224 // should be masked:
225 if ( bShowChg )
226 {
227 nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
228 }
229
230 const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE))->IsShowHiddenChar();
231
232 // If called from word count, we want to mask the hidden ranges even
233 // if they are visible:
234 if ( bHideHidden )
235 {
236 nHiddenCharsMasked =
237 SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
238 }
239
240 return (nRedlinesMasked > 0) || (nHiddenCharsMasked > 0);
241}
242
247 const SwTextFrame & rTextFrame, const SwTextNode & rNode,
248 sal_Int32 const nChgStart, sal_Int32 const nChgEnd)
249{
250 TextFrameIndex const iChgStart(rTextFrame.MapModelToView(&rNode, nChgStart));
251 TextFrameIndex const iChgEnd(rTextFrame.MapModelToView(&rNode, nChgEnd));
252
253 SwRect aRect = rTextFrame.GetPaintArea();
254 SwRect aTmp = rTextFrame.GetPaintArea();
255
256 const SwTextFrame* pStartFrame = &rTextFrame;
257 while( pStartFrame->HasFollow() &&
258 iChgStart >= pStartFrame->GetFollow()->GetOffset())
259 pStartFrame = pStartFrame->GetFollow();
260 const SwTextFrame* pEndFrame = pStartFrame;
261 while( pEndFrame->HasFollow() &&
262 iChgEnd >= pEndFrame->GetFollow()->GetOffset())
263 pEndFrame = pEndFrame->GetFollow();
264
265 bool bSameFrame = true;
266
267 if( rTextFrame.HasFollow() )
268 {
269 if( pEndFrame != pStartFrame )
270 {
271 bSameFrame = false;
272 SwRect aStFrame( pStartFrame->GetPaintArea() );
273 {
274 SwRectFnSet aRectFnSet(pStartFrame);
275 aRectFnSet.SetLeft( aTmp, aRectFnSet.GetLeft(aStFrame) );
276 aRectFnSet.SetRight( aTmp, aRectFnSet.GetRight(aStFrame) );
277 aRectFnSet.SetBottom( aTmp, aRectFnSet.GetBottom(aStFrame) );
278 }
279 aStFrame = pEndFrame->GetPaintArea();
280 {
281 SwRectFnSet aRectFnSet(pEndFrame);
282 aRectFnSet.SetTop( aRect, aRectFnSet.GetTop(aStFrame) );
283 aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aStFrame) );
284 aRectFnSet.SetRight( aRect, aRectFnSet.GetRight(aStFrame) );
285 }
286 aRect.Union( aTmp );
287 while( true )
288 {
289 pStartFrame = pStartFrame->GetFollow();
290 if( pStartFrame == pEndFrame )
291 break;
292 aRect.Union( pStartFrame->GetPaintArea() );
293 }
294 }
295 }
296 if( bSameFrame )
297 {
298 SwRectFnSet aRectFnSet(pStartFrame);
299 if( aRectFnSet.GetTop(aTmp) == aRectFnSet.GetTop(aRect) )
300 aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aTmp) );
301 else
302 {
303 SwRect aStFrame( pStartFrame->GetPaintArea() );
304 aRectFnSet.SetLeft( aRect, aRectFnSet.GetLeft(aStFrame) );
305 aRectFnSet.SetRight( aRect, aRectFnSet.GetRight(aStFrame) );
306 aRectFnSet.SetTop( aRect, aRectFnSet.GetTop(aTmp) );
307 }
308
309 if( aTmp.Height() > aRect.Height() )
310 aRect.Height( aTmp.Height() );
311 }
312
313 return aRect;
314}
315
319static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
320 const SfxItemSet* pSet1,
321 sal_uInt16 nWhichId,
322 const SfxItemSet& rSet2,
323 std::shared_ptr<SfxItemSet>& pStyleHandle )
324{
325 bool bRet = false;
326
327 std::unique_ptr<SfxItemSet> pNewSet;
328
329 if ( !pSet1 )
330 {
331 OSL_ENSURE( nWhichId, "lcl_HaveCommonAttributes not used correctly" );
332 if ( SfxItemState::SET == rSet2.GetItemState( nWhichId, false ) )
333 {
334 pNewSet = rSet2.Clone();
335 pNewSet->ClearItem( nWhichId );
336 }
337 }
338 else if ( pSet1->Count() )
339 {
340 SfxItemIter aIter( *pSet1 );
341 const SfxPoolItem* pItem = aIter.GetCurItem();
342 do
343 {
344 if ( SfxItemState::SET == rSet2.GetItemState( pItem->Which(), false ) )
345 {
346 if ( !pNewSet )
347 pNewSet = rSet2.Clone();
348 pNewSet->ClearItem( pItem->Which() );
349 }
350
351 pItem = aIter.NextItem();
352 } while (pItem);
353 }
354
355 if ( pNewSet )
356 {
357 if ( pNewSet->Count() )
358 pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
359 bRet = true;
360 }
361
362 return bRet;
363}
364
389 sal_Int32 nStt,
390 const sal_Int32 nLen,
391 const sal_uInt16 nWhich,
392 const SfxItemSet* pSet,
393 const bool bInclRefToxMark,
394 const bool bExactRange )
395{
396 if ( !GetpSwpHints() )
397 return;
398
399 sal_Int32 nEnd = nStt + nLen;
400 {
401 // enlarge range for the reset of text attributes in case of an overlapping input field
402 const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nStt, RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
403 if ( pTextInputField == nullptr )
404 {
405 pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nEnd, RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
406 }
407 if ( pTextInputField != nullptr )
408 {
409 if ( nStt > pTextInputField->GetStart() )
410 {
411 nStt = pTextInputField->GetStart();
412 }
413 if ( nEnd < *(pTextInputField->End()) )
414 {
415 nEnd = *(pTextInputField->End());
416 }
417 }
418 }
419
420 bool bChanged = false;
421
422 // nMin and nMax initialized to maximum / minimum (inverse)
423 sal_Int32 nMin = m_Text.getLength();
424 sal_Int32 nMax = nStt;
425 const bool bNoLen = nMin == 0;
426
427 // We have to remember the "new" attributes that have
428 // been introduced by splitting surrounding attributes (case 2,3,4).
429 std::vector<SwTextAttr *> newAttributes;
430 std::vector<SwTextAttr *> delAttributes;
431
432 // iterate over attribute array until start of attribute is behind deletion range
433 m_pSwpHints->SortIfNeedBe(); // trigger sorting now, we don't want it during iteration
434 size_t i = 0;
435 sal_Int32 nAttrStart = sal_Int32();
436 SwTextAttr *pHt = nullptr;
437 while ( (i < m_pSwpHints->Count())
438 && ( ( ( nAttrStart = m_pSwpHints->GetWithoutResorting(i)->GetStart()) < nEnd )
439 || nLen==0 || (nEnd == nAttrStart && nAttrStart == m_Text.getLength()))
440 && !bExactRange)
441 {
442 pHt = m_pSwpHints->GetWithoutResorting(i);
443
444 // attributes without end stay in!
445 // but consider <bInclRefToxMark> used by Undo
446 const sal_Int32* const pAttrEnd = pHt->GetEnd();
447 const bool bKeepAttrWithoutEnd =
448 pAttrEnd == nullptr
449 && ( !bInclRefToxMark
450 || ( RES_TXTATR_REFMARK != pHt->Which()
451 && RES_TXTATR_TOXMARK != pHt->Which()
452 && RES_TXTATR_META != pHt->Which()
453 && RES_TXTATR_METAFIELD != pHt->Which() ) );
454 if ( bKeepAttrWithoutEnd )
455 {
456
457 i++;
458 continue;
459 }
460 // attributes with content stay in
461 if ( pHt->HasContent() )
462 {
463 ++i;
464 continue;
465 }
466
467 // Default behavior is to process all attributes:
468 bool bSkipAttr = false;
469 std::shared_ptr<SfxItemSet> pStyleHandle;
470
471 // 1. case: We want to reset only the attributes listed in pSet:
472 if ( pSet )
473 {
474 bSkipAttr = SfxItemState::SET != pSet->GetItemState( pHt->Which(), false );
475 if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
476 {
477 // if the current attribute is an autostyle, we have to check if the autostyle
478 // and pSet have any attributes in common. If so, pStyleHandle will contain
479 // a handle to AutoStyle / pSet:
480 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFormatAutoFormat&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
481 }
482 }
483 else if ( nWhich )
484 {
485 // 2. case: We want to reset only the attributes with WhichId nWhich:
486 bSkipAttr = nWhich != pHt->Which();
487 if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
488 {
489 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), nullptr, nWhich, *static_cast<const SwFormatAutoFormat&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
490 }
491 }
492 else if ( !bInclRefToxMark )
493 {
494 // 3. case: Reset all attributes except from ref/toxmarks:
495 // skip hints with CH_TXTATR here
496 // (deleting those is ONLY allowed for UNDO!)
497 bSkipAttr = RES_TXTATR_REFMARK == pHt->Which()
498 || RES_TXTATR_TOXMARK == pHt->Which()
499 || RES_TXTATR_META == pHt->Which()
500 || RES_TXTATR_METAFIELD == pHt->Which();
501 }
502
503 if ( bSkipAttr )
504 {
505 i++;
506 continue;
507 }
508
509 if (nStt <= nAttrStart) // Case: 1,3,5
510 {
511 const sal_Int32 nAttrEnd = pAttrEnd != nullptr
512 ? *pAttrEnd
513 : nAttrStart;
514 if (nEnd > nAttrStart
515 || (nEnd == nAttrEnd && nEnd == nAttrStart)) // Case: 1,3
516 {
517 if ( nMin > nAttrStart )
518 nMin = nAttrStart;
519 if ( nMax < nAttrEnd )
520 nMax = nAttrEnd;
521 // If only a no-extent hint is deleted, no resorting is needed
522 bChanged = bChanged || nEnd > nAttrStart || bNoLen;
523 if (nAttrEnd <= nEnd) // Case: 1
524 {
525 delAttributes.push_back(pHt);
526
527 if ( pStyleHandle )
528 {
529 SwTextAttr* pNew = MakeTextAttr( GetDoc(),
530 *pStyleHandle, nAttrStart, nAttrEnd );
531 newAttributes.push_back(pNew);
532 }
533 }
534 else // Case: 3
535 {
536 bChanged = true;
537 m_pSwpHints->NoteInHistory( pHt );
538 // UGLY: this may temporarily destroy the sorting!
539 pHt->SetStart(nEnd);
540 m_pSwpHints->NoteInHistory( pHt, true );
541
542 if ( pStyleHandle && nAttrStart < nEnd )
543 {
544 SwTextAttr* pNew = MakeTextAttr( GetDoc(),
545 *pStyleHandle, nAttrStart, nEnd );
546 newAttributes.push_back(pNew);
547 }
548 }
549 }
550 }
551 else if (pAttrEnd != nullptr) // Case: 2,4,5
552 {
553 if (*pAttrEnd > nStt) // Case: 2,4
554 {
555 if (*pAttrEnd < nEnd) // Case: 2
556 {
557 if ( nMin > nAttrStart )
558 nMin = nAttrStart;
559 if ( nMax < *pAttrEnd )
560 nMax = *pAttrEnd;
561 bChanged = true;
562
563 const sal_Int32 nAttrEnd = *pAttrEnd;
564
565 m_pSwpHints->NoteInHistory( pHt );
566 // UGLY: this may temporarily destroy the sorting!
567 pHt->SetEnd(nStt);
568 m_pSwpHints->NoteInHistory( pHt, true );
569
570 if ( pStyleHandle )
571 {
572 SwTextAttr* pNew = MakeTextAttr( GetDoc(),
573 *pStyleHandle, nStt, nAttrEnd );
574 newAttributes.push_back(pNew);
575 }
576 }
577 else if (nLen) // Case: 4
578 {
579 // for Length 0 both hints would be merged again by
580 // InsertHint, so leave them alone!
581 if ( nMin > nAttrStart )
582 nMin = nAttrStart;
583 if ( nMax < *pAttrEnd )
584 nMax = *pAttrEnd;
585 bChanged = true;
586 const sal_Int32 nTmpEnd = *pAttrEnd;
587 m_pSwpHints->NoteInHistory( pHt );
588 // UGLY: this may temporarily destroy the sorting!
589 pHt->SetEnd(nStt);
590 m_pSwpHints->NoteInHistory( pHt, true );
591
592 if ( pStyleHandle && nStt < nEnd )
593 {
594 SwTextAttr* pNew = MakeTextAttr( GetDoc(),
595 *pStyleHandle, nStt, nEnd );
596 newAttributes.push_back(pNew);
597 }
598
599 if( nEnd < nTmpEnd )
600 {
601 SwTextAttr* pNew = MakeTextAttr( GetDoc(),
602 pHt->GetAttr(), nEnd, nTmpEnd );
603 if ( pNew )
604 {
605 SwTextCharFormat* pCharFormat = dynamic_cast<SwTextCharFormat*>(pHt);
606 if ( pCharFormat )
607 static_txtattr_cast<SwTextCharFormat*>(pNew)->SetSortNumber(pCharFormat->GetSortNumber());
608
609 newAttributes.push_back(pNew);
610 }
611 }
612 }
613 }
614 }
615 ++i;
616 }
617
618 if (bExactRange)
619 {
620 // Only delete the hints which start at nStt and end at nEnd.
621 for (i = 0; i < m_pSwpHints->Count(); ++i)
622 {
623 SwTextAttr* pHint = m_pSwpHints->Get(i);
624 if ( (isTXTATR_WITHEND(pHint->Which()) && RES_TXTATR_AUTOFMT != pHint->Which())
625 || pHint->GetStart() != nStt)
626 continue;
627
628 const sal_Int32* pHintEnd = pHint->GetEnd();
629 if (!pHintEnd || *pHintEnd != nEnd)
630 continue;
631
632 delAttributes.push_back(pHint);
633 }
634 }
635
636 if (bChanged && !delAttributes.empty())
637 { // Delete() calls GetStartOf() - requires sorted hints!
638 m_pSwpHints->Resort();
639 }
640
641 // delay deleting the hints because it re-sorts the hints array
642 for (SwTextAttr *const pDel : delAttributes)
643 {
644 m_pSwpHints->Delete(pDel);
645 DestroyAttr(pDel);
646 }
647
648 // delay inserting the hints because it re-sorts the hints array
649 for (SwTextAttr *const pNew : newAttributes)
650 {
652 }
653
655
656 if (!bChanged)
657 return;
658
659 if ( HasHints() )
660 { // possibly sometimes Resort would be sufficient, but...
661 m_pSwpHints->MergePortions(*this);
662 }
663
664 // TextFrame's respond to aHint, others to aNew
665 SwUpdateAttr aHint(
666 nMin,
667 nMax,
668 0);
669
670 CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aHint));
671 SwFormatChg aNew( GetFormatColl() );
672 CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aNew));
673}
674
675static sal_Int32 clipIndexBounds(std::u16string_view aStr, sal_Int32 nPos)
676{
677 if (nPos < 0)
678 return 0;
679 if (nPos > sal_Int32(aStr.size()))
680 return aStr.size();
681 return nPos;
682}
683
684// Return current word:
685// Search from left to right, so find the word before nPos.
686// Except if at the start of the paragraph, then return the first word.
687// If the first word consists only of whitespace, return an empty string.
688OUString SwTextFrame::GetCurWord(SwPosition const& rPos) const
689{
691 SwTextNode *const pTextNode(rPos.GetNode().GetTextNode());
692 assert(pTextNode);
693 OUString const& rText(GetText());
694 assert(sal_Int32(nPos) <= rText.getLength()); // invalid index
695
696 if (rText.isEmpty() || IsHiddenNow())
697 return OUString();
698
699 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
700 const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
701 sal_Int16 nWordType = WordType::DICTIONARY_WORD;
702 lang::Locale aLocale( g_pBreakIt->GetLocale(pTextNode->GetLang(rPos.GetContentIndex())) );
703 Boundary aBndry =
704 rxBreak->getWordBoundary(rText, sal_Int32(nPos), aLocale, nWordType, true);
705
706 // if no word was found use previous word (if any)
707 if (aBndry.startPos == aBndry.endPos)
708 {
709 aBndry = rxBreak->previousWord(rText, sal_Int32(nPos), aLocale, nWordType);
710 }
711
712 // check if word was found and if it uses a symbol font, if so
713 // enforce returning an empty string
714 if (aBndry.endPos != aBndry.startPos
715 && IsSymbolAt(TextFrameIndex(aBndry.startPos)))
716 {
717 aBndry.endPos = aBndry.startPos;
718 }
719
720 // can have -1 as start/end of bounds not found
721 aBndry.startPos = clipIndexBounds(rText, aBndry.startPos);
722 aBndry.endPos = clipIndexBounds(rText, aBndry.endPos);
723
724 return rText.copy(aBndry.startPos,
725 aBndry.endPos - aBndry.startPos);
726}
727
728SwScanner::SwScanner( const SwTextNode& rNd, const OUString& rText,
729 const LanguageType* pLang, const ModelToViewHelper& rConvMap,
730 sal_uInt16 nType, sal_Int32 nStart, sal_Int32 nEnd, bool bClp )
731 : SwScanner(
732 [&rNd](sal_Int32 const nBegin, sal_uInt16 const nScript, bool const bNoChar)
733 { return rNd.GetLang(nBegin, bNoChar ? 0 : 1, nScript); }
734 , rText, pLang, rConvMap, nType, nStart, nEnd, bClp)
735{
736}
737
738SwScanner::SwScanner(std::function<LanguageType(sal_Int32, sal_Int32, bool)> aGetLangOfChar,
739 OUString aText, const LanguageType* pLang,
740 ModelToViewHelper aConvMap, sal_uInt16 nType, sal_Int32 nStart,
741 sal_Int32 nEnd, bool bClp)
742 : m_pGetLangOfChar(std::move(aGetLangOfChar))
743 , m_aPreDashReplacementText(std::move(aText))
744 , m_pLanguage(pLang)
745 , m_ModelToView(std::move(aConvMap))
746 , m_nLength(0)
747 , m_nOverriddenDashCount(0)
748 , m_nWordType(nType)
749 , m_bClip(bClp)
750{
751 m_nStartPos = m_nBegin = nStart;
752 m_nEndPos = nEnd;
753
754 //MSWord f.e has special emdash and endash behaviour in that they break
755 //words for the purposes of word counting, while a hyphen etc. doesn't.
756
757 //The default configuration treats emdash/endash as a word break, but
758 //additional ones can be added in under tools->options
759 if (m_nWordType == i18n::WordType::WORD_COUNT)
760 {
762 OUStringBuffer aBuf(m_aPreDashReplacementText);
763 for (sal_Int32 i = m_nStartPos; i < m_nEndPos; ++i)
764 {
765 if (i < 0)
766 continue;
767 sal_Unicode cChar = aBuf[i];
768 if (sDashes.indexOf(cChar) != -1)
769 {
770 aBuf[i] = ' ';
772 }
773 }
774 m_aText = aBuf.makeStringAndClear();
775 }
776 else
778
779 assert(m_aPreDashReplacementText.getLength() == m_aText.getLength());
780
781 if ( m_pLanguage )
782 {
784 }
785 else
786 {
787 ModelToViewHelper::ModelPosition aModelBeginPos =
789 m_aCurrentLang = m_pGetLangOfChar(aModelBeginPos.mnPos, 0, true);
790 }
791}
792
793namespace
794{
795 //fdo#45271 for Asian words count characters instead of words
796 sal_Int32 forceEachAsianCodePointToWord(const OUString &rText, sal_Int32 nBegin, sal_Int32 nLen)
797 {
798 if (nLen > 1)
799 {
800 const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
801
802 sal_uInt16 nCurrScript = rxBreak->getScriptType( rText, nBegin );
803
804 sal_Int32 indexUtf16 = nBegin;
805 rText.iterateCodePoints(&indexUtf16);
806
807 //First character is Asian, consider it a word :-(
808 if (nCurrScript == i18n::ScriptType::ASIAN)
809 {
810 nLen = indexUtf16 - nBegin;
811 return nLen;
812 }
813
814 //First character was not Asian, consider appearance of any Asian character
815 //to be the end of the word
816 while (indexUtf16 < nBegin + nLen)
817 {
818 nCurrScript = rxBreak->getScriptType( rText, indexUtf16 );
819 if (nCurrScript == i18n::ScriptType::ASIAN)
820 {
821 nLen = indexUtf16 - nBegin;
822 return nLen;
823 }
824 rText.iterateCodePoints(&indexUtf16);
825 }
826 }
827 return nLen;
828 }
829}
830
832{
834 Boundary aBound;
835
836 std::optional<CharClass> xLocalCharClass;
837
838 while ( true )
839 {
840 // skip non-letter characters:
841 while (m_nBegin < m_aText.getLength())
842 {
843 if (m_nBegin >= 0 && !u_isspace(m_aText[m_nBegin]))
844 {
845 if ( !m_pLanguage )
846 {
847 const sal_uInt16 nNextScriptType = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, m_nBegin );
848 ModelToViewHelper::ModelPosition aModelBeginPos =
850 m_aCurrentLang = m_pGetLangOfChar(aModelBeginPos.mnPos, nNextScriptType, false);
851 }
852
853 if ( m_nWordType != i18n::WordType::WORD_COUNT )
854 {
855 xLocalCharClass.emplace(LanguageTag( g_pBreakIt->GetLocale( m_aCurrentLang ) ));
856 if ( xLocalCharClass->isLetterNumeric(OUString(m_aText[m_nBegin])) )
857 break;
858 }
859 else
860 break;
861 }
862 ++m_nBegin;
863 }
864
865 if ( m_nBegin >= m_aText.getLength() || m_nBegin >= m_nEndPos )
866 return false;
867
868 // get the word boundaries
869 aBound = g_pBreakIt->GetBreakIter()->getWordBoundary( m_aText, m_nBegin,
871 OSL_ENSURE( aBound.endPos >= aBound.startPos, "broken aBound result" );
872
873 // we don't want to include preceding text
874 // to count words in text with mixed script punctuation correctly,
875 // but we want to include preceding symbols (eg. percent sign, section sign,
876 // degree sign defined by dict_word_hu to spell check their affixed forms).
877 if (m_nWordType == i18n::WordType::WORD_COUNT && aBound.startPos < m_nBegin)
878 aBound.startPos = m_nBegin;
879
880 //no word boundaries could be found
881 if(aBound.endPos == aBound.startPos)
882 return false;
883
884 //if a word before is found it has to be searched for the next
885 if(aBound.endPos == m_nBegin)
886 ++m_nBegin;
887 else
888 break;
889 } // end while( true )
890
891 // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
892 if ( m_nWordType == i18n::WordType::WORD_COUNT )
893 {
894 m_nBegin = std::max(aBound.startPos, m_nBegin);
895 m_nLength = 0;
896 if (aBound.endPos > m_nBegin)
897 m_nLength = aBound.endPos - m_nBegin;
898 }
899 else
900 {
901 // we have to differentiate between these cases:
902 if ( aBound.startPos <= m_nBegin )
903 {
904 OSL_ENSURE( aBound.endPos >= m_nBegin, "Unexpected aBound result" );
905
906 // restrict boundaries to script boundaries and nEndPos
907 const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, m_nBegin );
908 OUString aTmpWord = m_aText.copy( m_nBegin, aBound.endPos - m_nBegin );
909 const sal_Int32 nScriptEnd = m_nBegin +
910 g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
911 const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
912
913 // restrict word start to last script change position
914 sal_Int32 nScriptBegin = 0;
915 if ( aBound.startPos < m_nBegin )
916 {
917 // search from nBegin backwards until the next script change
918 aTmpWord = m_aText.copy( aBound.startPos,
919 m_nBegin - aBound.startPos + 1 );
920 nScriptBegin = aBound.startPos +
921 g_pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, m_nBegin - aBound.startPos,
922 nCurrScript );
923 }
924
925 m_nBegin = std::max( aBound.startPos, nScriptBegin );
926 m_nLength = nEnd - m_nBegin;
927 }
928 else
929 {
930 const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( m_aText, aBound.startPos );
931 OUString aTmpWord = m_aText.copy( aBound.startPos,
932 aBound.endPos - aBound.startPos );
933 const sal_Int32 nScriptEnd = aBound.startPos +
934 g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
935 const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
936 m_nBegin = aBound.startPos;
937 m_nLength = nEnd - m_nBegin;
938 }
939 }
940
941 // optionally clip the result of getWordBoundaries:
942 if ( m_bClip )
943 {
944 aBound.startPos = std::max( aBound.startPos, m_nStartPos );
945 aBound.endPos = std::min( aBound.endPos, m_nEndPos );
946 if (aBound.endPos < aBound.startPos)
947 {
949 m_nLength = 0; // found word is outside of search interval
950 }
951 else
952 {
953 m_nBegin = aBound.startPos;
954 m_nLength = aBound.endPos - m_nBegin;
955 }
956 }
957
958 if( ! m_nLength )
959 return false;
960
961 if ( m_nWordType == i18n::WordType::WORD_COUNT )
962 m_nLength = forceEachAsianCodePointToWord(m_aText, m_nBegin, m_nLength);
963
966
967 return true;
968}
969
970// Note: this is a clone of SwTextFrame::AutoSpell_, so keep them in sync when fixing things!
972{
973 // modify string according to redline information and hidden text
974 const OUString aOldText( m_Text );
975 OUStringBuffer buf(m_Text);
976 const bool bContainsComments = lcl_HasComments(*this);
977 const bool bRestoreString =
978 lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength());
979 if (bRestoreString)
980 { // ??? UGLY: is it really necessary to modify m_Text here?
981 m_Text = buf.makeStringAndClear();
982 }
983
984 sal_Int32 nBegin = ( &pArgs->pStartPos->GetNode() != this )
985 ? 0
986 : pArgs->pStartPos->GetContentIndex();
987
988 sal_Int32 nEnd = ( &pArgs->pEndPos->GetNode() != this )
989 ? m_Text.getLength()
990 : pArgs->pEndPos->GetContentIndex();
991
992 pArgs->xSpellAlt = nullptr;
993
994 // 4 cases:
995
996 // 1. IsWrongDirty = 0 and GetWrong = 0
997 // Everything is checked and correct
998 // 2. IsWrongDirty = 0 and GetWrong = 1
999 // Everything is checked and errors are identified in the wrong list
1000 // 3. IsWrongDirty = 1 and GetWrong = 0
1001 // Nothing has been checked
1002 // 4. IsWrongDirty = 1 and GetWrong = 1
1003 // Text has been checked but there is an invalid range in the wrong list
1004
1005 // Nothing has to be done for case 1.
1006 if ( ( IsWrongDirty() || GetWrong() ) && m_Text.getLength() )
1007 {
1008 if (nBegin > m_Text.getLength())
1009 {
1010 nBegin = m_Text.getLength();
1011 }
1012 if (nEnd > m_Text.getLength())
1013 {
1014 nEnd = m_Text.getLength();
1015 }
1016
1017 if(!IsWrongDirty())
1018 {
1019 const sal_Int32 nTemp = GetWrong()->NextWrong( nBegin );
1020 if(nTemp > nEnd)
1021 {
1022 // reset original text
1023 if ( bRestoreString )
1024 {
1025 m_Text = aOldText;
1026 }
1027 return false;
1028 }
1029 if(nTemp > nBegin)
1030 nBegin = nTemp;
1031
1032 }
1033
1034 // In case 2. we pass the wrong list to the scanned, because only
1035 // the words in the wrong list have to be checked
1036 SwScanner aScanner( *this, m_Text, nullptr, ModelToViewHelper(),
1037 WordType::DICTIONARY_WORD,
1038 nBegin, nEnd );
1039 bool bNextWord = aScanner.NextWord();
1040 while( !pArgs->xSpellAlt.is() && bNextWord )
1041 {
1042 bool bCalledNextWord = false;
1043
1044 const OUString& rWord = aScanner.GetWord();
1045
1046 // get next language for next word, consider language attributes
1047 // within the word
1048 LanguageType eActLang = aScanner.GetCurrentLanguage();
1049 DetectAndMarkMissingDictionaries( GetTextNode()->GetDoc(), pArgs->xSpeller, eActLang );
1050
1051 if( rWord.getLength() > 0 && LANGUAGE_NONE != eActLang &&
1052 !lcl_IsURL(rWord, *this, aScanner.GetBegin(), aScanner.GetLen() ) )
1053 {
1054 if (pArgs->xSpeller.is())
1055 {
1056 SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
1057 pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, static_cast<sal_uInt16>(eActLang),
1058 Sequence< PropertyValue >() );
1059 }
1060 if( pArgs->xSpellAlt.is() )
1061 {
1062 if ( IsSymbolAt(aScanner.GetBegin()) ||
1063 // redlines can leave "in word" character within word,
1064 // we must remove them before spell checking
1065 // to avoid false alarm
1066 ( (bRestoreString || bContainsComments) && pArgs->xSpeller->isValid( rWord.replaceAll(OUStringChar(CH_TXTATR_INWORD), ""),
1067 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) ) )
1068 {
1069 pArgs->xSpellAlt = nullptr;
1070 }
1071 else
1072 {
1073 OUString sPrevWord = aScanner.GetPrevWord();
1074 auto nWordBegin = aScanner.GetBegin();
1075 auto nWordEnd = aScanner.GetEnd();
1076 bNextWord = aScanner.NextWord();
1077 const OUString& rActualWord = aScanner.GetPrevWord();
1078 bCalledNextWord = true;
1079 // check space separated word pairs in the dictionary, e.g. "vice versa"
1080 if ( !((bNextWord && pArgs->xSpeller->isValid( rActualWord + " " + aScanner.GetWord(),
1081 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() )) ||
1082 ( !sPrevWord.isEmpty() && pArgs->xSpeller->isValid( sPrevWord + " " + rActualWord,
1083 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ))) )
1084 {
1085 // make sure the selection build later from the data
1086 // below does not include "in word" character to the
1087 // left and right in order to preserve those. Therefore
1088 // count those "in words" in order to modify the
1089 // selection accordingly.
1090 const sal_Unicode* pChar = aScanner.GetPrevWord().getStr();
1091 sal_Int32 nLeft = 0;
1092 while (*pChar++ == CH_TXTATR_INWORD)
1093 ++nLeft;
1094 pChar = rActualWord.getLength() ? rActualWord.getStr() + rActualWord.getLength() - 1 : nullptr;
1095 sal_Int32 nRight = 0;
1096 while (pChar && *pChar-- == CH_TXTATR_INWORD)
1097 ++nRight;
1098
1099 pArgs->pStartPos->Assign(*this, nWordEnd - nRight );
1100 pArgs->pEndPos->Assign(*this, nWordBegin + nLeft );
1101 }
1102 else
1103 {
1104 pArgs->xSpellAlt = nullptr;
1105 }
1106 }
1107 }
1108 }
1109
1110 if ( !bCalledNextWord )
1111 bNextWord = aScanner.NextWord();
1112 }
1113 }
1114
1115 // reset original text
1116 if ( bRestoreString )
1117 {
1118 m_Text = aOldText;
1119 }
1120
1121 return pArgs->xSpellAlt.is();
1122}
1123
1125 LanguageType nLang, sal_uInt16 nLangWhichId,
1126 const vcl::Font *pFont, sal_uInt16 nFontWhichId )
1127{
1128 SwEditShell *pEditShell = GetDoc().GetEditShell();
1129 if (!pEditShell)
1130 return;
1131 SfxItemSet aSet(pEditShell->GetAttrPool(), nLangWhichId, nLangWhichId );
1132 if (pFont)
1133 aSet.MergeRange(nFontWhichId, nFontWhichId); // Keep it sorted
1134 aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
1135
1136 OSL_ENSURE( pFont, "target font missing?" );
1137 if (pFont)
1138 {
1139 SvxFontItem aFontItem = static_cast<const SvxFontItem&>( aSet.Get( nFontWhichId ) );
1140 aFontItem.SetFamilyName( pFont->GetFamilyName());
1141 aFontItem.SetFamily( pFont->GetFamilyType());
1142 aFontItem.SetStyleName( pFont->GetStyleName());
1143 aFontItem.SetPitch( pFont->GetPitch());
1144 aFontItem.SetCharSet( pFont->GetCharSet() );
1145 aSet.Put( aFontItem );
1146 }
1147
1149 // SetAttr( aSet ); <- Does not set language attribute of empty paragraphs correctly,
1150 // <- because since there is no selection the flag to garbage
1151 // <- collect all attributes is set, and therefore attributes spanned
1152 // <- over empty selection are removed.
1153
1154}
1155
1157{
1158 // get range of text within node to be converted
1159 // (either all the text or the text within the selection
1160 // when the conversion was started)
1161 const sal_Int32 nTextBegin = ( &rArgs.pStartPos->GetNode() == this )
1162 ? std::min(rArgs.pStartPos->GetContentIndex(), m_Text.getLength())
1163 : 0;
1164
1165 const sal_Int32 nTextEnd = ( &rArgs.pEndPos->GetNode() == this )
1166 ? std::min(rArgs.pEndPos->GetContentIndex(), m_Text.getLength())
1167 : m_Text.getLength();
1168
1169 rArgs.aConvText.clear();
1170
1171 // modify string according to redline information and hidden text
1172 const OUString aOldText( m_Text );
1173 OUStringBuffer buf(m_Text);
1174 const bool bRestoreString =
1175 lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength());
1176 if (bRestoreString)
1177 { // ??? UGLY: is it really necessary to modify m_Text here?
1178 m_Text = buf.makeStringAndClear();
1179 }
1180
1181 bool bFound = false;
1182 sal_Int32 nBegin = nTextBegin;
1183 sal_Int32 nLen = 0;
1184 LanguageType nLangFound = LANGUAGE_NONE;
1185 if (m_Text.isEmpty())
1186 {
1188 {
1189 // create SwPaM with mark & point spanning empty paragraph
1190 //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1191 SwPaM aCurPaM( *this, 0 );
1192
1193 SetLanguageAndFont( aCurPaM,
1196 }
1197 }
1198 else
1199 {
1200 SwLanguageIterator aIter( *this, nBegin );
1201
1202 // Implicit changes require setting new attributes, which in turn destroys
1203 // the attribute sequence on that aIter iterates. We store the necessary
1204 // coordinates and apply those changes after iterating through the text.
1205 typedef std::pair<sal_Int32, sal_Int32> ImplicitChangesRange;
1206 std::vector<ImplicitChangesRange> aImplicitChanges;
1207
1208 // find non zero length text portion of appropriate language
1209 do {
1210 nLangFound = aIter.GetLanguage();
1211 bool bLangOk = (nLangFound == rArgs.nConvSrcLang) ||
1214
1215 sal_Int32 nChPos = aIter.GetChgPos();
1216 // the position at the end of the paragraph is COMPLETE_STRING and
1217 // thus must be cut to the end of the actual string.
1218 assert(nChPos != -1);
1219 if (nChPos == -1 || nChPos == COMPLETE_STRING)
1220 {
1221 nChPos = m_Text.getLength();
1222 }
1223
1224 nLen = nChPos - nBegin;
1225 bFound = bLangOk && nLen > 0;
1226 if (!bFound)
1227 {
1228 // create SwPaM with mark & point spanning the attributed text
1229 //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
1230 SwPaM aCurPaM( *this, nBegin );
1231 aCurPaM.SetMark();
1232 aCurPaM.GetPoint()->SetContent(nBegin + nLen);
1233
1234 // check script type of selected text
1235 if (SwEditShell *pEditShell = GetDoc().GetEditShell())
1236 {
1237 pEditShell->Push(); // save current cursor on stack
1238 pEditShell->SetSelection( aCurPaM );
1239 bool bIsAsianScript = (SvtScriptType::ASIAN == pEditShell->GetScriptType());
1240 pEditShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // restore cursor from stack
1241
1242 if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
1243 {
1244 // Store for later use
1245 aImplicitChanges.emplace_back(nBegin, nBegin+nLen);
1246 }
1247 }
1248 nBegin = nChPos; // start of next language portion
1249 }
1250 } while (!bFound && aIter.Next()); /* loop while nothing was found and still sth is left to be searched */
1251
1252 // Apply implicit changes, if any, now that aIter is no longer used
1253 for (const auto& rImplicitChange : aImplicitChanges)
1254 {
1255 SwPaM aPaM( *this, rImplicitChange.first );
1256 aPaM.SetMark();
1257 aPaM.GetPoint()->SetContent( rImplicitChange.second );
1259 }
1260
1261 }
1262
1263 // keep resulting text within selection / range of text to be converted
1264 if (nBegin < nTextBegin)
1265 nBegin = nTextBegin;
1266 if (nBegin + nLen > nTextEnd)
1267 nLen = nTextEnd - nBegin;
1268 bool bInSelection = nBegin < nTextEnd;
1269
1270 if (bFound && bInSelection) // convertible text found within selection/range?
1271 {
1272 OSL_ENSURE( !m_Text.isEmpty(), "convertible text portion missing!" );
1273 rArgs.aConvText = m_Text.copy(nBegin, nLen);
1274 rArgs.nConvTextLang = nLangFound;
1275
1276 // position where to start looking in next iteration (after current ends)
1277 rArgs.pStartPos->Assign(*this, nBegin + nLen );
1278 // end position (when we have travelled over the whole document)
1279 rArgs.pEndPos->Assign(*this, nBegin );
1280 }
1281
1282 // restore original text
1283 if ( bRestoreString )
1284 {
1285 m_Text = aOldText;
1286 }
1287
1288 return !rArgs.aConvText.isEmpty();
1289}
1290
1291// Note: this is a clone of SwTextNode::Spell, so keep them in sync when fixing things!
1292SwRect SwTextFrame::AutoSpell_(SwTextNode & rNode, sal_Int32 nActPos)
1293{
1294 SwRect aRect;
1295 assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
1296 SwTextNode *const pNode(&rNode);
1297 if (!nActPos)
1298 nActPos = COMPLETE_STRING;
1299
1301
1302 // modify string according to redline information and hidden text
1303 const OUString aOldText( pNode->GetText() );
1304 OUStringBuffer buf(pNode->m_Text);
1305 const bool bContainsComments = lcl_HasComments(rNode);
1306 const bool bRestoreString =
1307 lcl_MaskRedlinesAndHiddenText(*pNode, buf, 0, pNode->GetText().getLength());
1308 if (bRestoreString)
1309 { // ??? UGLY: is it really necessary to modify m_Text here? just for GetLang()?
1310 pNode->m_Text = buf.makeStringAndClear();
1311 }
1312
1313 // a change of data indicates that at least one word has been modified
1314
1315 sal_Int32 nBegin = 0;
1316 sal_Int32 nEnd = pNode->GetText().getLength();
1317 sal_Int32 nInsertPos = 0;
1318 sal_Int32 nChgStart = COMPLETE_STRING;
1319 sal_Int32 nChgEnd = 0;
1320 sal_Int32 nInvStart = COMPLETE_STRING;
1321 sal_Int32 nInvEnd = 0;
1322
1323 const bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
1325
1326 if( pNode->GetWrong() )
1327 {
1328 nBegin = pNode->GetWrong()->GetBeginInv();
1329 if( COMPLETE_STRING != nBegin )
1330 {
1331 nEnd = std::max(pNode->GetWrong()->GetEndInv(), pNode->GetText().getLength());
1332 }
1333
1334 // get word around nBegin, we start at nBegin - 1
1335 if ( COMPLETE_STRING != nBegin )
1336 {
1337 if ( nBegin )
1338 --nBegin;
1339
1340 LanguageType eActLang = pNode->GetLang( nBegin );
1341 Boundary aBound =
1342 g_pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetText(), nBegin,
1343 g_pBreakIt->GetLocale( eActLang ),
1344 WordType::DICTIONARY_WORD, true );
1345 nBegin = aBound.startPos;
1346 }
1347
1348 // get the position in the wrong list
1349 nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
1350
1351 // sometimes we have to skip one entry
1352 if( nInsertPos < pNode->GetWrong()->Count() &&
1353 nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
1354 pNode->GetWrong()->Len( nInsertPos ) )
1355 nInsertPos++;
1356 }
1357
1358 bool bFresh = nBegin < nEnd;
1359 bool bPending(false);
1360
1361 if( bFresh )
1362 {
1363 uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1364 SwDoc& rDoc = pNode->GetDoc();
1365
1366 SwScanner aScanner( *pNode, pNode->GetText(), nullptr, ModelToViewHelper(),
1367 WordType::DICTIONARY_WORD, nBegin, nEnd);
1368
1369 bool bNextWord = aScanner.NextWord();
1370 while( bNextWord )
1371 {
1372 const OUString& rWord = aScanner.GetWord();
1373 nBegin = aScanner.GetBegin();
1374 sal_Int32 nLen = aScanner.GetLen();
1375 bool bCalledNextWord = false;
1376
1377 // get next language for next word, consider language attributes
1378 // within the word
1379 LanguageType eActLang = aScanner.GetCurrentLanguage();
1380 DetectAndMarkMissingDictionaries( rDoc, xSpell, eActLang );
1381
1382 bool bSpell = xSpell.is() && xSpell->hasLanguage( static_cast<sal_uInt16>(eActLang) );
1383 if( bSpell && !rWord.isEmpty() && !lcl_IsURL(rWord, *pNode, nBegin, nLen) )
1384 {
1385 // check for: bAlter => xHyphWord.is()
1386 OSL_ENSURE(!bSpell || xSpell.is(), "NULL pointer");
1387 if( !xSpell->isValid( rWord, static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) &&
1388 // redlines can leave "in word" character within word,
1389 // we must remove them before spell checking
1390 // to avoid false alarm
1391 ((!bRestoreString && !bContainsComments) || !xSpell->isValid( rWord.replaceAll(OUStringChar(CH_TXTATR_INWORD), ""),
1392 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ) ) )
1393 {
1394 OUString sPrevWord = aScanner.GetPrevWord();
1395 bNextWord = aScanner.NextWord();
1396 bCalledNextWord = true;
1397 // check space separated word pairs in the dictionary, e.g. "vice versa"
1398 if ( !((bNextWord && xSpell->isValid( aScanner.GetPrevWord() + " " + aScanner.GetWord(),
1399 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() )) ||
1400 (!sPrevWord.isEmpty() && xSpell->isValid( sPrevWord + " " + aScanner.GetPrevWord(),
1401 static_cast<sal_uInt16>(eActLang), Sequence< PropertyValue >() ))) )
1402 {
1403 sal_Int32 nSmartTagStt = nBegin;
1404 sal_Int32 nDummy = 1;
1405 if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
1406 {
1407 if( !pNode->GetWrong() )
1408 {
1409 pNode->SetWrong( std::make_unique<SwWrongList>( WRONGLIST_SPELL ) );
1410 pNode->GetWrong()->SetInvalid( 0, nEnd );
1411 }
1412 SwWrongList::FreshState const eState(pNode->GetWrong()->Fresh(
1413 nChgStart, nChgEnd, nBegin, nLen, nInsertPos, nActPos));
1414 switch (eState)
1415 {
1417 pNode->GetWrong()->Insert(OUString(), nullptr, nBegin, nLen, nInsertPos++);
1418 break;
1420 bPending = true;
1421 [[fallthrough]]; // to mark as invalid
1423 nInvStart = nBegin;
1424 nInvEnd = nBegin + nLen;
1425 break;
1426 }
1427 }
1428 }
1429 else if( bAddAutoCmpl && rACW.GetMinWordLen() <= aScanner.GetPrevWord().getLength() )
1430 {
1431 // tdf#119695 only add the word if the cursor position is outside the word
1432 // so that the incomplete words are not added as autocomplete candidates
1433 bool bCursorOutsideWord = nActPos > nBegin + nLen || nActPos < nBegin;
1434 if (bCursorOutsideWord)
1435 rACW.InsertWord(aScanner.GetPrevWord(), rDoc);
1436 }
1437 }
1438 else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.getLength() )
1439 {
1440 // tdf#119695 only add the word if the cursor position is outside the word
1441 // so that the incomplete words are not added as autocomplete candidates
1442 bool bCursorOutsideWord = nActPos > nBegin + nLen || nActPos < nBegin;
1443 if (bCursorOutsideWord)
1444 rACW.InsertWord(rWord, rDoc);
1445 }
1446 }
1447
1448 if ( !bCalledNextWord )
1449 bNextWord = aScanner.NextWord();
1450 }
1451 }
1452
1453 // reset original text
1454 // i63141 before calling GetCharRect(..) with formatting!
1455 if ( bRestoreString )
1456 {
1457 pNode->m_Text = aOldText;
1458 }
1459 if( pNode->GetWrong() )
1460 {
1461 if( bFresh )
1462 pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
1463 nEnd, 0, nInsertPos, nActPos );
1464
1465 // Calculate repaint area:
1466
1467 if( nChgStart < nChgEnd )
1468 {
1469 aRect = lcl_CalculateRepaintRect(*this, rNode, nChgStart, nChgEnd);
1470
1471 // fdo#71558 notify misspelled word to accessibility
1472#if !ENABLE_WASM_STRIP_ACCESSIBILITY
1473 SwViewShell* pViewSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
1474 if( pViewSh )
1475 pViewSh->InvalidateAccessibleParaAttrs( *this );
1476#endif
1477 }
1478
1479 pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
1480 pNode->SetWrongDirty(
1481 (COMPLETE_STRING != pNode->GetWrong()->GetBeginInv())
1482 ? (bPending
1486 if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
1487 pNode->ClearWrong();
1488 }
1489 else
1491
1492 if( bAddAutoCmpl )
1493 pNode->SetAutoCompleteWordDirty( false );
1494
1495 return aRect;
1496}
1497
1508{
1509 SwRect aRet;
1510
1511 assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
1512 SwTextNode *const pNode = &rNode;
1513 const OUString& rText = pNode->GetText();
1514
1515 // Iterate over language portions
1516 SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
1517
1518 SwWrongList* pSmartTagList = pNode->GetSmartTags();
1519
1520 sal_Int32 nBegin = 0;
1521 sal_Int32 nEnd = rText.getLength();
1522
1523 if ( pSmartTagList )
1524 {
1525 if ( pSmartTagList->GetBeginInv() != COMPLETE_STRING )
1526 {
1527 nBegin = pSmartTagList->GetBeginInv();
1528 nEnd = std::min( pSmartTagList->GetEndInv(), rText.getLength() );
1529
1530 if ( nBegin < nEnd )
1531 {
1532 const LanguageType aCurrLang = pNode->GetLang( nBegin );
1533 const css::lang::Locale aCurrLocale = g_pBreakIt->GetLocale( aCurrLang );
1534 nBegin = g_pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale );
1535 nEnd = g_pBreakIt->GetBreakIter()->endOfSentence(rText, nEnd, aCurrLocale);
1536 if (nEnd > rText.getLength() || nEnd < 0)
1537 nEnd = rText.getLength();
1538 }
1539 }
1540 }
1541
1542 const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
1543 sal_uInt16 nNumberOfRemovedEntries = 0;
1544 sal_uInt16 nNumberOfInsertedEntries = 0;
1545
1546 // clear smart tag list between nBegin and nEnd:
1547 if ( 0 != nNumberOfEntries )
1548 {
1549 sal_Int32 nChgStart = COMPLETE_STRING;
1550 sal_Int32 nChgEnd = 0;
1551 const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
1552 pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, COMPLETE_STRING );
1553 nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
1554 }
1555
1556 if ( nBegin < nEnd )
1557 {
1558 // Expand the string:
1559 const ModelToViewHelper aConversionMap(*pNode, getRootFrame() /*TODO - replace or expand fields for smart tags?*/);
1560 const OUString& aExpandText = aConversionMap.getViewText();
1561
1562 // Ownership ov ConversionMap is passed to SwXTextMarkup object!
1563 uno::Reference<text::XTextMarkup> const xTextMarkup =
1564 new SwXTextMarkup(pNode, aConversionMap);
1565
1566 css::uno::Reference< css::frame::XController > xController = pNode->GetDoc().GetDocShell()->GetController();
1567
1568 SwPosition start(*pNode, nBegin);
1569 SwPosition end (*pNode, nEnd);
1571
1572 rSmartTagMgr.RecognizeTextRange(xRange, xTextMarkup, xController);
1573
1574 sal_Int32 nLangBegin = nBegin;
1575 sal_Int32 nLangEnd;
1576
1577 // smart tag recognition has to be done for each language portion:
1578 SwLanguageIterator aIter( *pNode, nLangBegin );
1579
1580 do
1581 {
1582 const LanguageType nLang = aIter.GetLanguage();
1583 const css::lang::Locale aLocale = g_pBreakIt->GetLocale( nLang );
1584 nLangEnd = std::min<sal_Int32>( nEnd, aIter.GetChgPos() );
1585
1586 const sal_Int32 nExpandBegin = aConversionMap.ConvertToViewPosition( nLangBegin );
1587 const sal_Int32 nExpandEnd = aConversionMap.ConvertToViewPosition( nLangEnd );
1588
1589 rSmartTagMgr.RecognizeString(aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
1590
1591 nLangBegin = nLangEnd;
1592 }
1593 while ( aIter.Next() && nLangEnd < nEnd );
1594
1595 pSmartTagList = pNode->GetSmartTags();
1596
1597 const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
1598 nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
1599 }
1600
1601 if( pSmartTagList )
1602 {
1603 // Update WrongList stuff
1604 pSmartTagList->SetInvalid( COMPLETE_STRING, 0 );
1605 pNode->SetSmartTagDirty( COMPLETE_STRING != pSmartTagList->GetBeginInv() );
1606
1607 if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
1608 pNode->ClearSmartTags();
1609
1610 // Calculate repaint area:
1611 if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
1612 0 != nNumberOfInsertedEntries ) )
1613 {
1614 aRet = lcl_CalculateRepaintRect(*this, rNode, nBegin, nEnd);
1615 }
1616 }
1617 else
1618 pNode->SetSmartTagDirty( false );
1619
1620 return aRet;
1621}
1622
1623void SwTextFrame::CollectAutoCmplWrds(SwTextNode & rNode, sal_Int32 nActPos)
1624{
1625 assert(sw::FrameContainsNode(*this, rNode.GetIndex())); (void) this;
1626 SwTextNode *const pNode(&rNode);
1627 if (!nActPos)
1628 nActPos = COMPLETE_STRING;
1629
1630 SwDoc& rDoc = pNode->GetDoc();
1632
1633 sal_Int32 nBegin = 0;
1634 sal_Int32 nEnd = pNode->GetText().getLength();
1635 sal_Int32 nLen;
1636 bool bACWDirty = false;
1637
1638 if( nBegin < nEnd )
1639 {
1640 int nCnt = 200;
1641 SwScanner aScanner( *pNode, pNode->GetText(), nullptr, ModelToViewHelper(),
1642 WordType::DICTIONARY_WORD, nBegin, nEnd );
1643 while( aScanner.NextWord() )
1644 {
1645 nBegin = aScanner.GetBegin();
1646 nLen = aScanner.GetLen();
1647 if( rACW.GetMinWordLen() <= nLen )
1648 {
1649 const OUString& rWord = aScanner.GetWord();
1650
1651 if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
1652 {
1653 if( rACW.GetMinWordLen() <= rWord.getLength() )
1654 rACW.InsertWord( rWord, rDoc );
1655 }
1656 else
1657 bACWDirty = true;
1658 }
1659 if( !--nCnt )
1660 {
1661 // don't wait for TIMER here, so we can finish big paragraphs
1662 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
1663 return;
1664 nCnt = 100;
1665 }
1666 }
1667 }
1668
1669 if (!bACWDirty)
1670 pNode->SetAutoCompleteWordDirty( false );
1671}
1672
1674 SwTextFrame const& rFrame, SwTextNode const& rNode,
1675 SwInterHyphInfo const& rHyphInfo)
1676 : m_nStart(rFrame.MapModelToView(&rNode, rHyphInfo.m_nStart))
1677 , m_nEnd(rFrame.MapModelToView(&rNode, rHyphInfo.m_nEnd))
1678 , m_nWordStart(0)
1679 , m_nWordLen(0)
1680{
1681}
1682
1684 SwTextNode const& rNode, SwInterHyphInfo & o_rHyphInfo)
1685{
1686 std::pair<SwTextNode const*, sal_Int32> const wordStart(rFrame.MapViewToModel(m_nWordStart));
1687 std::pair<SwTextNode const*, sal_Int32> const wordEnd(rFrame.MapViewToModel(m_nWordStart+m_nWordLen));
1688 if (wordStart.first != &rNode || wordEnd.first != &rNode)
1689 { // not sure if this can happen since nStart/nEnd are in rNode
1690 SAL_WARN("sw.core", "UpdateTextNodeHyphInfo: outside of node");
1691 return;
1692 }
1693 o_rHyphInfo.m_nWordStart = wordStart.second;
1694 o_rHyphInfo.m_nWordLen = wordEnd.second - wordStart.second;
1695 o_rHyphInfo.SetHyphWord(m_xHyphWord);
1696}
1697
1700{
1701 // shortcut: paragraph doesn't have a language set:
1703 && LanguageType(USHRT_MAX) == GetLang(0, m_Text.getLength()))
1704 {
1705 return false;
1706 }
1707
1709 [&rHyphInf, this]() {
1710 std::pair<Point, bool> tmp;
1711 Point const*const pPoint = rHyphInf.GetCursorPos();
1712 if (pPoint)
1713 {
1714 tmp.first = *pPoint;
1715 tmp.second = true;
1716 }
1717 return static_cast<SwTextFrame*>(this->getLayoutFrame(
1718 this->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1719 nullptr, pPoint ? &tmp : nullptr));
1720 });
1721 if (!pFrame)
1722 {
1723 // There was a comment here that claimed that the following assertion
1724 // shouldn't exist as it's triggered by "Trennung ueber Sonderbereiche",
1725 // (hyphenation across special sections?), whatever that means.
1726 OSL_ENSURE( pFrame, "!SwTextNode::Hyphenate: can't find any frame" );
1727 return false;
1728 }
1729 SwInterHyphInfoTextFrame aHyphInfo(*pFrame, *this, rHyphInf);
1730
1731 pFrame = &(pFrame->GetFrameAtOfst( aHyphInfo.m_nStart ));
1732
1733 while( pFrame )
1734 {
1735 if (pFrame->Hyphenate(aHyphInfo))
1736 {
1737 // The layout is not robust wrt. "direct formatting"
1738 // cf. layact.cxx, SwLayAction::TurboAction_(), if( !pCnt->IsValid() ...
1739 pFrame->SetCompletePaint();
1740 aHyphInfo.UpdateTextNodeHyphInfo(*pFrame, *this, rHyphInf);
1741 return true;
1742 }
1743 pFrame = pFrame->GetFollow();
1744 if( pFrame )
1745 {
1746 aHyphInfo.m_nEnd = aHyphInfo.m_nEnd - (pFrame->GetOffset() - aHyphInfo.m_nStart);
1747 aHyphInfo.m_nStart = pFrame->GetOffset();
1748 }
1749 }
1750 return false;
1751}
1752
1753namespace
1754{
1755 struct swTransliterationChgData
1756 {
1757 sal_Int32 nStart;
1758 sal_Int32 nLen;
1759 OUString sChanged;
1760 Sequence< sal_Int32 > aOffsets;
1761 };
1762}
1763
1764// change text to Upper/Lower/Hiragana/Katakana/...
1767 sal_Int32 nStt, sal_Int32 nEnd,
1768 SwUndoTransliterate* pUndo, bool bUseRedlining )
1769{
1770 if (nStt >= nEnd)
1771 return;
1772
1773 const sal_Int32 selStart = nStt;
1774 const sal_Int32 selEnd = nEnd;
1775
1776 // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
1777 // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
1778 // occasionally miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
1779 // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
1780 // proper thing to do.
1781 const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
1782
1783 // In order to have less trouble with changing text size, e.g. because
1784 // of ligatures or German small sz being resolved, we need to process
1785 // the text replacements from end to start.
1786 // This way the offsets for the yet to be changed words will be
1787 // left unchanged by the already replaced text.
1788 // For this we temporarily save the changes to be done in this vector
1789 std::vector< swTransliterationChgData > aChanges;
1790 swTransliterationChgData aChgData;
1791
1792 if (rTrans.getType() == TransliterationFlags::TITLE_CASE)
1793 {
1794 // for 'capitalize every word' we need to iterate over each word
1795
1796 Boundary aSttBndry;
1797 Boundary aEndBndry;
1798 aSttBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1799 GetText(), nStt,
1800 g_pBreakIt->GetLocale( GetLang( nStt ) ),
1801 nWordType,
1802 true /*prefer forward direction*/);
1803 aEndBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1804 GetText(), nEnd,
1805 g_pBreakIt->GetLocale( GetLang( nEnd ) ),
1806 nWordType,
1807 false /*prefer backward direction*/);
1808
1809 // prevent backtracking to the previous word if selection is at word boundary
1810 if (aSttBndry.endPos <= nStt)
1811 {
1812 aSttBndry = g_pBreakIt->GetBreakIter()->nextWord(
1813 GetText(), aSttBndry.endPos,
1814 g_pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
1815 nWordType);
1816 }
1817 // prevent advancing to the next word if selection is at word boundary
1818 if (aEndBndry.startPos >= nEnd)
1819 {
1820 aEndBndry = g_pBreakIt->GetBreakIter()->previousWord(
1821 GetText(), aEndBndry.startPos,
1822 g_pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
1823 nWordType);
1824 }
1825
1826 /* Nothing to do if user selection lies entirely outside of word start and end boundary computed above.
1827 * Skip this node, because otherwise the below logic for constraining to the selection will fail */
1828 if (aSttBndry.startPos >= selEnd || aEndBndry.endPos <= selStart) {
1829 return;
1830 }
1831
1832 // prevent going outside of the user's selection, which may
1833 // start in the middle of a word
1834 aSttBndry.startPos = std::max(aSttBndry.startPos, selStart);
1835 aEndBndry.startPos = std::max(aSttBndry.startPos, aEndBndry.startPos);
1836
1837 Boundary aCurWordBndry( aSttBndry );
1838 while (aCurWordBndry.startPos <= aEndBndry.startPos)
1839 {
1840 nStt = aCurWordBndry.startPos;
1841 nEnd = aCurWordBndry.endPos;
1842 const sal_Int32 nLen = nEnd - nStt;
1843 OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1844
1845 Sequence <sal_Int32> aOffsets;
1846 OUString const sChgd( rTrans.transliterate(
1847 GetText(), GetLang(nStt), nStt, nLen, &aOffsets) );
1848
1849 assert(nStt < m_Text.getLength());
1850 if (0 != rtl_ustr_shortenedCompare_WithLength(
1851 m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1852 sChgd.getStr(), sChgd.getLength(), nLen))
1853 {
1854 aChgData.nStart = nStt;
1855 aChgData.nLen = nLen;
1856 aChgData.sChanged = sChgd;
1857 aChgData.aOffsets = aOffsets;
1858 aChanges.push_back( aChgData );
1859 }
1860
1861 aCurWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
1862 GetText(), nStt,
1863 g_pBreakIt->GetLocale(GetLang(nStt, 1)),
1864 nWordType);
1865 }
1866 }
1867 else if (rTrans.getType() == TransliterationFlags::SENTENCE_CASE)
1868 {
1869 // For 'sentence case' we need to iterate sentence by sentence.
1870 // nLastStart and nLastEnd are the boundaries of the last sentence in
1871 // the user's selection.
1872 sal_Int32 nLastStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
1873 GetText(), nEnd,
1874 g_pBreakIt->GetLocale( GetLang( nEnd ) ) );
1875 sal_Int32 nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1876 GetText(), nLastStart,
1877 g_pBreakIt->GetLocale( GetLang( nLastStart ) ) );
1878
1879 // Begin with the starting point of the user's selection (it may not be
1880 // the beginning of a sentence)...
1881 sal_Int32 nCurrentStart = nStt;
1882 // ...And extend to the end of the first sentence
1883 sal_Int32 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1884 GetText(), nCurrentStart,
1885 g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1886
1887 // prevent backtracking to the previous sentence if selection starts at end of a sentence
1888 if (nCurrentEnd <= nStt)
1889 {
1890 // now nCurrentStart is probably located on a non-letter word. (unless we
1891 // are in Asian text with no spaces...)
1892 // Thus to get the real sentence start we should locate the next real word,
1893 // that is one found by DICTIONARY_WORD
1894 i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->nextWord(
1895 GetText(), nCurrentEnd,
1896 g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1897 i18n::WordType::DICTIONARY_WORD);
1898
1899 // now get new current sentence boundaries
1900 nCurrentStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
1901 GetText(), aBndry.startPos,
1902 g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1903 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1904 GetText(), nCurrentStart,
1905 g_pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
1906 }
1907 // prevent advancing to the next sentence if selection ends at start of a sentence
1908 if (nLastStart >= nEnd)
1909 {
1910 // now nCurrentStart is probably located on a non-letter word. (unless we
1911 // are in Asian text with no spaces...)
1912 // Thus to get the real sentence start we should locate the previous real word,
1913 // that is one found by DICTIONARY_WORD
1914 i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->previousWord(
1915 GetText(), nLastStart,
1916 g_pBreakIt->GetLocale( GetLang( nLastStart) ),
1917 i18n::WordType::DICTIONARY_WORD);
1918 nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1919 GetText(), aBndry.startPos,
1920 g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
1921 if (nCurrentEnd > nLastEnd)
1922 nCurrentEnd = nLastEnd;
1923 }
1924
1925 // Prevent going outside of the user's selection
1926 nCurrentStart = std::max(selStart, nCurrentStart);
1927 nCurrentEnd = std::min(selEnd, nCurrentEnd);
1928 nLastEnd = std::min(selEnd, nLastEnd);
1929
1930 while (nCurrentStart < nLastEnd)
1931 {
1932 sal_Int32 nLen = nCurrentEnd - nCurrentStart;
1933 OSL_ENSURE( nLen > 0, "invalid word length of 0" );
1934
1935 Sequence <sal_Int32> aOffsets;
1936 OUString const sChgd( rTrans.transliterate(GetText(),
1937 GetLang(nCurrentStart), nCurrentStart, nLen, &aOffsets) );
1938
1939 assert(nStt < m_Text.getLength());
1940 if (0 != rtl_ustr_shortenedCompare_WithLength(
1941 m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1942 sChgd.getStr(), sChgd.getLength(), nLen))
1943 {
1944 aChgData.nStart = nCurrentStart;
1945 aChgData.nLen = nLen;
1946 aChgData.sChanged = sChgd;
1947 aChgData.aOffsets = aOffsets;
1948 aChanges.push_back( aChgData );
1949 }
1950
1951 Boundary aFirstWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
1952 GetText(), nCurrentEnd,
1953 g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
1954 nWordType);
1955 nCurrentStart = aFirstWordBndry.startPos;
1956 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
1957 GetText(), nCurrentStart,
1958 g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
1959 }
1960 }
1961 else
1962 {
1963 // here we may transliterate over complete language portions...
1964
1965 std::unique_ptr<SwLanguageIterator> pIter;
1966 if( rTrans.needLanguageForTheMode() )
1967 pIter.reset(new SwLanguageIterator( *this, nStt ));
1968
1969 sal_Int32 nEndPos = 0;
1971 do {
1972 if( pIter )
1973 {
1974 nLang = pIter->GetLanguage();
1975 nEndPos = pIter->GetChgPos();
1976 if( nEndPos > nEnd )
1977 nEndPos = nEnd;
1978 }
1979 else
1980 {
1982 nEndPos = nEnd;
1983 }
1984 const sal_Int32 nLen = nEndPos - nStt;
1985
1986 Sequence <sal_Int32> aOffsets;
1987 OUString const sChgd( rTrans.transliterate(
1988 m_Text, nLang, nStt, nLen, &aOffsets) );
1989
1990 assert(nStt < m_Text.getLength());
1991 if (0 != rtl_ustr_shortenedCompare_WithLength(
1992 m_Text.getStr() + nStt, m_Text.getLength() - nStt,
1993 sChgd.getStr(), sChgd.getLength(), nLen))
1994 {
1995 aChgData.nStart = nStt;
1996 aChgData.nLen = nLen;
1997 aChgData.sChanged = sChgd;
1998 aChgData.aOffsets = aOffsets;
1999 aChanges.push_back( aChgData );
2000 }
2001
2002 nStt = nEndPos;
2003 } while( nEndPos < nEnd && pIter && pIter->Next() );
2004 }
2005
2006 if (aChanges.empty())
2007 return;
2008
2009 // now apply the changes from end to start to leave the offsets of the
2010 // yet unchanged text parts remain the same.
2011 size_t nSum(0);
2012
2013 for (size_t i = 0; i < aChanges.size(); ++i)
2014 { // check this here since AddChanges cannot be moved below
2015 // call to ReplaceTextOnly
2016 swTransliterationChgData & rData =
2017 aChanges[ aChanges.size() - 1 - i ];
2018
2019 nSum += rData.sChanged.getLength() - rData.nLen;
2020 if (nSum > o3tl::make_unsigned(GetSpaceLeft()))
2021 {
2022 SAL_WARN("sw.core", "SwTextNode::ReplaceTextOnly: "
2023 "node text with insertion > node capacity.");
2024 return;
2025 }
2026
2027 if ( bUseRedlining )
2028 {
2029 // create SwPaM with mark & point spanning the attributed text
2030 //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
2031 SwPaM aCurPaM( *this, rData.nStart );
2032 aCurPaM.SetMark();
2033 aCurPaM.GetPoint()->SetContent( rData.nStart + rData.nLen );
2034 // replace the changed words
2035 if ( aCurPaM.GetText() != rData.sChanged )
2036 GetDoc().getIDocumentContentOperations().ReplaceRange( aCurPaM, rData.sChanged, false );
2037 }
2038 else
2039 {
2040 if (pUndo)
2041 pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
2042 ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
2043 }
2044 }
2045}
2046
2047void SwTextNode::ReplaceTextOnly( sal_Int32 nPos, sal_Int32 nLen,
2048 std::u16string_view aText,
2049 const Sequence<sal_Int32>& rOffsets )
2050{
2051 assert(sal_Int32(aText.size()) - nLen <= GetSpaceLeft());
2052
2053 m_Text = m_Text.replaceAt(nPos, nLen, aText);
2054
2055 sal_Int32 nTLen = aText.size();
2056 const sal_Int32* pOffsets = rOffsets.getConstArray();
2057 // now look for no 1-1 mapping -> move the indices!
2058 sal_Int32 nMyOff = nPos;
2059 for( sal_Int32 nI = 0; nI < nTLen; ++nI )
2060 {
2061 const sal_Int32 nOff = pOffsets[ nI ];
2062 if( nOff < nMyOff )
2063 {
2064 // something is inserted
2065 sal_Int32 nCnt = 1;
2066 while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
2067 ++nCnt;
2068
2069 Update(SwContentIndex(this, nMyOff), nCnt, UpdateMode::Default);
2070 nMyOff = nOff;
2071 //nMyOff -= nCnt;
2072 nI += nCnt - 1;
2073 }
2074 else if( nOff > nMyOff )
2075 {
2076 // something is deleted
2077 Update(SwContentIndex(this, nMyOff + 1), nOff - nMyOff, UpdateMode::Negative);
2078 nMyOff = nOff;
2079 }
2080 ++nMyOff;
2081 }
2082 if( nMyOff < nLen )
2083 // something is deleted at the end
2084 Update(SwContentIndex(this, nMyOff), nLen - nMyOff, UpdateMode::Negative);
2085
2086 // notify the layout!
2087 const auto aDelHint = sw::DeleteText(nPos, nTLen);
2088 CallSwClientNotify(aDelHint);
2089
2090 const auto aInsHint = sw::MakeInsertText(*this, nPos, nTLen);
2091 CallSwClientNotify(aInsHint);
2092}
2093
2094// the return values allows us to see if we did the heavy-
2095// lifting required to actually break and count the words.
2097 sal_Int32 nStt, sal_Int32 nEnd ) const
2098{
2099 if( nStt > nEnd )
2100 { // bad call
2101 return false;
2102 }
2103 if (IsInRedlines())
2104 { //not counting txtnodes used to hold deleted redline content
2105 return false;
2106 }
2107 bool bCountAll = ( (0 == nStt) && (GetText().getLength() == nEnd) );
2108 ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
2109 if ( IsHidden() )
2110 { // not counting hidden paras
2111 return false;
2112 }
2113 // count words in numbering string if started at beginning of para:
2114 bool bCountNumbering = nStt == 0;
2115 bool bHasBullet = false, bHasNumbering = false;
2116 OUString sNumString;
2117 if (bCountNumbering)
2118 {
2119 sNumString = GetNumString();
2120 bHasNumbering = !sNumString.isEmpty();
2121 if (!bHasNumbering)
2122 bHasBullet = HasBullet();
2123 bCountNumbering = bHasNumbering || bHasBullet;
2124 }
2125
2126 if( nStt == nEnd && !bCountNumbering)
2127 { // unnumbered empty node or empty selection
2128 if (bCountAll)
2129 {
2130 SetWordCountDirty( false ); // reset flag to speed up DoIdleJob
2131 }
2132 return false;
2133 }
2134
2135 // count of non-empty paras
2136 ++rStat.nPara;
2137
2138 // Shortcut when counting whole paragraph and current count is clean
2139 if ( bCountAll && !IsWordCountDirty() )
2140 {
2141 // accumulate into DocStat record to return the values
2142
2147 return false;
2148 }
2149
2150 // ConversionMap to expand fields, remove invisible and redline deleted text for scanner
2151 const ModelToViewHelper aConversionMap(*this,
2152 getIDocumentLayoutAccess().GetCurrentLayout(),
2154 const OUString& aExpandText = aConversionMap.getViewText();
2155
2156 if (aExpandText.isEmpty() && !bCountNumbering)
2157 {
2158 if (bCountAll)
2159 {
2160 SetWordCountDirty( false ); // reset flag to speed up DoIdleJob
2161 }
2162 return false;
2163 }
2164
2165 // map start and end points onto the ConversionMap
2166 const sal_Int32 nExpandBegin = aConversionMap.ConvertToViewPosition( nStt );
2167 const sal_Int32 nExpandEnd = aConversionMap.ConvertToViewPosition( nEnd );
2168
2169 //do the count
2170 // all counts exclude hidden paras and hidden+redlined within para
2171 // definition of space/white chars in SwScanner (and BreakIter!)
2172 // uses both u_isspace and BreakIter getWordBoundary in SwScanner
2173 sal_uInt32 nTmpWords = 0; // count of all words
2174 sal_uInt32 nTmpAsianWords = 0; //count of all Asian codepoints
2175 sal_uInt32 nTmpChars = 0; // count of all chars
2176 sal_uInt32 nTmpCharsExcludingSpaces = 0; // all non-white chars
2177
2178 // count words in masked and expanded text:
2179 if (!aExpandText.isEmpty())
2180 {
2181 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
2182
2183 // zero is NULL for pLanguage -----------v last param = true for clipping
2184 SwScanner aScanner( *this, aExpandText, nullptr, aConversionMap, i18n::WordType::WORD_COUNT,
2185 nExpandBegin, nExpandEnd, true );
2186
2187 // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
2188 const OUString aBreakWord( CH_TXTATR_BREAKWORD );
2189
2190 while ( aScanner.NextWord() )
2191 {
2192 if( !aExpandText.match(aBreakWord, aScanner.GetBegin() ))
2193 {
2194 ++nTmpWords;
2195 const OUString &rWord = aScanner.GetWord();
2196 if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
2197 ++nTmpAsianWords;
2198 nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
2199 }
2200 }
2201
2202 nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
2203
2204 nTmpChars = g_pBreakIt->getGraphemeCount(aExpandText, nExpandBegin, nExpandEnd);
2205 }
2206
2207 // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
2208 // nor for mid-word selection - set scanner bClip = true at creation
2209
2210 // count outline number label - ? no expansion into map
2211 // always counts all of number-ish label
2212 if (bHasNumbering) // count words in numbering string
2213 {
2214 LanguageType aLanguage = GetLang( 0 );
2215
2216 SwScanner aScanner( *this, sNumString, &aLanguage, ModelToViewHelper(),
2217 i18n::WordType::WORD_COUNT, 0, sNumString.getLength(), true );
2218
2219 while ( aScanner.NextWord() )
2220 {
2221 ++nTmpWords;
2222 const OUString &rWord = aScanner.GetWord();
2223 if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
2224 ++nTmpAsianWords;
2225 nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
2226 }
2227
2228 nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
2229 nTmpChars += g_pBreakIt->getGraphemeCount(sNumString);
2230 }
2231 else if ( bHasBullet )
2232 {
2233 ++nTmpWords;
2234 ++nTmpChars;
2235 ++nTmpCharsExcludingSpaces;
2236 }
2237
2238 // If counting the whole para then update cached values and mark clean
2239 if ( bCountAll )
2240 {
2244 m_aParagraphIdleData.nNumberOfCharsExcludingSpaces = nTmpCharsExcludingSpaces;
2245 SetWordCountDirty( false );
2246 }
2247 // accumulate into DocStat record to return the values
2248 rStat.nWord += nTmpWords;
2249 rStat.nAsianWord += nTmpAsianWords;
2250 rStat.nChar += nTmpChars;
2251 rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
2252
2253 return true;
2254}
2255
2256void SwTextNode::SetWrong( std::unique_ptr<SwWrongList> pNew )
2257{
2258 m_aParagraphIdleData.pWrong = std::move(pNew);
2259}
2260
2262{
2264}
2265
2266std::unique_ptr<SwWrongList> SwTextNode::ReleaseWrong()
2267{
2268 return std::move(m_aParagraphIdleData.pWrong);
2269}
2270
2272{
2273 return m_aParagraphIdleData.pWrong.get();
2274}
2275
2276// #i71360#
2278{
2279 return m_aParagraphIdleData.pWrong.get();
2280}
2281
2282void SwTextNode::SetGrammarCheck( std::unique_ptr<SwGrammarMarkUp> pNew )
2283{
2284 m_aParagraphIdleData.pGrammarCheck = std::move(pNew);
2285}
2286
2288{
2290}
2291
2292std::unique_ptr<SwGrammarMarkUp> SwTextNode::ReleaseGrammarCheck()
2293{
2294 return std::move(m_aParagraphIdleData.pGrammarCheck);
2295}
2296
2298{
2300}
2301
2303{
2304 return static_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetGrammarCheck());
2305}
2306
2307void SwTextNode::SetSmartTags( std::unique_ptr<SwWrongList> pNew )
2308{
2309 OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
2310 "Weird - we have a smart tag list without any recognizers?" );
2311
2312 m_aParagraphIdleData.pSmartTags = std::move(pNew);
2313}
2314
2316{
2318}
2319
2320std::unique_ptr<SwWrongList> SwTextNode::ReleaseSmartTags()
2321{
2322 return std::move(m_aParagraphIdleData.pSmartTags);
2323}
2324
2326{
2327 return m_aParagraphIdleData.pSmartTags.get();
2328}
2329
2331{
2332 return const_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetSmartTags());
2333}
2334
2335void SwTextNode::SetWordCountDirty( bool bNew ) const
2336{
2338}
2339
2341{
2343}
2344
2346{
2348}
2349
2351{
2353}
2354
2356{
2358}
2359
2361{
2363}
2364
2366{
2368}
2369
2370void SwTextNode::SetSmartTagDirty( bool bNew ) const
2371{
2373}
2374
2376{
2378}
2379
2381{
2383}
2384
2386{
2388}
2389
2390// <-- Paragraph statistics end
2391
2392/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const sal_Int32 m_nLength
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
static bool AnyInput(VclInputFlags nType=VCL_INPUT_ANY)
virtual bool ReplaceRange(SwPaM &rPam, const OUString &rNewStr, const bool bRegExReplace)=0
Replace selected range in a TextNode with string.
virtual void InsertItemSet(const SwPaM &rRg, const SfxItemSet &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr)=0
static bool IsShowChanges(const RedlineFlags eM)
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
virtual std::shared_ptr< SfxItemSet > getAutomaticStyle(const SfxItemSet &rSet, SwAutoStyleFamily eFamily, const OUString *pParentName=nullptr)=0
ModelPosition ConvertToModelPosition(sal_Int32 nViewPos) const
Converts a view position into a model position.
const OUString & getViewText() const
sal_Int32 ConvertToViewPosition(sal_Int32 nModelPos) const
Converts a model position into a view position.
const SfxPoolItem * GetCurItem() const
const SfxPoolItem * NextItem()
sal_uInt16 Count() const
virtual std::unique_ptr< SfxItemSet > Clone(bool bItems=true, SfxItemPool *pToPool=nullptr) const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
void MergeRange(sal_uInt16 nFrom, sal_uInt16 nTo)
sal_uInt16 Which() const
void RecognizeTextRange(const css::uno::Reference< css::text::XTextRange > &rRange, const css::uno::Reference< css::text::XTextMarkup > &rMarkup, const css::uno::Reference< css::frame::XController > &rController) const
void RecognizeString(const OUString &rText, const css::uno::Reference< css::text::XTextMarkup > &rMarkup, const css::uno::Reference< css::frame::XController > &rController, const css::lang::Locale &rLocale, sal_uInt32 nStart, sal_uInt32 nLen) const
void SetStyleName(const OUString &rStyleName)
void SetFamily(FontFamily _eFamily)
void SetPitch(FontPitch _ePitch)
void SetFamilyName(const OUString &rFamilyName)
void SetCharSet(rtl_TextEncoding _eEncoding)
static sal_Int16 CheckSpellLang(css::uno::Reference< css::linguistic2::XSpellChecker1 > const &xSpell, LanguageType nLang)
bool InsertWord(const OUString &rWord, SwDoc &rDoc)
Definition: acmplwrd.cxx:238
sal_uInt16 GetMinWordLen() const
Definition: acmplwrd.hxx:64
sal_Int32 getGraphemeCount(const OUString &rStr, sal_Int32 nStart, sal_Int32 nEnd) const
Definition: breakit.cxx:158
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:63
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:68
Marks a character position inside a document model content node (SwContentNode)
SwFormatColl * GetFormatColl() const
Definition: node.hxx:497
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1223
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:727
css::uno::Reference< css::frame::XController > GetController()
Definition: docsh.cxx:1291
Definition: doc.hxx:197
static SwAutoCompleteWord & GetAutoCompleteWords()
Definition: doc.hxx:1558
void SetMissingDictionaries(bool bIsMissing)
Use to notify if the dictionary can be found for a single content portion (has to be called for all p...
Definition: doc.cxx:1856
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:329
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:349
SwEditShell const * GetEditShell() const
Definition: doccorr.cxx:330
::sw::DocumentSettingManager & GetDocumentSettingManager()
Definition: doc.cxx:200
SwDocShell * GetDocShell()
Definition: doc.hxx:1370
const std::shared_ptr< SfxItemSet > & GetStyleHandle() const
Definition: fmtautofmt.hxx:49
SwRect GetPaintArea() const
|* The paintarea is the area, in which the content of a frame is allowed |* to be displayed.
Definition: ssfrm.cxx:595
SwRootFrame * getRootFrame()
Definition: frame.hxx:685
void SetCompletePaint() const
Definition: frame.hxx:1000
a clone of SwInterHyphInfo, but with TextFrameIndex instead of node index
Definition: txtfrm.hxx:61
TextFrameIndex m_nWordLen
Definition: txtfrm.hxx:71
SwInterHyphInfoTextFrame(SwTextFrame const &rFrame, SwTextNode const &rNode, SwInterHyphInfo const &rHyphInfo)
Definition: txtedt.cxx:1673
TextFrameIndex m_nEnd
Definition: txtfrm.hxx:68
TextFrameIndex m_nStart
input: requested range to hyphenate
Definition: txtfrm.hxx:67
css::uno::Reference< css::linguistic2::XHyphenatedWord > m_xHyphWord
output: hyphenated word
Definition: txtfrm.hxx:64
void UpdateTextNodeHyphInfo(SwTextFrame const &rFrame, SwTextNode const &rNode, SwInterHyphInfo &o_rHyphInfo)
Definition: txtedt.cxx:1683
TextFrameIndex m_nWordStart
output: found word
Definition: txtfrm.hxx:70
void SetHyphWord(const css::uno::Reference< css::linguistic2::XHyphenatedWord > &rxHW)
Definition: splargs.hxx:131
sal_Int32 m_nWordStart
output: found word
Definition: splargs.hxx:117
const Point * GetCursorPos() const
Definition: splargs.hxx:127
sal_Int32 m_nWordLen
Definition: splargs.hxx:118
LanguageType GetLanguage() const
Definition: txatritr.hxx:68
sal_Int32 GetChgPos() const
Definition: txatritr.hxx:67
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:901
SwNodeOffset GetIndex() const
Definition: node.hxx:312
SwDoc & GetDoc()
Definition: node.hxx:233
bool IsInRedlines() const
Checks if this node is in redlines.
Definition: node.cxx:2155
IStyleAccess & getIDocumentStyleAccess()
Provides access to the document automatic styles interface.
Definition: node.cxx:2153
const IDocumentLayoutAccess & getIDocumentLayoutAccess() const
Provides access to the document layout interface.
Definition: node.cxx:2143
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:188
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:643
OUString GetText() const
Definition: pam.cxx:1305
const SwPosition * GetPoint() const
Definition: pam.hxx:253
const SwPosition * Start() const
Definition: pam.hxx:258
void CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32 &rStart, sal_Int32 &rEnd) const
Calculates the intersection with text node number nNdIdx.
Definition: docredln.cxx:1470
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1975
void SetBottom(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1392
void SetRight(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1394
tools::Long GetTop(const SwRect &rRect) const
Definition: frame.hxx:1382
tools::Long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1384
tools::Long GetBottom(const SwRect &rRect) const
Definition: frame.hxx:1383
void SetTop(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1391
tools::Long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1385
void SetLeft(SwRect &rRect, tools::Long nNew) const
Definition: frame.hxx:1393
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void Height(tools::Long nNew)
Definition: swrect.hxx:193
SwRect & Union(const SwRect &rRect)
Definition: swrect.cxx:35
size_type size() const
Definition: docary.hxx:268
vector_type::size_type size_type
Definition: docary.hxx:223
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:215
const LanguageType * m_pLanguage
Definition: swscanner.hxx:39
sal_uInt16 m_nWordType
Definition: swscanner.hxx:47
sal_Int32 m_nLength
Definition: swscanner.hxx:44
const ModelToViewHelper m_ModelToView
Definition: swscanner.hxx:40
bool m_bClip
Definition: swscanner.hxx:48
const OUString m_aPreDashReplacementText
Definition: swscanner.hxx:37
LanguageType m_aCurrentLang
Definition: swscanner.hxx:46
sal_Int32 m_nEndPos
Definition: swscanner.hxx:42
sal_Int32 GetBegin() const
Definition: swscanner.hxx:68
OUString m_aText
Definition: swscanner.hxx:38
sal_Int32 GetLen() const
Definition: swscanner.hxx:70
const OUString & GetWord() const
Definition: swscanner.hxx:65
OUString m_aPrevWord
Definition: swscanner.hxx:36
sal_Int32 getOverriddenDashCount() const
Definition: swscanner.hxx:74
sal_Int32 m_nStartPos
Definition: swscanner.hxx:41
sal_Int32 GetEnd() const
Definition: swscanner.hxx:69
std::function< LanguageType(sal_Int32, sal_Int32, bool)> m_pGetLangOfChar
Definition: swscanner.hxx:34
sal_Int32 m_nBegin
Definition: swscanner.hxx:43
OUString m_aWord
Definition: swscanner.hxx:35
bool NextWord()
Definition: txtedt.cxx:831
SwScanner(std::function< LanguageType(sal_Int32, sal_Int32, bool)> pGetLangOfChar, OUString aText, const LanguageType *pLang, ModelToViewHelper aConvMap, sal_uInt16 nWordType, sal_Int32 nStart, sal_Int32 nEnd, bool bClip=false)
Definition: txtedt.cxx:738
sal_Int32 m_nOverriddenDashCount
Definition: swscanner.hxx:45
const OUString & GetPrevWord() const
Definition: swscanner.hxx:66
LanguageType GetCurrentLanguage() const
Definition: swscanner.hxx:72
static sal_Int32 MaskHiddenRanges(const SwTextNode &rNode, OUStringBuffer &rText, const sal_Int32 nStt, const sal_Int32 nEnd, const sal_Unicode cChar)
Hidden text attribute handling.
Definition: porlay.cxx:1971
static SwSmartTagMgr & Get()
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:167
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
const sal_Int32 * End() const
Definition: txatbase.hxx:156
sal_Int32 GetStart() const
Definition: txatbase.hxx:88
virtual void SetEnd(sal_Int32)
Definition: txatbase.cxx:53
void SetStart(sal_Int32 n)
start position
Definition: txatbase.hxx:87
bool HasContent() const
Definition: txatbase.hxx:112
sal_uInt16 Which() const
Definition: txatbase.hxx:116
void SetSortNumber(sal_uInt16 nSortNumber)
Definition: txtatr.hxx:48
sal_uInt16 GetSortNumber() const
Definition: txtatr.hxx:49
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:168
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:889
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:453
std::pair< SwTextNode *, sal_Int32 > MapViewToModel(TextFrameIndex nIndex) const
map position in potentially merged text frame to SwPosition
Definition: txtfrm.cxx:1318
void CollectAutoCmplWrds(SwTextNode &, sal_Int32)
Is called by DoIdleJob_()
Definition: txtedt.cxx:1623
SwRect SmartTagScan(SwTextNode &)
Is called by DoIdleJob_()
Definition: txtedt.cxx:1507
bool Hyphenate(SwInterHyphInfoTextFrame &rInf)
We format a Line for interactive hyphenation.
Definition: txthyph.cxx:58
TextFrameIndex MapModelToView(SwTextNode const *pNode, sal_Int32 nIndex) const
Definition: txtfrm.cxx:1339
bool IsSymbolAt(TextFrameIndex) const
Definition: itratr.cxx:190
SwRect AutoSpell_(SwTextNode &, sal_Int32)
Is called by DoIdleJob_(), ExecSpellPopup() and UpDown()
Definition: txtedt.cxx:1292
TextFrameIndex MapModelToViewPos(SwPosition const &rPos) const
Definition: txtfrm.cxx:1354
bool IsHiddenNow() const
Hidden.
Definition: txtfrm.cxx:1447
SwTextFrame & GetFrameAtOfst(TextFrameIndex nOfst)
Definition: frmcrsr.cxx:143
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1380
OUString GetCurWord(SwPosition const &) const
Definition: txtedt.cxx:688
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3229
OUString m_Text
Definition: ndtxt.hxx:129
sw::ParagraphIdleData m_aParagraphIdleData
Definition: ndtxt.hxx:131
void SetWrongDirty(sw::WrongState eNew) const
Definition: txtedt.cxx:2345
SAL_DLLPRIVATE void SetLanguageAndFont(const SwPaM &rPaM, LanguageType nLang, sal_uInt16 nLangWhichId, const vcl::Font *pFont, sal_uInt16 nFontWhichId)
Definition: txtedt.cxx:1124
sal_Int32 GetSpaceLeft() const
Definition: ndtxt.hxx:918
bool IsSmartTagDirty() const
Definition: txtedt.cxx:2375
SwWrongList * GetSmartTags()
Definition: txtedt.cxx:2325
void RstTextAttr(const sal_Int32 nContentStart, const sal_Int32 nLen, const sal_uInt16 nWhich=0, const SfxItemSet *pSet=nullptr, const bool bInclRefToxMark=false, const bool bExactRange=false)
delete all attributes.
Definition: txtedt.cxx:388
bool IsGrammarCheckDirty() const
Definition: txtedt.cxx:2365
void ClearSmartTags()
Definition: txtedt.cxx:2315
void DestroyAttr(SwTextAttr *pAttr)
Definition: thints.cxx:1186
void TryDeleteSwpHints()
Definition: ndtxt.hxx:887
SwWrongList * GetWrong()
Definition: txtedt.cxx:2271
bool IsAutoCompleteWordDirty() const
Definition: txtedt.cxx:2385
void SetWordCountDirty(bool bNew) const
Definition: txtedt.cxx:2335
void SetGrammarCheckDirty(bool bNew) const
Definition: txtedt.cxx:2360
void SetSmartTags(std::unique_ptr< SwWrongList > pNew)
Definition: txtedt.cxx:2307
void SetSmartTagDirty(bool bNew) const
Definition: txtedt.cxx:2370
void ReplaceTextOnly(sal_Int32 nPos, sal_Int32 nLen, std::u16string_view aText, const css::uno::Sequence< sal_Int32 > &rOffsets)
Definition: txtedt.cxx:2047
std::unique_ptr< SwpHints > m_pSwpHints
May be 0.
Definition: ndtxt.hxx:123
void ClearGrammarCheck()
Definition: txtedt.cxx:2287
bool HasHints() const
Definition: ndtxt.hxx:254
void SetAutoCompleteWordDirty(bool bNew) const
Definition: txtedt.cxx:2380
void ClearWrong()
Definition: txtedt.cxx:2261
std::unique_ptr< SwWrongList > ReleaseSmartTags()
Definition: txtedt.cxx:2320
bool CountWords(SwDocStat &rStat, sal_Int32 nStart, sal_Int32 nEnd) const
count words in given range - returns true if we refreshed out count
Definition: txtedt.cxx:2096
bool Convert(SwConversionArgs &)
Definition: txtedt.cxx:1156
bool IsSymbolAt(sal_Int32 nBegin) const
in ndcopy.cxx
Definition: itratr.cxx:859
bool IsWordCountDirty() const
Definition: txtedt.cxx:2340
std::unique_ptr< SwGrammarMarkUp > ReleaseGrammarCheck()
Definition: txtedt.cxx:2292
SwGrammarMarkUp * GetGrammarCheck()
Definition: txtedt.cxx:2297
virtual void Update(SwContentIndex const &rPos, const sal_Int32 nChangeLen, UpdateMode eMode) override
override SwContentIndexReg
Definition: ndtxt.cxx:1251
bool IsHidden() const
Definition: ndtxt.cxx:4749
sw::WrongState GetWrongDirty() const
Definition: txtedt.cxx:2350
OUString GetNumString(const bool _bInclPrefixAndSuffixStrings=true, const unsigned int _nRestrictToThisLevel=MAXLEVEL, SwRootFrame const *pLayout=nullptr, SwListRedlineType eRedline=SwListRedlineType::SHOW) const
Returns outline of numbering string.
Definition: ndtxt.cxx:3247
bool Spell(SwSpellArgs *)
Definition: txtedt.cxx:971
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, ::sw::GetTextAttrMode const eMode=::sw::GetTextAttrMode::Default) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1804
bool IsWrongDirty() const
Definition: txtedt.cxx:2355
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:252
void SetWrong(std::unique_ptr< SwWrongList > pNew)
Definition: txtedt.cxx:2256
const OUString & GetText() const
Definition: ndtxt.hxx:244
void TransliterateText(utl::TransliterationWrapper &rTrans, sal_Int32 nStart, sal_Int32 nEnd, SwUndoTransliterate *pUndo, bool bUseRedlining=false)
change text to Upper/Lower/Hiragana/Katakana/...
Definition: txtedt.cxx:1765
bool InsertHint(SwTextAttr *const pAttr, const SetAttrMode nMode=SetAttrMode::DEFAULT)
Insert pAttr into hints array.
Definition: thints.cxx:1340
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3474
void SetGrammarCheck(std::unique_ptr< SwGrammarMarkUp > pNew)
Definition: txtedt.cxx:2282
SwTextAttr * GetTextAttrForCharAt(const sal_Int32 nIndex, const sal_uInt16 nWhich=RES_TXTATR_END) const
get the text attribute at position nIndex which owns the dummy character CH_TXTATR_* at that position...
Definition: ndtxt.cxx:3155
bool Hyphenate(SwInterHyphInfo &rHyphInf)
Interactive hyphenation: we find TextFrame and call its CalcHyph.
Definition: txtedt.cxx:1699
std::unique_ptr< SwWrongList > ReleaseWrong()
Definition: txtedt.cxx:2266
void AddChanges(SwTextNode &rTNd, sal_Int32 nStart, sal_Int32 nLen, css::uno::Sequence< sal_Int32 > const &rOffsets)
Definition: unovwr.cxx:383
static bool IsAutoCompleteWords()
Definition: viewopt.cxx:402
void InvalidateAccessibleParaAttrs(const SwTextFrame &rTextFrame)
invalidate attributes for paragraphs and paragraph's characters
Definition: viewsh.cxx:2625
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:648
sal_uInt16 Count() const
Definition: wrong.hxx:323
sal_Int32 GetEndInv() const
Definition: wrong.hxx:289
sal_Int32 Pos(sal_uInt16 nIdx) const
Definition: wrong.hxx:318
FreshState Fresh(sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos, sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos)
Remove given range of entries.
Definition: wrong.cxx:356
sal_uInt16 GetWrongPos(sal_Int32 nValue) const
Find the first position that is greater or equal to the given value.
Definition: wrong.cxx:191
bool InWrongWord(sal_Int32 &rChk, sal_Int32 &rLn) const
If a word is incorrectly selected, this method returns begin and length of it.
Definition: wrong.cxx:103
void SetInvalid(sal_Int32 nBegin, sal_Int32 nEnd)
Definition: wrong.cxx:254
void Insert(sal_uInt16 nWhere, std::vector< SwWrongArea >::iterator startPos, std::vector< SwWrongArea >::iterator const &endPos)
Definition: wrong.cxx:538
sal_Int32 GetBeginInv() const
Definition: wrong.hxx:288
sal_Int32 Len(sal_uInt16 nIdx) const
Definition: wrong.hxx:313
sal_Int32 NextWrong(sal_Int32 nChk) const
Find next incorrectly selected position.
Definition: wrong.cxx:164
Implementation of the css::text::XTextMarkup interface.
static rtl::Reference< SwXTextRange > CreateXTextRange(SwDoc &rDoc, const SwPosition &rPos, const SwPosition *const pMark)
Definition: unoobj2.cxx:1221
static bool IsChinese(LanguageType nLang)
virtual bool get(DocumentSettingId id) const override
Return the specified document setting.
OUString transliterate(const OUString &rStr, sal_Int32 nStart, sal_Int32 nLen) const
bool needLanguageForTheMode() const
TransliterationFlags getType() const
FontFamily GetFamilyType()
const OUString & GetStyleName() const
const OUString & GetFamilyName() const
FontPitch GetPitch()
rtl_TextEncoding GetCharSet() const
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CJK_FONT(22)
bool isTXTATR_WITHEND(const sal_uInt16 nWhich)
Definition: hintids.hxx:472
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
constexpr TypedWhichId< SwFormatINetFormat > RES_TXTATR_INETFMT(51)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(60)
#define CH_TXTATR_INWORD
Definition: hintids.hxx:175
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
constexpr TypedWhichId< SwFormatRefMark > RES_TXTATR_REFMARK(RES_TXTATR_WITHEND_BEGIN)
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_META(48)
constexpr TypedWhichId< SwTOXMark > RES_TXTATR_TOXMARK(47)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:174
VclInputFlags
#define VCL_INPUT_ANY
#define LANGUAGE_SYSTEM
#define LANGUAGE_NONE
sal_uInt16 nPos
#define SAL_WARN(area, stream)
aStr
aBuf
@ HideFieldmarkCommands
LanguageType GetLanguage(SfxItemSet const &aSet, sal_uInt16 nLangWhichId)
Definition: langhelper.cxx:365
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
end
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
SwTextFrame * SwHyphIterCacheLastTextFrame(SwTextNode const *pNode, const sw::Creator &create)
Definition: edlingu.cxx:584
WrongState
Definition: ndtxt.hxx:87
bool FrameContainsNode(SwContentFrame const &rFrame, SwNodeOffset nNodeIndex)
Definition: txtfrm.cxx:290
TextFrameIndex MapModelToView(MergedPara const &, SwTextNode const *pNode, sal_Int32 nIndex)
Definition: txtfrm.cxx:1270
InsertText MakeInsertText(SwTextNode &rNode, const sal_Int32 nPos, const sal_Int32 nLen)
Definition: docbm.cxx:2094
@ Parent
EXPAND : (Start < nIndex <= End)
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
QPRO_FUNC_TYPE nType
static LanguageType nLang
Definition: srtdlg.cxx:51
This struct defines a position in the model string.
SwPosition * pStartPos
Definition: splargs.hxx:40
SwPosition * pEndPos
Definition: splargs.hxx:41
OUString aConvText
Definition: splargs.hxx:61
bool bAllowImplicitChangesForNotConvertibleText
Definition: splargs.hxx:69
LanguageType nConvSrcLang
Definition: splargs.hxx:62
LanguageType nConvTargetLang
Definition: splargs.hxx:66
const vcl::Font * pTargetFont
Definition: splargs.hxx:67
LanguageType nConvTextLang
Definition: splargs.hxx:63
sal_uLong nWord
Definition: docstat.hxx:35
sal_uLong nCharExcludingSpaces
Definition: docstat.hxx:38
sal_uLong nPara
paragraphs for document statistic: non-empty and non-hidden ones
Definition: docstat.hxx:32
sal_uLong nAsianWord
Definition: docstat.hxx:36
sal_uLong nAllPara
all paragraphs, including empty/hidden ones
Definition: docstat.hxx:34
sal_uLong nChar
Definition: docstat.hxx:37
Marks a position in the document model.
Definition: pam.hxx:38
SwNode & GetNode() const
Definition: pam.hxx:81
void Assign(const SwNode &rNd, SwNodeOffset nDelta, sal_Int32 nContentOffset=0)
These all set both nNode and nContent.
Definition: pam.cxx:231
void SetContent(sal_Int32 nContentIndex)
Set content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:267
sal_Int32 GetContentIndex() const
Definition: pam.hxx:85
css::uno::Reference< css::linguistic2::XSpellAlternatives > xSpellAlt
Definition: splargs.hxx:87
css::uno::Reference< css::linguistic2::XSpellChecker1 > xSpeller
Definition: splargs.hxx:85
UNDERLYING_TYPE get() const
sal_uLong nNumberOfAsianWords
Definition: ndtxt.hxx:95
WrongState eWrongDirty
online spell checking needed/done?
Definition: ndtxt.hxx:99
sal_uLong nNumberOfCharsExcludingSpaces
Definition: ndtxt.hxx:97
std::unique_ptr< SwWrongList > pWrong
Definition: ndtxt.hxx:91
std::unique_ptr< SwWrongList > pSmartTags
Definition: ndtxt.hxx:93
sal_uLong nNumberOfWords
Definition: ndtxt.hxx:94
std::unique_ptr< SwGrammarMarkUp > pGrammarCheck
Definition: ndtxt.hxx:92
bool bAutoComplDirty
auto complete list dirty
Definition: ndtxt.hxx:102
sal_uLong nNumberOfChars
Definition: ndtxt.hxx:96
Reference< XController > xController
#define SW_MOD()
Definition: swmodule.hxx:254
uno::Reference< linguistic2::XSpellChecker1 > GetSpellChecker()
Definition: swtypes.cxx:52
@ NOHINTADJUST
attention: NOHINTADJUST prevents MergePortions! when using this need to pay attention to ignore start...
constexpr sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:57
SwTextAttr * MakeTextAttr(SwDoc &rDoc, SfxPoolItem &rAttr, sal_Int32 const nStt, sal_Int32 const nEnd, CopyOrNewType const bIsCopy, SwTextNode *const pTextNode)
if COPY then pTextNode must be given!
Definition: thints.cxx:1030
const formula::FormulaGrammar::AddressConvention aConvMap[]
static bool lcl_IsDelim(const sal_Unicode c)
Definition: txtedt.cxx:116
static bool lcl_MaskRedlinesAndHiddenText(const SwTextNode &rNode, OUStringBuffer &rText, sal_Int32 nStt, sal_Int32 nEnd, const sal_Unicode cChar=CH_TXTATR_INWORD)
Used for spell checking.
Definition: txtedt.cxx:213
static SwRect lcl_CalculateRepaintRect(const SwTextFrame &rTextFrame, const SwTextNode &rNode, sal_Int32 const nChgStart, sal_Int32 const nChgEnd)
Used for spell checking.
Definition: txtedt.cxx:246
static bool lcl_IsURL(std::u16string_view rWord, SwTextNode &rNode, sal_Int32 nBegin, sal_Int32 nLen)
Definition: txtedt.cxx:124
static sal_Int32 clipIndexBounds(std::u16string_view aStr, sal_Int32 nPos)
Definition: txtedt.cxx:675
static sal_Int32 lcl_MaskRedlines(const SwTextNode &rNode, OUStringBuffer &rText, sal_Int32 nStt, sal_Int32 nEnd, const sal_Unicode cChar)
Definition: txtedt.cxx:169
static bool lcl_HasComments(const SwTextNode &rNode)
Definition: txtedt.cxx:102
static bool lcl_HaveCommonAttributes(IStyleAccess &rStyleAccess, const SfxItemSet *pSet1, sal_uInt16 nWhichId, const SfxItemSet &rSet2, std::shared_ptr< SfxItemSet > &pStyleHandle)
Used for automatic styles.
Definition: txtedt.cxx:319
sal_uInt16 sal_Unicode
Count
@ WRONGLIST_SPELL
Definition: wrong.hxx:58
const char * pChar