1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <hintids.hxx>
22 #include <osl/diagnose.h>
23 #include <unotools/charclass.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/lrspitem.hxx>
27 #include <editeng/formatbreakitem.hxx>
28 #include <editeng/adjustitem.hxx>
29 #include <editeng/tstpitem.hxx>
30 #include <editeng/fontitem.hxx>
31 #include <editeng/langitem.hxx>
32 #include <editeng/acorrcfg.hxx>
33 #include <o3tl/string_view.hxx>
36 #include <fmtpdsc.hxx>
38 #include <IDocumentUndoRedo.hxx>
39 #include <DocumentRedlineManager.hxx>
40 #include <IDocumentStylePoolAccess.hxx>
41 #include <redline.hxx>
42 #include <unocrsr.hxx>
45 #include <contentindex.hxx>
48 #include <poolfmt.hxx>
50 #include <rootfrm.hxx>
53 #include <pagedesc.hxx>
55 #include <acorrect.hxx>
56 #include <shellres.hxx>
57 #include <section.hxx>
59 #include <charatr.hxx>
61 #include <strings.hrc>
62 #include <comcore.hxx>
63 #include <numrule.hxx>
64 #include <itabenum.hxx>
69 using namespace ::com::sun::star
;
71 //JP 16.12.99: definition:
72 // from pos cPosEnDash to cPosEmDash all chars changed to em dashes,
73 // from pos cPosEmDash to cPosEnd all chars changed to em dashes
74 // all other chars are changed to the user configuration
76 const sal_Unicode pBulletChar
[6] = { '+', '*', '-', 0x2013, 0x2014, 0 };
77 const int cnPosEnDash
= 2, cnPosEmDash
= 4;
79 const sal_Unicode cStarSymbolEnDash
= 0x2013;
80 const sal_Unicode cStarSymbolEmDash
= 0x2014;
82 SvxSwAutoFormatFlags
* SwEditShell::s_pAutoFormatFlags
= nullptr;
84 // Number of num-/bullet-paragraph templates. MAXLEVEL will soon be raised
85 // to x, but not the number of templates. (Artifact from <= 4.0)
86 const sal_uInt16 cnNumBullColls
= 4;
90 SvxSwAutoFormatFlags m_aFlags
;
91 SwPaM m_aDelPam
; // a Pam that can be used
92 SwNodeIndex m_aNdIdx
; // the index on the current TextNode
93 SwNodeIndex m_aEndNdIdx
; // index on the end of the area
95 SwEditShell
* m_pEditShell
;
97 SwTextNode
* m_pCurTextNd
; // the current TextNode
98 SwTextFrame
* m_pCurTextFrame
; // frame of the current TextNode
99 bool m_bIsRightToLeft
; // text direction of the current frame
100 SwNodeOffset m_nEndNdIdx
; // for the percentage-display
101 mutable std::optional
<CharClass
> m_oCharClass
; // Character classification
102 mutable LanguageType m_eCharClassLang
;
104 sal_uInt16 m_nRedlAutoFormatSeqId
;
116 NO_DELIM
= (DIGIT
|LOWER_ALPHA
|UPPER_ALPHA
|LOWER_ROMAN
|UPPER_ROMAN
)
120 bool m_bMoreLines
: 1;
122 CharClass
& GetCharClass( LanguageType eLang
) const
124 if( !m_oCharClass
|| eLang
!= m_eCharClassLang
)
126 m_oCharClass
.emplace( LanguageTag( eLang
) );
127 m_eCharClassLang
= eLang
;
129 return *m_oCharClass
;
132 static bool IsSpace( const sal_Unicode c
)
133 { return (' ' == c
|| '\t' == c
|| 0x0a == c
|| 0x3000 == c
/* Jap. space */); }
135 void SetColl( sal_uInt16 nId
, bool bHdLineOrText
= false );
137 static bool HasObjects(const SwTextFrame
&);
140 const SwTextFrame
* GetNextNode(bool isCheckEnd
= true) const;
141 static bool IsEmptyLine(const SwTextFrame
& rFrame
)
143 return rFrame
.GetText().isEmpty()
144 || rFrame
.GetText().getLength() == GetLeadingBlanks(rFrame
.GetText());
147 bool IsOneLine(const SwTextFrame
&) const;
148 bool IsFastFullLine(const SwTextFrame
&) const;
149 bool IsNoAlphaLine(const SwTextFrame
&) const;
150 bool IsEnumericChar(const SwTextFrame
&) const;
151 static bool IsBlanksInString(const SwTextFrame
&);
152 sal_uInt16
CalcLevel(const SwTextFrame
&, sal_uInt16
*pDigitLvl
= nullptr) const;
153 sal_Int32
GetBigIndent(TextFrameIndex
& rCurrentSpacePos
) const;
155 static OUString
DelLeadingBlanks(const OUString
& rStr
);
156 static OUString
DelTrailingBlanks( const OUString
& rStr
);
157 static sal_Int32
GetLeadingBlanks( std::u16string_view aStr
);
158 static sal_Int32
GetTrailingBlanks( std::u16string_view aStr
);
160 bool IsFirstCharCapital(const SwTextFrame
& rNd
) const;
161 sal_uInt16
GetDigitLevel(const SwTextFrame
& rFrame
, TextFrameIndex
& rPos
,
162 OUString
* pPrefix
= nullptr, OUString
* pPostfix
= nullptr,
163 OUString
* pNumTypes
= nullptr ) const;
164 /// get the FORMATTED TextFrame
165 SwTextFrame
* GetFrame( const SwTextNode
& rTextNd
) const;
166 SwTextFrame
* EnsureFormatted(SwTextFrame
const&) const;
170 void BuildTextIndent();
171 void BuildEnum( sal_uInt16 nLvl
, sal_uInt16 nDigitLevel
);
172 void BuildNegIndent( SwTwips nSpaces
);
173 void BuildHeadLine( sal_uInt16 nLvl
);
175 static bool HasBreakAttr(const SwTextFrame
&);
176 void DeleteSel( SwPaM
& rPam
);
177 void DeleteSelImpl(SwPaM
& rDelPam
, SwPaM
& rPamToCorrect
);
178 bool DeleteJoinCurNextPara(SwTextFrame
const* pNextFrame
, bool bIgnoreLeadingBlanks
= false);
179 /// delete in the node start and/or end
180 void DeleteLeadingTrailingBlanks( bool bStart
= true, bool bEnd
= true );
181 void DelEmptyLine( bool bTstNextPara
= true );
182 /// when using multiline paragraphs delete the "left" and/or
184 void DelMoreLinesBlanks( bool bWithLineBreaks
= false );
185 /// join with the previous paragraph
187 /// execute AutoCorrect on current TextNode
188 void AutoCorrect(TextFrameIndex nSttPos
= TextFrameIndex(0));
190 bool CanJoin(const SwTextFrame
* pNextFrame
) const
192 return !m_bEnd
&& pNextFrame
193 && !IsEmptyLine(*pNextFrame
)
194 && !IsNoAlphaLine(*pNextFrame
)
195 && !IsEnumericChar(*pNextFrame
)
196 // check the last / first nodes here...
197 && ((COMPLETE_STRING
- 50 - pNextFrame
->GetTextNodeFirst()->GetText().getLength())
198 > (m_pCurTextFrame
->GetMergedPara()
199 ? m_pCurTextFrame
->GetMergedPara()->pLastNode
200 : m_pCurTextNd
)->GetText().getLength())
201 && !HasBreakAttr(*pNextFrame
);
204 /// is a dot at the end ??
205 static bool IsSentenceAtEnd(const SwTextFrame
& rTextFrame
);
210 void SetRedlineText_( sal_uInt16 nId
);
211 bool SetRedlineText( sal_uInt16 nId
) {
212 if( m_aFlags
.bWithRedlining
)
213 SetRedlineText_( nId
);
216 void ClearRedlineText() {
217 if( m_aFlags
.bWithRedlining
)
218 m_pDoc
->GetDocumentRedlineManager().SetAutoFormatRedlineComment(nullptr);
222 SwAutoFormat( SwEditShell
* pEdShell
, SvxSwAutoFormatFlags aFlags
,
223 SwNode
const * pSttNd
= nullptr, SwNode
const * pEndNd
= nullptr );
226 static const sal_Unicode
* StrChr( const sal_Unicode
* pSrc
, sal_Unicode c
)
228 while( *pSrc
&& *pSrc
!= c
)
230 return *pSrc
? pSrc
: nullptr;
233 SwTextFrame
* SwAutoFormat::GetFrame( const SwTextNode
& rTextNd
) const
236 const SwContentFrame
*pFrame
= rTextNd
.getLayoutFrame( m_pEditShell
->GetLayout() );
237 assert(pFrame
&& "For Autoformat a Layout is needed");
238 return EnsureFormatted(*static_cast<SwTextFrame
const*>(pFrame
));
241 SwTextFrame
* SwAutoFormat::EnsureFormatted(SwTextFrame
const& rFrame
) const
243 SwTextFrame
*const pFrame(const_cast<SwTextFrame
*>(&rFrame
));
244 if( m_aFlags
.bAFormatByInput
&& !pFrame
->isFrameAreaDefinitionValid() )
246 DisableCallbackAction
a(*pFrame
->getRootFrame());
247 SwRect
aTmpFrame( pFrame
->getFrameArea() );
248 SwRect
aTmpPrt( pFrame
->getFramePrintArea() );
249 pFrame
->Calc(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
251 if( pFrame
->getFrameArea() != aTmpFrame
|| pFrame
->getFramePrintArea() != aTmpPrt
||
252 !pFrame
->GetPaintSwRect().IsEmpty())
254 pFrame
->SetCompletePaint();
258 return pFrame
->GetFormatted();
261 void SwAutoFormat::SetRedlineText_( sal_uInt16 nActionId
)
264 sal_uInt16 nSeqNo
= 0;
265 if( STR_AUTOFMTREDL_END
> nActionId
)
267 sText
= SwViewShell::GetShellRes()->GetAutoFormatNameLst()[ nActionId
];
270 case STR_AUTOFMTREDL_SET_NUMBER_BULLET
:
271 case STR_AUTOFMTREDL_DEL_MORELINES
:
273 // AutoCorrect actions
274 case STR_AUTOFMTREDL_USE_REPLACE
:
275 case STR_AUTOFMTREDL_CPTL_STT_WORD
:
276 case STR_AUTOFMTREDL_CPTL_STT_SENT
:
277 case STR_AUTOFMTREDL_TYPO
:
278 case STR_AUTOFMTREDL_UNDER
:
279 case STR_AUTOFMTREDL_BOLD
:
280 case STR_AUTOFMTREDL_FRACTION
:
281 case STR_AUTOFMTREDL_DASH
:
282 case STR_AUTOFMTREDL_ORDINAL
:
283 case STR_AUTOFMTREDL_NON_BREAK_SPACE
:
284 case STR_AUTOFMTREDL_TRANSLITERATE_RTL
:
285 nSeqNo
= ++m_nRedlAutoFormatSeqId
;
289 #if OSL_DEBUG_LEVEL > 0
291 sText
= "Action text is missing";
294 m_pDoc
->GetDocumentRedlineManager().SetAutoFormatRedlineComment( &sText
, nSeqNo
);
297 void SwAutoFormat::GoNextPara()
299 SwNode
* pNewNd
= nullptr;
301 // has to be checked twice before and after incrementation
302 if( m_aNdIdx
.GetIndex() >= m_aEndNdIdx
.GetIndex() )
308 sw::GotoNextLayoutTextFrame(m_aNdIdx
, m_pEditShell
->GetLayout());
309 if( m_aNdIdx
.GetIndex() >= m_aEndNdIdx
.GetIndex() )
315 pNewNd
= &m_aNdIdx
.GetNode();
318 // TableNode : skip table
319 // NoTextNode : skip nodes
320 // EndNode : at the end, terminate
321 if( pNewNd
->IsEndNode() )
326 else if( pNewNd
->IsTableNode() )
327 m_aNdIdx
= *pNewNd
->EndOfSectionNode();
328 else if( pNewNd
->IsSectionNode() )
330 const SwSection
& rSect
= pNewNd
->GetSectionNode()->GetSection();
331 if( rSect
.IsHiddenFlag() || rSect
.IsProtectFlag() )
332 m_aNdIdx
= *pNewNd
->EndOfSectionNode();
334 } while( !pNewNd
->IsTextNode() );
336 if( !m_aFlags
.bAFormatByInput
)
337 ::SetProgressState( sal_Int32(m_aNdIdx
.GetIndex() + m_nEndNdIdx
- m_aEndNdIdx
.GetIndex()),
338 m_pDoc
->GetDocShell() );
340 m_pCurTextNd
= static_cast<SwTextNode
*>(pNewNd
);
341 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
342 m_bIsRightToLeft
= m_pCurTextFrame
->IsRightToLeft();
345 bool SwAutoFormat::HasObjects(const SwTextFrame
& rFrame
)
347 // Is there something bound to the paragraph in the paragraph
348 // like Frames, DrawObjects, ...
349 SwNodeIndex
node(*rFrame
.GetTextNodeFirst());
352 if (!node
.GetNode().GetAnchoredFlys().empty())
356 while (sw::FrameContainsNode(rFrame
, node
.GetIndex()));
360 const SwTextFrame
* SwAutoFormat::GetNextNode(bool const isCheckEnd
) const
362 SwNodeIndex
tmp(m_aNdIdx
);
363 sw::GotoNextLayoutTextFrame(tmp
, m_pEditShell
->GetLayout());
364 if ((isCheckEnd
&& m_aEndNdIdx
<= tmp
) || !tmp
.GetNode().IsTextNode())
366 // note: the returned frame is not necessarily formatted, have to call
367 // EnsureFormatted for that
368 return static_cast<SwTextFrame
*>(tmp
.GetNode().GetTextNode()->getLayoutFrame(m_pEditShell
->GetLayout()));
371 bool SwAutoFormat::IsOneLine(const SwTextFrame
& rFrame
) const
373 SwTextFrameInfo
aFInfo( EnsureFormatted(rFrame
) );
374 return aFInfo
.IsOneLine();
377 bool SwAutoFormat::IsFastFullLine(const SwTextFrame
& rFrame
) const
379 bool bRet
= m_aFlags
.bRightMargin
;
382 SwTextFrameInfo
aFInfo( EnsureFormatted(rFrame
) );
383 bRet
= aFInfo
.IsFilled( m_aFlags
.nRightMargin
);
388 bool SwAutoFormat::IsEnumericChar(const SwTextFrame
& rFrame
) const
390 const OUString
& rText
= rFrame
.GetText();
391 TextFrameIndex
nBlanks(GetLeadingBlanks(rText
));
392 const TextFrameIndex nLen
= TextFrameIndex(rText
.getLength()) - nBlanks
;
396 // -, +, * separated by blank ??
397 if (TextFrameIndex(2) < nLen
&& IsSpace(rText
[sal_Int32(nBlanks
) + 1]))
399 if (StrChr(pBulletChar
, rText
[sal_Int32(nBlanks
)]))
401 // Should there be a symbol font at the position?
402 SwTextFrameInfo
aFInfo( EnsureFormatted(rFrame
) );
403 if (aFInfo
.IsBullet(nBlanks
))
407 // 1.) / 1. / 1.1.1 / (1). / (1) / ...
408 return USHRT_MAX
!= GetDigitLevel(rFrame
, nBlanks
);
411 bool SwAutoFormat::IsBlanksInString(const SwTextFrame
& rFrame
)
413 // Search more than 5 consecutive blanks/tabs in the string.
414 OUString
sTmp( DelLeadingBlanks(rFrame
.GetText()) );
415 const sal_Int32 nLen
= sTmp
.getLength();
420 while (nIdx
< nLen
&& !IsSpace(sTmp
[nIdx
])) ++nIdx
;
423 // Then count consecutive blanks
424 const sal_Int32 nFirst
= nIdx
;
425 while (nIdx
< nLen
&& IsSpace(sTmp
[nIdx
])) ++nIdx
;
426 // And exit if enough consecutive blanks were found
433 sal_uInt16
SwAutoFormat::CalcLevel(const SwTextFrame
& rFrame
,
434 sal_uInt16
*const pDigitLvl
) const
436 sal_uInt16 nLvl
= 0, nBlnk
= 0;
437 const OUString
& rText
= rFrame
.GetText();
439 *pDigitLvl
= USHRT_MAX
;
441 if (RES_POOLCOLL_TEXT_MOVE
== rFrame
.GetTextNodeForParaProps()->GetTextColl()->GetPoolFormatId())
443 if( m_aFlags
.bAFormatByInput
)
445 // this is very non-obvious: on the *first* invocation of
446 // AutoFormat, the node will have the tabs (any number) converted
447 // to a fixed indent in BuildTextIndent(), and the number of tabs
448 // is stored in the node;
449 // on the *second* invocation of AutoFormat, CalcLevel() will
450 // retrieve the stored number, and it will be used by
451 // BuildHeadLine() to select the corresponding heading style.
452 nLvl
= rFrame
.GetTextNodeForParaProps()->GetAutoFormatLvl();
453 const_cast<SwTextNode
*>(rFrame
.GetTextNodeForParaProps())->SetAutoFormatLvl(0);
460 for (TextFrameIndex
n(0),
461 nEnd(rText
.getLength()); n
< nEnd
; ++n
)
463 switch (rText
[sal_Int32(n
)])
465 case ' ': if( 3 == ++nBlnk
)
476 // test 1.) / 1. / 1.1.1 / (1). / (1) / ...
477 *pDigitLvl
= GetDigitLevel(rFrame
, n
);
484 sal_Int32
SwAutoFormat::GetBigIndent(TextFrameIndex
& rCurrentSpacePos
) const
486 SwTextFrameInfo
aFInfo( m_pCurTextFrame
);
487 const SwTextFrame
* pNextFrame
= nullptr;
491 pNextFrame
= GetNextNode();
492 if (!CanJoin(pNextFrame
) || !IsOneLine(*pNextFrame
))
495 pNextFrame
= EnsureFormatted(*pNextFrame
);
498 return aFInfo
.GetBigIndent( rCurrentSpacePos
, pNextFrame
);
501 bool SwAutoFormat::IsNoAlphaLine(const SwTextFrame
& rFrame
) const
503 const OUString
& rStr
= rFrame
.GetText();
506 // or better: determine via number of AlphaNum and !AlphaNum characters
507 sal_Int32 nANChar
= 0, nBlnk
= 0;
509 for (TextFrameIndex
n(0),
510 nEnd(rStr
.getLength()); n
< nEnd
; ++n
)
511 if (IsSpace(rStr
[sal_Int32(n
)]))
515 auto const pair
= rFrame
.MapViewToModel(n
);
516 CharClass
& rCC
= GetCharClass(pair
.first
->GetSwAttrSet().GetLanguage().GetLanguage());
517 if (rCC
.isLetterNumeric(rStr
, sal_Int32(n
)))
521 // If there are 75% of non-alphanumeric characters, then true
522 sal_uLong nLen
= rStr
.getLength() - nBlnk
;
523 nLen
= ( nLen
* 3 ) / 4; // long overflow, if the strlen > sal_uInt16
524 return sal_Int32(nLen
) < (rStr
.getLength() - nANChar
- nBlnk
);
527 bool SwAutoFormat::DoUnderline()
529 if( !m_aFlags
.bSetBorder
)
532 OUString
const& rText(m_pCurTextFrame
->GetText());
535 while (nCnt
< rText
.getLength())
540 case '-': eTmp
= 1; break;
541 case '_': eTmp
= 2; break;
542 case '=': eTmp
= 3; break;
543 case '*': eTmp
= 4; break;
544 case '~': eTmp
= 5; break;
545 case '#': eTmp
= 6; break;
551 else if( eState
!= eTmp
)
558 // then underline the previous paragraph if one exists
559 DelEmptyLine( false ); // -> point will be on end of current paragraph
560 // WARNING: rText may be deleted now, m_pCurTextFrame may be nullptr
562 // apply to last node & rely on InsertItemSet to apply it to props-node
564 editeng::SvxBorderLine aLine
;
567 case 1: // single, hairline
568 aLine
.SetBorderLineStyle(SvxBorderLineStyle::SOLID
);
569 aLine
.SetWidth( SvxBorderLineWidth::Hairline
);
571 case 2: // single, thin
572 aLine
.SetBorderLineStyle(SvxBorderLineStyle::SOLID
);
573 aLine
.SetWidth( SvxBorderLineWidth::Thin
);
575 case 3: // double, thin
576 aLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
577 aLine
.SetWidth( SvxBorderLineWidth::Thin
);
579 case 4: // double, thick/thin
580 aLine
.SetBorderLineStyle(SvxBorderLineStyle::THICKTHIN_SMALLGAP
);
581 aLine
.SetWidth( SvxBorderLineWidth::Thick
);
583 case 5: // double, thin/thick
584 aLine
.SetBorderLineStyle(SvxBorderLineStyle::THINTHICK_SMALLGAP
);
585 aLine
.SetWidth( SvxBorderLineWidth::Thick
);
587 case 6: // double, medium
588 aLine
.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE
);
589 aLine
.SetWidth( SvxBorderLineWidth::Medium
);
592 SfxItemSetFixed
<RES_PARATR_CONNECT_BORDER
, RES_PARATR_CONNECT_BORDER
,
593 RES_BOX
, RES_BOX
> aSet(m_pDoc
->GetAttrPool());
594 aSet
.Put( SwParaConnectBorderItem( false ) );
595 SvxBoxItem
aBox( RES_BOX
);
596 aBox
.SetLine( &aLine
, SvxBoxItemLine::BOTTOM
);
597 aBox
.SetDistance(42, SvxBoxItemLine::BOTTOM
); // ~0,75 mm
599 m_pDoc
->getIDocumentContentOperations().InsertItemSet(m_aDelPam
, aSet
,
600 SetAttrMode::DEFAULT
, m_pEditShell
->GetLayout());
602 m_aDelPam
.DeleteMark();
607 bool SwAutoFormat::DoTable()
609 if( !m_aFlags
.bCreateTable
|| !m_aFlags
.bAFormatByInput
||
610 m_pCurTextNd
->FindTableNode() )
613 const OUString
& rTmp
= m_pCurTextFrame
->GetText();
614 TextFrameIndex
nSttPlus(GetLeadingBlanks(rTmp
));
615 TextFrameIndex
nEndPlus(GetTrailingBlanks(rTmp
));
618 if (TextFrameIndex(2) > nEndPlus
- nSttPlus
619 || ('+' != (cChar
= rTmp
[sal_Int32(nSttPlus
)]) && '|' != cChar
)
620 || ('+' != (cChar
= rTmp
[sal_Int32(nEndPlus
) - 1]) && '|' != cChar
))
623 SwTextFrameInfo
aInfo( m_pCurTextFrame
);
625 TextFrameIndex n
= nSttPlus
;
626 std::vector
<sal_uInt16
> aPosArr
;
628 while (n
< TextFrameIndex(rTmp
.getLength()))
630 switch (rTmp
[sal_Int32(n
)])
641 aPosArr
.push_back( o3tl::narrowing
<sal_uInt16
>(aInfo
.GetCharPos(n
)) );
647 if( ++n
== nEndPlus
)
651 if( 1 < aPosArr
.size() )
653 // get the text node's alignment
654 sal_uInt16 nColCnt
= aPosArr
.size() - 1;
655 SwTwips nSttPos
= aPosArr
[ 0 ];
657 switch (m_pCurTextFrame
->GetTextNodeForParaProps()->GetSwAttrSet().GetAdjust().GetAdjust())
659 case SvxAdjust::Center
: eHori
= text::HoriOrientation::CENTER
; break;
660 case SvxAdjust::Right
: eHori
= text::HoriOrientation::RIGHT
; break;
665 eHori
= text::HoriOrientation::NONE
;
666 // then - as last - we need to add the current frame width into the array
667 aPosArr
.push_back( o3tl::narrowing
<sal_uInt16
>(m_pCurTextFrame
->getFrameArea().Width()) );
670 eHori
= text::HoriOrientation::LEFT
;
674 // then create a table that matches the character
676 // WARNING: rTmp may be deleted now, m_pCurTextFrame may be nullptr
677 SwNodeIndex
aIdx( m_aDelPam
.GetPoint()->GetNode() );
678 m_aDelPam
.Move( fnMoveForward
);
679 m_pDoc
->InsertTable( SwInsertTableOptions( SwInsertTableFlags::All
, 1 ),
680 *m_aDelPam
.GetPoint(), 1, nColCnt
, eHori
,
682 m_aDelPam
.GetPoint()->Assign(aIdx
);
684 return 1 < aPosArr
.size();
687 OUString
SwAutoFormat::DelLeadingBlanks( const OUString
& rStr
)
690 for( nL
= rStr
.getLength(), n
= 0; n
< nL
&& IsSpace( rStr
[n
] ); ++n
)
697 OUString
SwAutoFormat::DelTrailingBlanks( const OUString
& rStr
)
699 sal_Int32 nL
= rStr
.getLength(), n
= nL
;
703 while( --n
&& IsSpace( rStr
[ n
] ) )
705 if( n
+1 != nL
) // no Spaces
706 return rStr
.copy( 0, n
+1 );
710 sal_Int32
SwAutoFormat::GetLeadingBlanks( std::u16string_view aStr
)
715 for( nL
= aStr
.size(), n
= 0; n
< nL
&& IsSpace( aStr
[ n
] ); ++n
)
720 sal_Int32
SwAutoFormat::GetTrailingBlanks( std::u16string_view aStr
)
722 size_t nL
= aStr
.size(), n
= nL
;
726 while( --n
&& IsSpace( aStr
[ n
] ) )
731 bool SwAutoFormat::IsFirstCharCapital(const SwTextFrame
& rFrame
) const
733 const OUString
& rText
= rFrame
.GetText();
734 for (TextFrameIndex
n(0),
735 nEnd(rText
.getLength()); n
< nEnd
; ++n
)
736 if (!IsSpace(rText
[sal_Int32(n
)]))
738 auto const pair
= rFrame
.MapViewToModel(n
);
739 CharClass
& rCC
= GetCharClass( pair
.first
->GetSwAttrSet().
740 GetLanguage().GetLanguage() );
741 sal_Int32 nCharType
= rCC
.getCharacterType(rText
, sal_Int32(n
));
742 return CharClass::isLetterType( nCharType
) &&
743 0 != ( i18n::KCharacterType::UPPER
&
750 SwAutoFormat::GetDigitLevel(const SwTextFrame
& rFrame
, TextFrameIndex
& rPos
,
751 OUString
* pPrefix
, OUString
* pPostfix
, OUString
* pNumTypes
) const
754 // check for 1.) / 1. / 1.1.1 / (1). / (1) / ...
755 const OUString
& rText
= rFrame
.GetText();
756 sal_Int32
nPos(rPos
);
759 sal_uInt16 nStart
= 0;
760 sal_uInt8 nDigitLvl
= 0, nDigitCnt
= 0;
761 // count number of parenthesis to assure a sensible order is found
762 sal_uInt16 nOpeningParentheses
= 0;
763 sal_uInt16 nClosingParentheses
= 0;
765 while (nPos
< rText
.getLength() && nDigitLvl
< MAXLEVEL
- 1)
767 auto const pair
= rFrame
.MapViewToModel(TextFrameIndex(nPos
));
768 CharClass
& rCC
= GetCharClass(pair
.first
->GetSwAttrSet().GetLanguage().GetLanguage());
769 const sal_Unicode cCurrentChar
= rText
[nPos
];
770 if( ('0' <= cCurrentChar
&& '9' >= cCurrentChar
) ||
771 (0xff10 <= cCurrentChar
&& 0xff19 >= cCurrentChar
) )
775 if( eScan
& CHG
) // not if it starts with a number
783 *pNumTypes
+= OUStringChar(sal_Unicode('0' + SVX_NUM_ARABIC
));
787 else if( pNumTypes
&& !(eScan
& DIGIT
) )
788 *pNumTypes
+= OUStringChar(sal_Unicode('0' + SVX_NUM_ARABIC
));
790 eScan
&= ~DELIM
; // remove Delim
791 if( 0 != (eScan
& ~CHG
) && DIGIT
!= (eScan
& ~CHG
))
794 eScan
|= DIGIT
; // add Digit
795 if( 3 == ++nDigitCnt
) // more than 2 numbers are not an enum anymore
799 nStart
+= cCurrentChar
<= '9' ? cCurrentChar
- '0' : cCurrentChar
- 0xff10;
801 else if( rCC
.isAlpha( rText
, nPos
) )
804 0 != ( i18n::KCharacterType::UPPER
&
805 rCC
.getCharacterType( rText
, nPos
));
806 sal_Unicode cLow
= rCC
.lowercase(rText
, nPos
, 1)[0], cNumTyp
;
809 // Roman numbers are "mdclxvi". Since we want to start numbering with c or d more often,
810 // convert first to characters and later to roman numbers if needed.
811 if( 256 > cLow
&& strchr( "mdclxvi", cLow
) )
815 cNumTyp
= '0' + SVX_NUM_ROMAN_UPPER
;
816 eTmpScan
= UPPER_ROMAN
;
820 cNumTyp
= '0' + SVX_NUM_ROMAN_LOWER
;
821 eTmpScan
= LOWER_ROMAN
;
826 cNumTyp
= '0' + SVX_NUM_CHARS_UPPER_LETTER
;
827 eTmpScan
= UPPER_ALPHA
;
831 cNumTyp
= '0' + SVX_NUM_CHARS_LOWER_LETTER
;
832 eTmpScan
= LOWER_ALPHA
;
835 // Switch to roman numbers (only for c/d!)
836 if( 1 == nDigitCnt
&& ( eScan
& (UPPER_ALPHA
|LOWER_ALPHA
) ) &&
837 ( 3 == nStart
|| 4 == nStart
) && 256 > cLow
&&
838 strchr( "mdclxvi", cLow
) &&
839 (( eScan
& UPPER_ALPHA
) ? (eTmpScan
& (UPPER_ALPHA
|UPPER_ROMAN
))
840 : (eTmpScan
& (LOWER_ALPHA
|LOWER_ROMAN
))) )
843 nStart
= 3 == nStart
? 100 : 500;
844 if( UPPER_ALPHA
== eTmpScan
)
846 eTmpScan
= UPPER_ROMAN
;
847 c
+= SVX_NUM_ROMAN_UPPER
;
851 eTmpScan
= LOWER_ROMAN
;
852 c
+= SVX_NUM_ROMAN_LOWER
;
855 eScan
= (eScan
& ~(UPPER_ALPHA
|LOWER_ALPHA
)) | eTmpScan
;
857 (*pNumTypes
) = pNumTypes
->replaceAt( pNumTypes
->getLength() - 1, 1, rtl::OUStringChar(c
) );
862 if( eScan
& CHG
) // not if it starts with a number
870 *pNumTypes
+= OUStringChar(cNumTyp
);
873 else if( pNumTypes
&& !(eScan
& eTmpScan
) )
874 *pNumTypes
+= OUStringChar(cNumTyp
);
876 eScan
&= ~DELIM
; // remove Delim
878 // if another type is set, stop here
879 if( 0 != ( eScan
& ~CHG
) && eTmpScan
!= ( eScan
& ~CHG
))
882 if( eTmpScan
& (UPPER_ALPHA
| LOWER_ALPHA
) )
884 // allow characters only if they appear once
889 // roman numbers, check if valid characters
894 case 'm': nVal
= 1000; goto CHECK_ROMAN_1
;
895 case 'd': nVal
= 500; goto CHECK_ROMAN_5
;
896 case 'c': nVal
= 100; goto CHECK_ROMAN_1
;
897 case 'l': nVal
= 50; goto CHECK_ROMAN_5
;
898 case 'x': nVal
= 10; goto CHECK_ROMAN_1
;
899 case 'v': nVal
= 5; goto CHECK_ROMAN_5
;
903 int nMod5
= nStart
% (nVal
* 5);
904 int nLast
= nStart
% nVal
;
907 if( nMod5
== ((3 * nVal
) + n10
) ||
908 nMod5
== ((4 * nVal
) + n10
) ||
910 nStart
= o3tl::narrowing
<sal_uInt16
>(nStart
+ (n10
* 8));
911 else if( nMod5
== 0 ||
912 nMod5
== (1 * nVal
) ||
913 nMod5
== (2 * nVal
) )
914 nStart
= nStart
+ nVal
;
922 if( ( nStart
/ nVal
) & 1 )
926 int nMod
= nStart
% nVal
;
929 nStart
= o3tl::narrowing
<sal_uInt16
>(nStart
+ (3 * n10
));
931 nStart
= nStart
+ nVal
;
939 if( nStart
% 5 >= 3 )
952 eScan
|= eTmpScan
; // add Digit
955 else if( (256 > cCurrentChar
&&
956 strchr( ".)(", cCurrentChar
)) ||
957 0x3002 == cCurrentChar
/* Chinese trad. dot */||
958 0xff0e == cCurrentChar
/* Japanese dot */||
959 0xFF08 == cCurrentChar
/* opening bracket Chin./Jap.*/||
960 0xFF09 == cCurrentChar
)/* closing bracket Chin./Jap. */
962 if(cCurrentChar
== '(' || cCurrentChar
== 0xFF09)
963 nOpeningParentheses
++;
964 else if(cCurrentChar
== ')'|| cCurrentChar
== 0xFF08)
965 nClosingParentheses
++;
966 // only if no numbers were read until here
967 if( pPrefix
&& !( eScan
& ( NO_DELIM
| CHG
)) )
968 *pPrefix
+= OUStringChar(rText
[nPos
]);
970 *pPostfix
+= OUStringChar(rText
[nPos
]);
972 if( NO_DELIM
& eScan
)
976 *pPrefix
+= "\x01" + OUString::number( nStart
);
978 eScan
&= ~NO_DELIM
; // remove Delim
979 eScan
|= DELIM
; // add Digit
987 if (!( CHG
& eScan
) || rPos
== TextFrameIndex(nPos
) ||
988 nPos
== rText
.getLength() || !IsSpace(rText
[nPos
]) ||
989 (nOpeningParentheses
> nClosingParentheses
))
992 if( (NO_DELIM
& eScan
) && pPrefix
) // do not forget the last one
993 *pPrefix
+= "\x01" + OUString::number( nStart
);
995 rPos
= TextFrameIndex(nPos
);
996 return nDigitLvl
; // 0 .. 9 (MAXLEVEL - 1)
999 void SwAutoFormat::SetColl( sal_uInt16 nId
, bool bHdLineOrText
)
1001 m_aDelPam
.DeleteMark();
1002 m_aDelPam
.GetPoint()->Assign( *m_pCurTextFrame
->GetTextNodeForParaProps() );
1004 // keep hard tabs, alignment, language, hyphenation, DropCaps and nearly all frame attributes
1006 RES_CHRATR_LANGUAGE
, RES_CHRATR_LANGUAGE
,
1007 RES_PARATR_ADJUST
, RES_PARATR_ADJUST
,
1008 RES_PARATR_TABSTOP
, RES_PARATR_DROP
,
1009 RES_BACKGROUND
, RES_SHADOW
> aSet(m_pDoc
->GetAttrPool());
1011 if (m_aDelPam
.GetPoint()->GetNode().GetTextNode()->HasSwAttrSet())
1013 aSet
.Put(*m_aDelPam
.GetPoint()->GetNode().GetTextNode()->GetpSwAttrSet());
1014 // take HeaderLine/TextBody only if centered or right aligned, otherwise only justification
1015 if( SvxAdjustItem
const * pAdj
= aSet
.GetItemIfSet( RES_PARATR_ADJUST
, false) )
1017 SvxAdjust eAdj
= pAdj
->GetAdjust();
1018 if( bHdLineOrText
? (SvxAdjust::Right
!= eAdj
&&
1019 SvxAdjust::Center
!= eAdj
)
1020 : SvxAdjust::Block
!= eAdj
)
1021 aSet
.ClearItem( RES_PARATR_ADJUST
);
1025 m_pDoc
->SetTextFormatCollByAutoFormat( *m_aDelPam
.GetPoint(), nId
, &aSet
);
1028 static bool HasSelBlanks(
1029 SwTextFrame
const*const pStartFrame
, TextFrameIndex
& rStartIndex
,
1030 SwTextFrame
const*const pEndFrame
, TextFrameIndex
& rEndIndex
)
1032 if (TextFrameIndex(0) < rEndIndex
1033 && rEndIndex
< TextFrameIndex(pEndFrame
->GetText().getLength())
1034 && ' ' == pEndFrame
->GetText()[sal_Int32(rEndIndex
) - 1])
1039 if (rStartIndex
< TextFrameIndex(pStartFrame
->GetText().getLength())
1040 && ' ' == pStartFrame
->GetText()[sal_Int32(rStartIndex
)])
1048 bool SwAutoFormat::HasBreakAttr(const SwTextFrame
& rTextFrame
)
1050 const SfxItemSet
*const pSet
= rTextFrame
.GetTextNodeFirst()->GetpSwAttrSet();
1054 const SvxFormatBreakItem
* pBreakItem
= pSet
->GetItemIfSet( RES_BREAK
, false );
1055 if( pBreakItem
&& SvxBreak::NONE
!= pBreakItem
->GetBreak() )
1058 const SwFormatPageDesc
* pItem
= pSet
->GetItemIfSet( RES_PAGEDESC
, false );
1059 if( pItem
&& pItem
->GetPageDesc()
1060 && UseOnPage::NONE
!= pItem
->GetPageDesc()->GetUseOn() )
1065 /// Is there a dot at the end?
1066 bool SwAutoFormat::IsSentenceAtEnd(const SwTextFrame
& rTextFrame
)
1068 const OUString
& rStr
= rTextFrame
.GetText();
1069 sal_Int32 n
= rStr
.getLength();
1073 while( --n
&& IsSpace( rStr
[ n
] ) )
1075 return '.' == rStr
[ n
];
1078 /// Delete beginning and/or end in a node
1079 void SwAutoFormat::DeleteLeadingTrailingBlanks(bool bStart
, bool bEnd
)
1081 if( !(m_aFlags
.bAFormatByInput
1082 ? m_aFlags
.bAFormatByInpDelSpacesAtSttEnd
1083 : m_aFlags
.bAFormatDelSpacesAtSttEnd
) )
1086 // delete blanks at the end of the current and at the beginning of the next one
1087 m_aDelPam
.DeleteMark();
1088 TextFrameIndex
nPos(GetLeadingBlanks(m_pCurTextFrame
->GetText()));
1089 if (bStart
&& TextFrameIndex(0) != nPos
)
1091 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(TextFrameIndex(0));
1092 m_aDelPam
.SetMark();
1093 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
1094 DeleteSel( m_aDelPam
);
1095 m_aDelPam
.DeleteMark();
1097 nPos
= TextFrameIndex(GetTrailingBlanks(m_pCurTextFrame
->GetText()));
1098 if (bEnd
&& TextFrameIndex(m_pCurTextFrame
->GetText().getLength()) != nPos
)
1100 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(
1101 TextFrameIndex(m_pCurTextFrame
->GetText().getLength()));
1102 m_aDelPam
.SetMark();
1103 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
1104 DeleteSel( m_aDelPam
);
1105 m_aDelPam
.DeleteMark();
1111 bool GetRanges(std::vector
<std::shared_ptr
<SwUnoCursor
>> & rRanges
,
1112 SwDoc
& rDoc
, SwPaM
const& rDelPam
)
1114 bool isNoRedline(true);
1115 SwRedlineTable::size_type tmp
;
1116 IDocumentRedlineAccess
const& rIDRA(rDoc
.getIDocumentRedlineAccess());
1117 if (!(rIDRA
.GetRedlineFlags() & RedlineFlags::ShowDelete
))
1121 rIDRA
.GetRedline(*rDelPam
.Start(), &tmp
);
1122 SwPosition
const* pCurrent(rDelPam
.Start());
1123 for ( ; tmp
< rIDRA
.GetRedlineTable().size(); ++tmp
)
1125 SwRangeRedline
const*const pRedline(rIDRA
.GetRedlineTable()[tmp
]);
1126 if (*rDelPam
.End() <= *pRedline
->Start())
1130 if (*pRedline
->End() <= *rDelPam
.Start())
1134 if (pRedline
->GetType() == RedlineType::Delete
)
1136 assert(*pRedline
->Start() != *pRedline
->End());
1137 isNoRedline
= false;
1138 if (*pCurrent
< *pRedline
->Start())
1140 rRanges
.push_back(rDoc
.CreateUnoCursor(*pCurrent
));
1141 rRanges
.back()->SetMark();
1142 *rRanges
.back()->GetPoint() = *pRedline
->Start();
1144 pCurrent
= pRedline
->End();
1147 if (!isNoRedline
&& *pCurrent
< *rDelPam
.End())
1149 rRanges
.push_back(rDoc
.CreateUnoCursor(*pCurrent
));
1150 rRanges
.back()->SetMark();
1151 *rRanges
.back()->GetPoint() = *rDelPam
.End();
1158 void SwAutoFormat::DeleteSel(SwPaM
& rDelPam
)
1160 std::vector
<std::shared_ptr
<SwUnoCursor
>> ranges
; // need correcting cursor
1161 if (GetRanges(ranges
, *m_pDoc
, rDelPam
))
1163 DeleteSelImpl(rDelPam
, rDelPam
);
1167 for (auto const& pCursor
: ranges
)
1169 DeleteSelImpl(*pCursor
, rDelPam
);
1174 void SwAutoFormat::DeleteSelImpl(SwPaM
& rDelPam
, SwPaM
& rPamToCorrect
)
1176 if (m_aFlags
.bWithRedlining
|| &rDelPam
!= &rPamToCorrect
)
1178 // Add to Shell-Cursor-Ring so that DelPam will be moved as well!
1179 SwPaM
* pShCursor
= m_pEditShell
->GetCursor_();
1180 SwPaM
aTmp( *m_pCurTextNd
, 0, pShCursor
);
1182 SwPaM
* pPrev
= rPamToCorrect
.GetPrev();
1183 rPamToCorrect
.GetRingContainer().merge( pShCursor
->GetRingContainer() );
1185 m_pEditShell
->DeleteSel(rDelPam
, true);
1187 // and remove Pam again:
1189 SwPaM
* pNext
= &rPamToCorrect
;
1192 pNext
= p
->GetNext();
1193 p
->MoveTo( &rPamToCorrect
);
1194 } while( p
!= pPrev
);
1196 m_aNdIdx
= aTmp
.GetPoint()->GetNode();
1197 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
1198 m_pCurTextFrame
= GetFrame(*m_pCurTextNd
); // keep it up to date
1201 m_pEditShell
->DeleteSel(rDelPam
, true);
1204 bool SwAutoFormat::DeleteJoinCurNextPara(SwTextFrame
const*const pNextFrame
,
1205 bool const bIgnoreLeadingBlanks
)
1207 // delete blanks at the end of the current and at the beginning of the next one
1208 m_aDelPam
.DeleteMark();
1209 TextFrameIndex
nTrailingPos(GetTrailingBlanks(m_pCurTextFrame
->GetText()));
1211 SwTextFrame
const*const pEndFrame(pNextFrame
? pNextFrame
: m_pCurTextFrame
);
1212 TextFrameIndex
nLeadingPos(0);
1215 nLeadingPos
= TextFrameIndex(
1216 bIgnoreLeadingBlanks
? 0 : GetLeadingBlanks(pNextFrame
->GetText()));
1220 nLeadingPos
= TextFrameIndex(m_pCurTextFrame
->GetText().getLength());
1223 // Is there a Blank at the beginning or end?
1224 // Do not delete it, it will be inserted again.
1225 bool bHasBlnks
= HasSelBlanks(m_pCurTextFrame
, nTrailingPos
, pEndFrame
, nLeadingPos
);
1227 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nTrailingPos
);
1228 m_aDelPam
.SetMark();
1229 *m_aDelPam
.GetPoint() = pEndFrame
->MapViewToModelPos(nLeadingPos
);
1231 if( *m_aDelPam
.GetPoint() != *m_aDelPam
.GetMark() )
1232 DeleteSel( m_aDelPam
);
1233 m_aDelPam
.DeleteMark();
1234 // note: keep m_aDelPam point at insert pos. for clients
1239 void SwAutoFormat::DelEmptyLine( bool bTstNextPara
)
1241 SetRedlineText( STR_AUTOFMTREDL_DEL_EMPTY_PARA
);
1242 // delete blanks in empty paragraph
1243 m_aDelPam
.DeleteMark();
1244 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(
1246 m_aDelPam
.SetMark();
1248 m_aDelPam
.GetMark()->Assign( m_pCurTextFrame
->GetTextNodeFirst()->GetIndex() - 1 );
1249 SwTextNode
* pTNd
= m_aDelPam
.GetMarkNode().GetTextNode();
1251 // first use the previous text node
1252 m_aDelPam
.GetMark()->SetContent(pTNd
->GetText().getLength());
1253 else if( bTstNextPara
)
1255 // then try the next (at the beginning of a Doc, table cells, frames, ...)
1256 const SwTextNode
* pNext
= m_pCurTextFrame
->GetMergedPara()
1257 ? m_pCurTextFrame
->GetMergedPara()->pLastNode
1259 m_aDelPam
.GetMark()->Assign(pNext
->GetIndex() + 1);
1260 pTNd
= m_aDelPam
.GetMarkNode().GetTextNode();
1263 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(
1264 TextFrameIndex(m_pCurTextFrame
->GetText().getLength()));
1268 { // join with previous or next paragraph
1269 DeleteSel(m_aDelPam
);
1271 assert(m_aDelPam
.GetPointNode().IsTextNode());
1272 assert(!m_aDelPam
.HasMark());
1273 m_aDelPam
.SetMark(); // mark remains at join position
1274 m_pCurTextFrame
= GetFrame(*m_aDelPam
.GetPointNode().GetTextNode());
1275 // replace until the end of the merged paragraph
1276 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(
1277 TextFrameIndex(m_pCurTextFrame
->GetText().getLength()));
1278 if (*m_aDelPam
.GetPoint() != *m_aDelPam
.GetMark())
1279 { // tdf#137245 replace (not delete) to preserve any flys
1280 m_pDoc
->getIDocumentContentOperations().ReplaceRange(m_aDelPam
, "", false);
1283 m_aDelPam
.DeleteMark();
1285 // note: this likely has deleted m_pCurTextFrame - update it...
1286 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
1287 m_pCurTextFrame
= m_pCurTextNd
? GetFrame( *m_pCurTextNd
) : nullptr;
1290 void SwAutoFormat::DelMoreLinesBlanks( bool bWithLineBreaks
)
1292 if( !(m_aFlags
.bAFormatByInput
1293 ? m_aFlags
.bAFormatByInpDelSpacesBetweenLines
1294 : m_aFlags
.bAFormatDelSpacesBetweenLines
) )
1297 // delete all blanks on the left and right of the indentation
1298 m_aDelPam
.DeleteMark();
1300 SwTextFrameInfo
aFInfo( m_pCurTextFrame
);
1301 std::vector
<std::pair
<TextFrameIndex
, TextFrameIndex
>> spaces
;
1302 aFInfo
.GetSpaces(spaces
, !m_aFlags
.bAFormatByInput
|| bWithLineBreaks
);
1304 // tdf#123285 iterate backwards - delete invalidates following indexes
1305 for (auto iter
= spaces
.rbegin(); iter
!= spaces
.rend(); ++iter
)
1307 auto & rSpaceRange(*iter
);
1308 assert(rSpaceRange
.first
!= rSpaceRange
.second
);
1309 bool const bHasBlanks
= HasSelBlanks(
1310 m_pCurTextFrame
, rSpaceRange
.first
,
1311 m_pCurTextFrame
, rSpaceRange
.second
);
1312 if (rSpaceRange
.first
!= rSpaceRange
.second
)
1314 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(rSpaceRange
.first
);
1315 m_aDelPam
.SetMark();
1316 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(rSpaceRange
.second
);
1317 DeleteSel(m_aDelPam
);
1320 m_pDoc
->getIDocumentContentOperations().InsertString(m_aDelPam
, OUString(' '));
1322 m_aDelPam
.DeleteMark();
1327 void SwAutoFormat::JoinPrevPara()
1329 m_aDelPam
.DeleteMark();
1330 m_aDelPam
.GetPoint()->Assign( *m_pCurTextFrame
->GetTextNodeFirst() );
1331 m_aDelPam
.SetMark();
1333 m_aDelPam
.GetPoint()->Adjust(SwNodeOffset(-1));
1334 SwTextNode
* pTNd
= m_aDelPam
.GetPointNode().GetTextNode();
1337 // use the previous text node first
1338 m_aDelPam
.GetPoint()->SetContent(pTNd
->GetText().getLength());
1339 DeleteSel( m_aDelPam
);
1341 m_aDelPam
.DeleteMark();
1344 void SwAutoFormat::BuildIndent()
1346 SetRedlineText( STR_AUTOFMTREDL_SET_TMPL_INDENT
);
1348 // read all succeeding paragraphs that belong to this indentation
1351 DelMoreLinesBlanks( true );
1353 bBreak
= !IsFastFullLine(*m_pCurTextFrame
)
1354 || IsBlanksInString(*m_pCurTextFrame
)
1355 || IsSentenceAtEnd(*m_pCurTextFrame
);
1356 SetColl( RES_POOLCOLL_TEXT_IDENT
);
1359 SetRedlineText( STR_AUTOFMTREDL_DEL_MORELINES
);
1360 const SwTextFrame
* pNextFrame
= GetNextNode();
1361 if (pNextFrame
&& !m_bEnd
)
1364 bBreak
= !IsFastFullLine(*pNextFrame
)
1365 || IsBlanksInString(*pNextFrame
)
1366 || IsSentenceAtEnd(*pNextFrame
);
1367 if (DeleteJoinCurNextPara(pNextFrame
))
1369 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(' ') );
1373 pNextFrame
= GetNextNode();
1375 while (CanJoin(pNextFrame
)
1376 && !CalcLevel(*pNextFrame
));
1379 DeleteLeadingTrailingBlanks();
1383 void SwAutoFormat::BuildTextIndent()
1385 SetRedlineText( STR_AUTOFMTREDL_SET_TMPL_TEXT_INDENT
);
1386 // read all succeeding paragraphs that belong to this indentation
1389 DelMoreLinesBlanks( true );
1391 bBreak
= !IsFastFullLine(*m_pCurTextFrame
)
1392 || IsBlanksInString(*m_pCurTextFrame
)
1393 || IsSentenceAtEnd(*m_pCurTextFrame
);
1395 if( m_aFlags
.bAFormatByInput
)
1397 const_cast<SwTextNode
*>(m_pCurTextFrame
->GetTextNodeForParaProps())->SetAutoFormatLvl(
1398 static_cast<sal_uInt8
>(CalcLevel(*m_pCurTextFrame
)));
1401 SetColl( RES_POOLCOLL_TEXT_MOVE
);
1404 SetRedlineText( STR_AUTOFMTREDL_DEL_MORELINES
);
1405 const SwTextFrame
* pNextFrame
= GetNextNode();
1406 while (CanJoin(pNextFrame
) &&
1407 CalcLevel(*pNextFrame
))
1409 bBreak
= !IsFastFullLine(*pNextFrame
)
1410 || IsBlanksInString(*pNextFrame
)
1411 || IsSentenceAtEnd(*pNextFrame
);
1412 if (DeleteJoinCurNextPara(pNextFrame
))
1414 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(' ') );
1418 pNextFrame
= GetNextNode();
1421 DeleteLeadingTrailingBlanks();
1425 void SwAutoFormat::BuildText()
1427 SetRedlineText( STR_AUTOFMTREDL_SET_TMPL_TEXT
);
1428 // read all succeeding paragraphs that belong to this text without indentation
1431 DelMoreLinesBlanks();
1433 bBreak
= !IsFastFullLine(*m_pCurTextFrame
)
1434 || IsBlanksInString(*m_pCurTextFrame
)
1435 || IsSentenceAtEnd(*m_pCurTextFrame
);
1438 SetRedlineText( STR_AUTOFMTREDL_DEL_MORELINES
);
1439 const SwTextFrame
* pNextFrame
= GetNextNode();
1440 while (CanJoin(pNextFrame
) &&
1441 !CalcLevel(*pNextFrame
))
1443 bBreak
= !IsFastFullLine(*pNextFrame
)
1444 || IsBlanksInString(*pNextFrame
)
1445 || IsSentenceAtEnd(*pNextFrame
);
1446 if (DeleteJoinCurNextPara(pNextFrame
))
1448 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(' ') );
1452 const SwTextFrame
*const pCurrNode
= pNextFrame
;
1453 pNextFrame
= GetNextNode();
1454 if (!pNextFrame
|| pCurrNode
== pNextFrame
)
1458 DeleteLeadingTrailingBlanks();
1462 void SwAutoFormat::BuildEnum( sal_uInt16 nLvl
, sal_uInt16 nDigitLevel
)
1464 SetRedlineText( STR_AUTOFMTREDL_SET_NUMBER_BULLET
);
1468 // first, determine current indentation and frame width
1469 SwTwips nFrameWidth
= m_pCurTextFrame
->getFramePrintArea().Width();
1470 SwTwips nLeftTextPos
;
1472 TextFrameIndex
nPos(0);
1473 while (nPos
< TextFrameIndex(m_pCurTextFrame
->GetText().getLength())
1474 && IsSpace(m_pCurTextFrame
->GetText()[sal_Int32(nPos
)]))
1479 SwTextFrameInfo
aInfo( m_pCurTextFrame
);
1480 nLeftTextPos
= aInfo
.GetCharPos(nPos
);
1481 nLeftTextPos
-= m_pCurTextFrame
->GetTextNodeForParaProps()->GetSwAttrSet().GetTextLeftMargin().GetLeft(m_pCurTextFrame
->GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent());
1485 DelMoreLinesBlanks();
1487 bBreak
= !IsFastFullLine(*m_pCurTextFrame
)
1488 || IsBlanksInString(*m_pCurTextFrame
)
1489 || IsSentenceAtEnd(*m_pCurTextFrame
);
1490 bool bRTL
= m_pEditShell
->IsInRightToLeftText();
1491 DeleteLeadingTrailingBlanks();
1493 bool bChgBullet
= false, bChgEnum
= false;
1494 TextFrameIndex
nAutoCorrPos(0);
1496 // if numbering is set, get the current one
1497 SwNumRule
aRule( m_pDoc
->GetUniqueNumRuleName(),
1499 numfunc::GetDefaultPositionAndSpaceMode() );
1501 const SwNumRule
* pCur
= nullptr;
1502 if (m_aFlags
.bSetNumRule
)
1504 pCur
= m_pCurTextFrame
->GetTextNodeForParaProps()->GetNumRule();
1511 // replace bullet character with defined one
1512 const OUString
& rStr
= m_pCurTextFrame
->GetText();
1513 TextFrameIndex
nTextStt(0);
1514 const sal_Unicode
* pFndBulletChr
= nullptr;
1515 if (m_aFlags
.bChgEnumNum
&& 2 < rStr
.getLength())
1516 pFndBulletChr
= StrChr(pBulletChar
, rStr
[sal_Int32(nTextStt
)]);
1517 if (nullptr != pFndBulletChr
&& IsSpace(rStr
[sal_Int32(nTextStt
) + 1]))
1519 if( m_aFlags
.bAFormatByInput
)
1521 if( m_aFlags
.bSetNumRule
)
1523 SwCharFormat
* pCFormat
= m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
1524 RES_POOLCHR_BULLET_LEVEL
);
1526 // Was the format already somewhere adjusted?
1527 if( !aRule
.GetNumFormat( nLvl
) )
1529 int nBulletPos
= pFndBulletChr
- pBulletChar
;
1531 const vcl::Font
* pBullFnt( nullptr );
1532 if( nBulletPos
< cnPosEnDash
)
1534 cBullChar
= m_aFlags
.cBullet
;
1535 pBullFnt
= &m_aFlags
.aBulletFont
;
1539 cBullChar
= nBulletPos
< cnPosEmDash
1541 : cStarSymbolEmDash
;
1543 // Only apply user defined default bullet font
1544 if ( numfunc::IsDefBulletFontUserDefined() )
1546 pBullFnt
= &numfunc::GetDefBulletFont();
1550 sal_Int32 nAbsPos
= lBulletIndent
;
1551 SwTwips nSpaceSteps
= nLvl
1552 ? nLeftTextPos
/ nLvl
1554 for( sal_uInt8 n
= 0; n
< MAXLEVEL
; ++n
, nAbsPos
= nAbsPos
+ nSpaceSteps
)
1556 SwNumFormat
aFormat( aRule
.Get( n
) );
1557 aFormat
.SetBulletFont( pBullFnt
);
1558 aFormat
.SetBulletChar( cBullChar
);
1559 aFormat
.SetNumberingType(SVX_NUM_CHAR_SPECIAL
);
1560 // #i93908# clear suffix for bullet lists
1561 aFormat
.SetListFormat("", "", n
);
1562 aFormat
.SetFirstLineOffset( lBulletFirstLineOffset
);
1563 aFormat
.SetAbsLSpace( nAbsPos
);
1564 if( !aFormat
.GetCharFormat() )
1565 aFormat
.SetCharFormat( pCFormat
);
1567 aFormat
.SetNumAdjust( SvxAdjust::Right
);
1569 aRule
.Set( n
, aFormat
);
1572 nFrameWidth
< ( nSpaceSteps
* MAXLEVEL
) )
1573 nSpaceSteps
= ( nFrameWidth
- nLeftTextPos
) /
1574 ( MAXLEVEL
- nLvl
);
1582 SetColl( o3tl::narrowing
<sal_uInt16
>(RES_POOLCOLL_BULLET_LEVEL1
+ ( std::min( nLvl
, cnNumBullColls
) * 4 )) );
1587 // Then it is a numbering
1589 //JP 21.11.97: The NumLevel is either the DigitLevel or, if the latter is not existent or 0,
1590 // it is determined by the indentation level.
1592 OUString aPostfix
, aPrefix
, aNumTypes
;
1593 nDigitLevel
= GetDigitLevel(*m_pCurTextFrame
, nTextStt
,
1594 &aPrefix
, &aPostfix
, &aNumTypes
);
1595 if (USHRT_MAX
!= nDigitLevel
)
1599 // Level 0 and Indentation, determine level by left indentation and default NumIndent
1600 if( !nDigitLevel
&& nLeftTextPos
)
1601 nLvl
= std::min( sal_uInt16( nLeftTextPos
/ lNumberIndent
),
1602 sal_uInt16( MAXLEVEL
- 1 ) );
1607 if( bChgEnum
&& m_aFlags
.bSetNumRule
)
1609 if( !pCur
) // adjust NumRule if it is new
1611 SwCharFormat
* pCFormat
= m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
1612 RES_POOLCHR_NUM_LEVEL
);
1614 sal_Int32 nPrefixIdx
{ 0 };
1617 SwNumFormat
aFormat( aRule
.Get( nLvl
) );
1618 const OUString sPrefix
= aPrefix
.getToken(0, u
'\x0001', nPrefixIdx
);
1619 aFormat
.SetStart( o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(o3tl::getToken(aPrefix
, 0, u
'\x0001', nPrefixIdx
))));
1620 aFormat
.SetListFormat(sPrefix
, aPostfix
.getToken(0, u
'\x0001'), nLvl
);
1621 aFormat
.SetIncludeUpperLevels( 0 );
1623 if( !aFormat
.GetCharFormat() )
1624 aFormat
.SetCharFormat( pCFormat
);
1626 if( !aNumTypes
.isEmpty() )
1627 aFormat
.SetNumberingType(static_cast<SvxNumType
>(aNumTypes
[ 0 ] - '0'));
1630 aFormat
.SetNumAdjust( SvxAdjust::Right
);
1631 aRule
.Set( nLvl
, aFormat
);
1635 auto const nSpaceSteps
= nLvl
? nLeftTextPos
/ nLvl
: 0;
1637 sal_Int32 nPostfixIdx
{ 0 };
1638 for( n
= 0; n
<= nLvl
; ++n
)
1640 SwNumFormat
aFormat( aRule
.Get( n
) );
1642 const OUString sPrefix
= n
? "" : aPrefix
.getToken(0, u
'\x0001', nPrefixIdx
);
1643 aFormat
.SetStart( o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(o3tl::getToken(aPrefix
, 0, u
'\x0001', nPrefixIdx
)) ));
1644 aFormat
.SetListFormat(sPrefix
, aPostfix
.getToken(0, u
'\x0001', nPostfixIdx
), n
);
1645 aFormat
.SetIncludeUpperLevels( MAXLEVEL
);
1646 if( n
< aNumTypes
.getLength() )
1647 aFormat
.SetNumberingType(static_cast<SvxNumType
>(aNumTypes
[ n
] - '0'));
1649 aFormat
.SetAbsLSpace( nSpaceSteps
* n
1652 if( !aFormat
.GetCharFormat() )
1653 aFormat
.SetCharFormat( pCFormat
);
1655 aFormat
.SetNumAdjust( SvxAdjust::Right
);
1657 aRule
.Set( n
, aFormat
);
1660 // Does it fit completely into the frame?
1661 bool bDefStep
= nFrameWidth
< (nSpaceSteps
* MAXLEVEL
);
1662 for( ; n
< MAXLEVEL
; ++n
)
1664 SwNumFormat
aFormat( aRule
.Get( n
) );
1665 aFormat
.SetIncludeUpperLevels( MAXLEVEL
);
1667 aFormat
.SetAbsLSpace( nLeftTextPos
+
1668 SwNumRule::GetNumIndent(static_cast<sal_uInt8
>(n
-nLvl
)));
1670 aFormat
.SetAbsLSpace( nSpaceSteps
* n
1672 aRule
.Set( n
, aFormat
);
1677 else if( !m_aFlags
.bAFormatByInput
)
1678 SetColl( o3tl::narrowing
<sal_uInt16
>(RES_POOLCOLL_NUM_LEVEL1
+ ( std::min( nLvl
, cnNumBullColls
) * 4 ) ));
1683 if ( bChgEnum
|| bChgBullet
)
1685 m_aDelPam
.DeleteMark();
1686 m_aDelPam
.GetPoint()->Assign( *m_pCurTextFrame
->GetTextNodeForParaProps() );
1688 if( m_aFlags
.bSetNumRule
)
1690 if( m_aFlags
.bAFormatByInput
)
1692 m_aDelPam
.SetMark();
1693 SwTextFrame
const*const pNextFrame
= GetNextNode(false);
1695 m_aDelPam
.GetMark()->Assign( *pNextFrame
->GetTextNodeForParaProps() );
1696 m_aDelPam
.GetMarkNode().GetTextNode()->SetAttrListLevel( nLvl
);
1699 const_cast<SwTextNode
*>(m_pCurTextFrame
->GetTextNodeForParaProps())->SetAttrListLevel(nLvl
);
1702 m_pDoc
->SetNumRule(m_aDelPam
, aRule
, true, m_pEditShell
->GetLayout());
1703 m_aDelPam
.DeleteMark();
1705 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(TextFrameIndex(0));
1709 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(
1710 bChgEnum
? nTextStt
: TextFrameIndex(0));
1712 m_aDelPam
.SetMark();
1715 nTextStt
+= TextFrameIndex(2);
1717 while (nTextStt
< TextFrameIndex(rStr
.getLength()) && IsSpace(rStr
[sal_Int32(nTextStt
)]))
1720 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nTextStt
);
1721 DeleteSel( m_aDelPam
);
1723 if( !m_aFlags
.bSetNumRule
)
1725 OUString
sChgStr('\t');
1727 sChgStr
= OUString(&m_aFlags
.cBullet
, 1) + sChgStr
;
1728 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, sChgStr
);
1730 SfxItemSet
aSet( m_pDoc
->GetAttrPool(), aTextNodeSetRange
);
1731 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(TextFrameIndex(0));
1732 assert(&m_aDelPam
.GetPoint()->GetNode() == m_pCurTextFrame
->GetTextNodeForParaProps());
1735 m_aDelPam
.SetMark();
1736 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(TextFrameIndex(1));
1737 SetAllScriptItem( aSet
,
1738 SvxFontItem( m_aFlags
.aBulletFont
.GetFamilyType(),
1739 m_aFlags
.aBulletFont
.GetFamilyName(),
1740 m_aFlags
.aBulletFont
.GetStyleName(),
1741 m_aFlags
.aBulletFont
.GetPitch(),
1742 m_aFlags
.aBulletFont
.GetCharSet(),
1743 RES_CHRATR_FONT
) );
1744 m_pDoc
->SetFormatItemByAutoFormat( m_aDelPam
, aSet
);
1745 m_aDelPam
.DeleteMark();
1746 nAutoCorrPos
= TextFrameIndex(2);
1749 SvxTabStopItem
aTStops( RES_PARATR_TABSTOP
);
1750 aTStops
.Insert( SvxTabStop( 0 ) );
1751 aSet
.Put( aTStops
);
1752 assert(&m_aDelPam
.GetPoint()->GetNode() == m_pCurTextFrame
->GetTextNodeForParaProps());
1753 m_pDoc
->SetFormatItemByAutoFormat( m_aDelPam
, aSet
);
1759 AutoCorrect( nAutoCorrPos
); /* Offset due to Bullet + Tab */
1763 const SwTextFrame
* pNextFrame
= GetNextNode();
1764 while (CanJoin(pNextFrame
)
1765 && nLvl
== CalcLevel(*pNextFrame
))
1767 SetRedlineText( STR_AUTOFMTREDL_DEL_MORELINES
);
1768 bBreak
= !IsFastFullLine(*pNextFrame
)
1769 || IsBlanksInString(*pNextFrame
)
1770 || IsSentenceAtEnd(*pNextFrame
);
1771 if (DeleteJoinCurNextPara(pNextFrame
))
1773 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(' ') );
1777 const SwTextFrame
*const pCurrNode
= pNextFrame
;
1778 pNextFrame
= GetNextNode();
1779 if (!pNextFrame
|| pCurrNode
== pNextFrame
)
1782 DeleteLeadingTrailingBlanks( false );
1783 AutoCorrect( nAutoCorrPos
);
1786 void SwAutoFormat::BuildNegIndent( SwTwips nSpaces
)
1788 SetRedlineText( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT
);
1789 // Test of contraposition (n words, divided by spaces/tabs, with same indentation in 2nd line)
1791 // read all succeeding paragraphs that belong to this enumeration
1793 TextFrameIndex
nSpacePos(0);
1794 const sal_Int32 nTextPos
= GetBigIndent( nSpacePos
);
1796 DelMoreLinesBlanks( true );
1798 bBreak
= !IsFastFullLine(*m_pCurTextFrame
)
1799 || (!nTextPos
&& IsBlanksInString(*m_pCurTextFrame
))
1800 || IsSentenceAtEnd(*m_pCurTextFrame
);
1802 SetColl( o3tl::narrowing
<sal_uInt16
>( nTextPos
1803 ? RES_POOLCOLL_CONFRONTATION
1804 : RES_POOLCOLL_TEXT_NEGIDENT
) );
1808 const OUString
& rStr
= m_pCurTextFrame
->GetText();
1809 bool bInsTab
= true;
1811 if ('\t' == rStr
[sal_Int32(nSpacePos
) + 1]) // leave tab alone
1817 TextFrameIndex nSpaceStt
= nSpacePos
;
1818 while (nSpaceStt
&& IsSpace(rStr
[sal_Int32(--nSpaceStt
)]))
1822 if (bInsTab
&& '\t' == rStr
[sal_Int32(nSpaceStt
)]) // leave tab alone
1828 m_aDelPam
.DeleteMark();
1829 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nSpacePos
);
1831 // delete old Spaces, etc.
1832 if( nSpaceStt
< nSpacePos
)
1834 m_aDelPam
.SetMark();
1835 *m_aDelPam
.GetMark() = m_pCurTextFrame
->MapViewToModelPos(nSpaceStt
);
1836 DeleteSel( m_aDelPam
);
1839 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString('\t') );
1846 SetRedlineText( STR_AUTOFMTREDL_DEL_MORELINES
);
1847 SwTextFrameInfo
aFInfo( m_pCurTextFrame
);
1848 const SwTextFrame
* pNextFrame
= GetNextNode();
1849 while (CanJoin(pNextFrame
) &&
1850 20 < std::abs( static_cast<tools::Long
>(nSpaces
- aFInfo
.SetFrame(
1851 EnsureFormatted(*pNextFrame
)).GetLineStart()) )
1854 bBreak
= !IsFastFullLine(*pNextFrame
)
1855 || IsBlanksInString(*pNextFrame
)
1856 || IsSentenceAtEnd(*pNextFrame
);
1857 if (DeleteJoinCurNextPara(pNextFrame
))
1859 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(' ') );
1863 pNextFrame
= GetNextNode();
1866 DeleteLeadingTrailingBlanks();
1870 void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl
)
1872 if( m_aFlags
.bWithRedlining
)
1874 OUString
sText(SwViewShell::GetShellRes()->GetAutoFormatNameLst()[
1875 STR_AUTOFMTREDL_SET_TMPL_HEADLINE
] );
1876 sText
= sText
.replaceAll( "$(ARG1)", OUString::number( nLvl
+ 1 ) );
1877 m_pDoc
->GetDocumentRedlineManager().SetAutoFormatRedlineComment( &sText
);
1880 SetColl( o3tl::narrowing
<sal_uInt16
>(RES_POOLCOLL_HEADLINE1
+ nLvl
), true );
1881 if( m_aFlags
.bAFormatByInput
)
1883 SwTextFormatColl
& rNxtColl
= m_pCurTextFrame
->GetTextNodeForParaProps()->GetTextColl()->GetNextTextFormatColl();
1887 DeleteLeadingTrailingBlanks( true, false );
1888 const SwTextFrame
* pNextFrame
= GetNextNode(false);
1889 if (pNextFrame
->GetNext())
1891 (void)DeleteJoinCurNextPara(pNextFrame
, true);
1892 pNextFrame
= GetNextNode(false);
1894 m_aDelPam
.DeleteMark();
1895 m_aDelPam
.GetPoint()->Assign( *pNextFrame
->GetTextNodeForParaProps() );
1896 m_pDoc
->SetTextFormatColl( m_aDelPam
, &rNxtColl
);
1900 DeleteLeadingTrailingBlanks();
1905 /// Start autocorrection for the current TextNode
1906 void SwAutoFormat::AutoCorrect(TextFrameIndex nPos
)
1908 SvxAutoCorrect
* pATst
= SvxAutoCorrCfg::Get().GetAutoCorrect();
1909 ACFlags aSvxFlags
= pATst
->GetFlags( );
1910 bool bReplaceQuote( aSvxFlags
& ACFlags::ChgQuotes
);
1911 bool bReplaceSglQuote( aSvxFlags
& ACFlags::ChgSglQuotes
);
1913 if( m_aFlags
.bAFormatByInput
||
1914 (!m_aFlags
.bAutoCorrect
&& !bReplaceQuote
&& !bReplaceSglQuote
&&
1915 !m_aFlags
.bCapitalStartSentence
&& !m_aFlags
.bCapitalStartWord
&&
1916 !m_aFlags
.bChgOrdinalNumber
&& !m_aFlags
.bTransliterateRTL
&&
1917 !m_aFlags
.bChgToEnEmDash
&& !m_aFlags
.bSetINetAttr
&&
1918 !m_aFlags
.bChgWeightUnderl
&& !m_aFlags
.bAddNonBrkSpace
) )
1921 const OUString
* pText
= &m_pCurTextFrame
->GetText();
1922 if (TextFrameIndex(pText
->getLength()) <= nPos
)
1925 bool bGetLanguage
= m_aFlags
.bChgOrdinalNumber
|| m_aFlags
.bTransliterateRTL
||
1926 m_aFlags
.bChgToEnEmDash
|| m_aFlags
.bSetINetAttr
||
1927 m_aFlags
.bCapitalStartWord
|| m_aFlags
.bCapitalStartSentence
||
1928 m_aFlags
.bAddNonBrkSpace
;
1930 m_aDelPam
.DeleteMark();
1931 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(TextFrameIndex(0));
1933 SwAutoCorrDoc
aACorrDoc( *m_pEditShell
, m_aDelPam
);
1935 SwTextFrameInfo
aFInfo( nullptr );
1937 TextFrameIndex nSttPos
, nLastBlank
= nPos
;
1938 bool bFirst
= m_aFlags
.bCapitalStartSentence
, bFirstSent
= bFirst
;
1939 sal_Unicode cChar
= 0;
1940 bool bNbspRunNext
= false;
1942 CharClass
& rAppCC
= GetAppCharClass();
1945 while (nPos
< TextFrameIndex(pText
->getLength())
1946 && IsSpace(cChar
= (*pText
)[sal_Int32(nPos
)]))
1948 if (nPos
== TextFrameIndex(pText
->getLength()))
1951 if( ( ( bReplaceQuote
&& '\"' == cChar
) ||
1952 ( bReplaceSglQuote
&& '\'' == cChar
) ) &&
1953 (!nPos
|| ' ' == (*pText
)[sal_Int32(nPos
)-1]))
1956 // note: special case symbol fonts !!!
1957 if( !aFInfo
.GetFrame() )
1958 aFInfo
.SetFrame( GetFrame( *m_pCurTextNd
) );
1959 if( !aFInfo
.IsBullet( nPos
))
1961 SetRedlineText( STR_AUTOFMTREDL_TYPO
);
1962 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
1963 bool bSetHardBlank
= false;
1965 OUString
sReplace( pATst
->GetQuote( aACorrDoc
,
1966 sal_Int32(nPos
), cChar
, true ));
1968 m_aDelPam
.SetMark();
1969 m_aDelPam
.GetPoint()->SetContent( m_aDelPam
.GetMark()->GetContentIndex() + 1 );
1970 if( 2 == sReplace
.getLength() && ' ' == sReplace
[ 1 ])
1972 sReplace
= sReplace
.copy( 0, 1 );
1973 bSetHardBlank
= true;
1975 m_pDoc
->getIDocumentContentOperations().ReplaceRange( m_aDelPam
, sReplace
, false );
1977 if( m_aFlags
.bWithRedlining
)
1979 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
1980 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
1981 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
1982 pText
= &m_pCurTextFrame
->GetText();
1983 m_aDelPam
.SetMark();
1984 aFInfo
.SetFrame( nullptr );
1987 nPos
+= TextFrameIndex(sReplace
.getLength() - 1);
1988 m_aDelPam
.DeleteMark();
1991 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(CHAR_HARDBLANK
) );
1997 bool bCallACorr
= false;
1999 if (nPos
&& IsSpace((*pText
)[sal_Int32(nPos
) - 1]))
2001 for (nSttPos
= nPos
; !bBreak
&& nPos
< TextFrameIndex(pText
->getLength()); ++nPos
)
2003 cChar
= (*pText
)[sal_Int32(nPos
)];
2008 if( ( cChar
== '\"' && bReplaceQuote
) || ( cChar
== '\'' && bReplaceSglQuote
) )
2010 // consider Symbolfonts!
2011 if( !aFInfo
.GetFrame() )
2012 aFInfo
.SetFrame( GetFrame( *m_pCurTextNd
) );
2013 if( !aFInfo
.IsBullet( nPos
))
2015 SetRedlineText( STR_AUTOFMTREDL_TYPO
);
2016 bool bSetHardBlank
= false;
2017 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
2018 OUString
sReplace( pATst
->GetQuote( aACorrDoc
,
2019 sal_Int32(nPos
), cChar
, false) );
2021 if( 2 == sReplace
.getLength() && ' ' == sReplace
[ 0 ])
2023 sReplace
= sReplace
.copy( 1 );
2024 bSetHardBlank
= true;
2027 m_aDelPam
.SetMark();
2028 m_aDelPam
.GetPoint()->SetContent( m_aDelPam
.GetMark()->GetContentIndex() + 1 );
2029 m_pDoc
->getIDocumentContentOperations().ReplaceRange( m_aDelPam
, sReplace
, false );
2031 if( m_aFlags
.bWithRedlining
)
2033 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
2034 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
2035 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
2036 pText
= &m_pCurTextFrame
->GetText();
2037 m_aDelPam
.SetMark();
2038 m_aDelPam
.DeleteMark();
2039 aFInfo
.SetFrame( nullptr );
2042 nPos
+= TextFrameIndex(sReplace
.getLength() - 1);
2043 m_aDelPam
.DeleteMark();
2047 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
2048 m_pDoc
->getIDocumentContentOperations().InsertString( m_aDelPam
, OUString(CHAR_HARDBLANK
) );
2050 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
2057 if( m_aFlags
.bChgWeightUnderl
)
2059 // consider Symbolfonts!
2060 if( !aFInfo
.GetFrame() )
2061 aFInfo
.SetFrame( GetFrame( *m_pCurTextNd
) );
2062 if( !aFInfo
.IsBullet( nPos
))
2064 SetRedlineText( '*' == cChar
2065 ? STR_AUTOFMTREDL_BOLD
2066 : STR_AUTOFMTREDL_UNDER
);
2068 sal_Unicode cBlank
= nSttPos
? (*pText
)[sal_Int32(nSttPos
) - 1] : 0;
2069 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
2071 if (pATst
->FnChgWeightUnderl(aACorrDoc
, *pText
, sal_Int32(nPos
)))
2073 if( m_aFlags
.bWithRedlining
)
2075 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
2076 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
2077 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
2078 pText
= &m_pCurTextFrame
->GetText();
2079 m_aDelPam
.SetMark();
2080 m_aDelPam
.DeleteMark();
2081 aFInfo
.SetFrame( nullptr );
2083 //#125102# in case of the mode RedlineFlags::ShowDelete the ** are still contained in pText
2084 if(!(m_pDoc
->getIDocumentRedlineAccess().GetRedlineFlags() & RedlineFlags::ShowDelete
))
2085 nPos
= m_pCurTextFrame
->MapModelToViewPos(*m_aDelPam
.GetPoint()) - TextFrameIndex(1);
2086 // Was a character deleted before starting?
2087 if (cBlank
&& cBlank
!= (*pText
)[sal_Int32(nSttPos
) - 1])
2094 if ( m_aFlags
.bAddNonBrkSpace
)
2096 LanguageType eLang
= bGetLanguage
2097 ? m_pCurTextFrame
->GetLangOfChar(nSttPos
, 0, true)
2100 SetRedlineText( STR_AUTOFMTREDL_NON_BREAK_SPACE
);
2101 if (pATst
->FnAddNonBrkSpace(aACorrDoc
, *pText
, sal_Int32(nPos
), eLang
, bNbspRunNext
))
2109 if( m_aFlags
.bCapitalStartSentence
)
2113 if (!(rAppCC
.isBase(*pText
, sal_Int32(nPos
))
2114 || '/' == cChar
)) // '/' should not be a word separator (e.g. '1/2' needs to be handled as one word for replacement)
2116 --nPos
; // revert ++nPos which was decremented in for loop
2123 if( nPos
== nSttPos
)
2125 if (++nPos
== TextFrameIndex(pText
->getLength()))
2133 *m_aDelPam
.GetPoint() = m_pCurTextFrame
->MapViewToModelPos(nPos
);
2134 SetRedlineText( STR_AUTOFMTREDL_USE_REPLACE
);
2136 LanguageType eLang
= bGetLanguage
2137 ? m_pCurTextFrame
->GetLangOfChar(nSttPos
, 0, true)
2140 if( m_bIsRightToLeft
&& m_aFlags
.bTransliterateRTL
&& eLang
== LANGUAGE_HUNGARIAN
&&
2141 SetRedlineText( STR_AUTOFMTREDL_TRANSLITERATE_RTL
) &&
2142 aACorrDoc
.TransliterateRTLWord(reinterpret_cast<sal_Int32
&>(nSttPos
), sal_Int32(nPos
), /*bApply=*/true))
2144 nPos
= m_pCurTextFrame
->MapModelToViewPos(*m_aDelPam
.GetPoint());
2146 if( m_aFlags
.bWithRedlining
)
2148 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
2149 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
2150 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
2151 pText
= &m_pCurTextFrame
->GetText();
2152 m_aDelPam
.SetMark();
2153 m_aDelPam
.DeleteMark();
2156 continue; // do not check further
2159 if( m_aFlags
.bAutoCorrect
&&
2160 aACorrDoc
.ChgAutoCorrWord(reinterpret_cast<sal_Int32
&>(nSttPos
), sal_Int32(nPos
), *pATst
, nullptr) )
2162 nPos
= m_pCurTextFrame
->MapModelToViewPos(*m_aDelPam
.GetPoint());
2163 if( m_aFlags
.bWithRedlining
)
2165 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
2166 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
2167 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
2168 pText
= &m_pCurTextFrame
->GetText();
2169 m_aDelPam
.SetMark();
2170 m_aDelPam
.DeleteMark();
2173 continue; // do not check further
2176 if ( m_aFlags
.bAddNonBrkSpace
&& nPos
< TextFrameIndex(pText
->getLength()) )
2178 SetRedlineText( STR_AUTOFMTREDL_NON_BREAK_SPACE
);
2179 pATst
->FnAddNonBrkSpace(aACorrDoc
, *pText
, sal_Int32(nPos
), eLang
, bNbspRunNext
);
2182 if( ( m_aFlags
.bChgOrdinalNumber
&&
2183 SetRedlineText( STR_AUTOFMTREDL_ORDINAL
) &&
2184 pATst
->FnChgOrdinalNumber(aACorrDoc
, *pText
, sal_Int32(nSttPos
), sal_Int32(nPos
), eLang
)) ||
2185 ( m_aFlags
.bChgToEnEmDash
&&
2186 SetRedlineText( STR_AUTOFMTREDL_DASH
) &&
2187 pATst
->FnChgToEnEmDash(aACorrDoc
, *pText
, sal_Int32(nSttPos
), sal_Int32(nPos
), eLang
)) ||
2188 ( m_aFlags
.bSetINetAttr
&&
2189 (nPos
== TextFrameIndex(pText
->getLength()) || IsSpace((*pText
)[sal_Int32(nPos
)])) &&
2190 SetRedlineText( STR_AUTOFMTREDL_DETECT_URL
) &&
2191 pATst
->FnSetINetAttr(aACorrDoc
, *pText
, sal_Int32(nLastBlank
), sal_Int32(nPos
), eLang
)) ||
2192 ( m_aFlags
.bSetDOIAttr
&&
2193 (nPos
== TextFrameIndex(pText
->getLength()) || IsSpace((*pText
)[sal_Int32(nPos
)])) &&
2194 SetRedlineText( STR_AUTOFMTREDL_DETECT_DOI
) &&
2195 pATst
->FnSetDOIAttr(aACorrDoc
, *pText
, sal_Int32(nLastBlank
), sal_Int32(nPos
), eLang
)))
2197 nPos
= m_pCurTextFrame
->MapModelToViewPos(*m_aDelPam
.GetPoint());
2201 // two capital letters at the beginning of a word?
2202 if( m_aFlags
.bCapitalStartWord
)
2204 SetRedlineText( STR_AUTOFMTREDL_CPTL_STT_WORD
);
2205 pATst
->FnCapitalStartWord(aACorrDoc
, *pText
, sal_Int32(nSttPos
), sal_Int32(nPos
), eLang
);
2207 // capital letter at the beginning of a sentence?
2208 if( m_aFlags
.bCapitalStartSentence
&& bFirst
)
2210 SetRedlineText( STR_AUTOFMTREDL_CPTL_STT_SENT
);
2211 pATst
->FnCapitalStartSentence(aACorrDoc
, *pText
, true, sal_Int32(nSttPos
), sal_Int32(nPos
), eLang
);
2214 bFirst
= bFirstSent
;
2217 if( m_aFlags
.bWithRedlining
)
2219 m_aNdIdx
= m_aDelPam
.GetPoint()->GetNode();
2220 m_pCurTextNd
= m_aNdIdx
.GetNode().GetTextNode();
2221 m_pCurTextFrame
= GetFrame( *m_pCurTextNd
);
2222 pText
= &m_pCurTextFrame
->GetText();
2223 m_aDelPam
.SetMark();
2224 m_aDelPam
.DeleteMark();
2229 while (nPos
< TextFrameIndex(pText
->getLength()));
2233 SwAutoFormat::SwAutoFormat( SwEditShell
* pEdShell
, SvxSwAutoFormatFlags aFlags
,
2234 SwNode
const * pSttNd
, SwNode
const * pEndNd
)
2235 : m_aFlags(std::move( aFlags
)),
2236 m_aDelPam( pEdShell
->GetDoc()->GetNodes().GetEndOfExtras() ),
2237 m_aNdIdx( pEdShell
->GetDoc()->GetNodes().GetEndOfExtras(), SwNodeOffset(+1) ),
2238 m_aEndNdIdx( pEdShell
->GetDoc()->GetNodes().GetEndOfContent() ),
2239 m_pEditShell( pEdShell
),
2240 m_pDoc( pEdShell
->GetDoc() ),
2241 m_pCurTextNd( nullptr ), m_pCurTextFrame( nullptr ),
2242 m_nRedlAutoFormatSeqId( 0 )
2244 OSL_ENSURE( (pSttNd
&& pEndNd
) || (!pSttNd
&& !pEndNd
),
2247 if( m_aFlags
.bSetNumRule
&& !m_aFlags
.bAFormatByInput
)
2248 m_aFlags
.bSetNumRule
= false;
2250 bool bReplaceStyles
= !m_aFlags
.bAFormatByInput
|| m_aFlags
.bReplaceStyles
;
2252 const SwTextFrame
* pNextFrame
= nullptr;
2253 bool bNxtEmpty
= false;
2254 bool bNxtAlpha
= false;
2255 sal_uInt16 nNxtLevel
= 0;
2258 // set area for autoformatting
2262 // for GoNextPara, one paragraph prior to that
2263 sw::GotoPrevLayoutTextFrame(m_aNdIdx
, m_pEditShell
->GetLayout());
2264 m_aEndNdIdx
= *pEndNd
;
2265 sw::GotoNextLayoutTextFrame(m_aEndNdIdx
, m_pEditShell
->GetLayout());
2267 // check the previous TextNode
2268 SwTextFrame
const*const pPrevFrame
= m_aNdIdx
.GetNode().GetTextNode()
2269 ? static_cast<SwTextFrame
const*>(m_aNdIdx
.GetNode().GetTextNode()->getLayoutFrame(m_pEditShell
->GetLayout()))
2271 bEmptyLine
= !pPrevFrame
2272 || IsEmptyLine(*pPrevFrame
)
2273 || IsNoAlphaLine(*pPrevFrame
);
2276 bEmptyLine
= true; // at document beginning
2280 // set value for percentage display
2281 m_nEndNdIdx
= m_aEndNdIdx
.GetIndex();
2283 if( !m_aFlags
.bAFormatByInput
)
2285 m_nEndNdIdx
= m_aEndNdIdx
.GetIndex();
2286 ::StartProgress( STR_STATSTR_AUTOFORMAT
, sal_Int32(m_aNdIdx
.GetIndex()),
2287 sal_Int32(m_nEndNdIdx
),
2288 m_pDoc
->GetDocShell() );
2291 RedlineFlags eRedlMode
= m_pDoc
->getIDocumentRedlineAccess().GetRedlineFlags(), eOldMode
= eRedlMode
;
2292 if( m_aFlags
.bWithRedlining
)
2294 m_pDoc
->SetAutoFormatRedline( true );
2295 eRedlMode
= RedlineFlags::On
| (eOldMode
& RedlineFlags::ShowMask
);
2298 eRedlMode
= RedlineFlags::Ignore
| (eOldMode
& RedlineFlags::ShowMask
);
2299 m_pDoc
->getIDocumentRedlineAccess().SetRedlineFlags( eRedlMode
);
2301 // save undo state (might be turned off)
2302 bool const bUndoState
= m_pDoc
->GetIDocumentUndoRedo().DoesUndo();
2304 // If multiple lines, then do not merge with next paragraph
2305 m_bMoreLines
= false;
2307 sal_uInt16 nLastCalcHeadLvl
= 0;
2308 sal_uInt16 nLastHeadLvl
= USHRT_MAX
;
2309 sal_uInt16 nLevel
= 0;
2310 sal_uInt16 nDigitLvl
= 0;
2313 SwTextFrameInfo
aFInfo( nullptr );
2317 READ_NEXT_PARA
, // -> ISEND, TST_EMPTY_LINE
2318 TST_EMPTY_LINE
, // -> READ_NEXT_PARA, TST_ALPHA_LINE
2319 TST_ALPHA_LINE
, // -> READ_NEXT_PARA, GET_ALL_INFO, IS_END
2320 GET_ALL_INFO
, // -> READ_NEXT_PARA, IS_ONE_LINE, TST_ENUMERIC, HAS_FMTCOLL
2321 IS_ONE_LINE
, // -> READ_NEXT_PARA, TST_ENUMERIC
2322 TST_ENUMERIC
, // -> READ_NEXT_PARA, TST_IDENT, TST_NEG_IDENT
2323 TST_IDENT
, // -> READ_NEXT_PARA, TST_TXT_BODY
2324 TST_NEG_IDENT
, // -> READ_NEXT_PARA, TST_TXT_BODY
2325 TST_TXT_BODY
, // -> READ_NEXT_PARA
2326 HAS_FMTCOLL
, // -> READ_NEXT_PARA
2330 // This is the automat for autoformatting
2331 eStat
= READ_NEXT_PARA
;
2336 case READ_NEXT_PARA
:
2339 eStat
= m_bEnd
? IS_END
: TST_EMPTY_LINE
;
2343 case TST_EMPTY_LINE
:
2344 if (IsEmptyLine(*m_pCurTextFrame
))
2346 if (m_aFlags
.bDelEmptyNode
&& !HasObjects(*m_pCurTextFrame
))
2349 SwNodeOffset nOldCnt
= m_pDoc
->GetNodes().Count();
2351 // Was there really a deletion of a node?
2352 if( nOldCnt
!= m_pDoc
->GetNodes().Count() )
2354 // do not skip the next paragraph
2355 sw::GotoPrevLayoutTextFrame(m_aNdIdx
, m_pEditShell
->GetLayout());
2358 eStat
= READ_NEXT_PARA
;
2361 eStat
= TST_ALPHA_LINE
;
2364 case TST_ALPHA_LINE
:
2365 if (IsNoAlphaLine(*m_pCurTextFrame
))
2367 // recognize a table definition +---+---+
2368 if( m_aFlags
.bAFormatByInput
&& m_aFlags
.bCreateTable
&& DoTable() )
2370 //JP 30.09.96: DoTable() builds on PopCursor and MoveCursor after AutoFormat!
2371 pEdShell
->Pop(SwCursorShell::PopMode::DeleteCurrent
);
2372 static_cast<SwPaM
&>(*pEdShell
->GetCursor()) = m_aDelPam
;
2379 // Check for 3 "---" or "===". In this case, the previous paragraph should be
2380 // underlined and the current be deleted!
2381 if( !DoUnderline() && bReplaceStyles
)
2383 SetColl( RES_POOLCOLL_STANDARD
, true );
2386 eStat
= READ_NEXT_PARA
;
2389 eStat
= GET_ALL_INFO
;
2394 if (m_pCurTextFrame
->GetTextNodeForParaProps()->GetNumRule())
2396 // do nothing in numbering, go to next
2398 eStat
= READ_NEXT_PARA
;
2399 // delete all blanks at beginning/end and in between
2400 //JP 29.04.98: first only "all in between"
2401 DelMoreLinesBlanks();
2402 // auto correct paragraphs that fail to enter state HAS_FMTCOLL
2407 aFInfo
.SetFrame( m_pCurTextFrame
);
2409 // so far: if there were templates assigned, keep these and go to next node
2410 sal_uInt16 nPoolId
= m_pCurTextFrame
->GetTextNodeForParaProps()->GetTextColl()->GetPoolFormatId();
2411 if( IsPoolUserFormat( nPoolId
)
2412 ? !m_aFlags
.bChgUserColl
2413 : ( RES_POOLCOLL_STANDARD
!= nPoolId
&&
2414 ( !m_aFlags
.bAFormatByInput
||
2415 (RES_POOLCOLL_TEXT_MOVE
!= nPoolId
&&
2416 RES_POOLCOLL_TEXT
!= nPoolId
)) ))
2418 eStat
= HAS_FMTCOLL
;
2422 // replace custom styles with text body
2423 if ( IsPoolUserFormat( nPoolId
) && m_aFlags
.bChgUserColl
)
2425 SetColl( RES_POOLCOLL_TEXT
, true );
2428 // check for left margin set by the style
2429 if( IsPoolUserFormat( nPoolId
) ||
2430 RES_POOLCOLL_STANDARD
== nPoolId
)
2432 SvxFirstLineIndentItem
const*const pFirstLineIndent(
2433 m_pCurTextFrame
->GetTextNodeForParaProps()
2434 ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_FIRSTLINE
));
2435 SvxTextLeftMarginItem
const*const pTextLeftMargin(
2436 m_pCurTextFrame
->GetTextNodeForParaProps()
2437 ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_TEXTLEFT
));
2438 short nSz(pFirstLineIndent
? pFirstLineIndent
->GetTextFirstLineOffset() : 0);
2440 (pTextLeftMargin
&& 0 != pTextLeftMargin
->GetTextLeft()))
2442 // exception: numbering/enumeration can have an indentation
2443 if (IsEnumericChar(*m_pCurTextFrame
))
2445 nLevel
= CalcLevel(*m_pCurTextFrame
, &nDigitLvl
);
2446 if( nLevel
>= MAXLEVEL
)
2447 nLevel
= MAXLEVEL
-1;
2448 BuildEnum( nLevel
, nDigitLvl
);
2449 eStat
= READ_NEXT_PARA
;
2453 // never merge (maybe only indent as exception)
2454 m_bMoreLines
= true;
2456 if( bReplaceStyles
)
2458 // then use one of our templates
2459 if( 0 < nSz
) // positive 1st line indentation
2461 else if( 0 > nSz
) // negative 1st line indentation
2462 BuildNegIndent( aFInfo
.GetLineStart() );
2463 else if (pTextLeftMargin
&& pTextLeftMargin
->GetTextLeft() != 0) // is indentation
2466 eStat
= READ_NEXT_PARA
;
2471 nLevel
= CalcLevel( *m_pCurTextFrame
, &nDigitLvl
);
2472 m_bMoreLines
= !IsOneLine(*m_pCurTextFrame
);
2473 // note: every use of pNextFrame in following states, until the
2474 // next READ_NEXT_PARA, relies on this update
2475 pNextFrame
= GetNextNode();
2478 bNxtEmpty
= IsEmptyLine(*pNextFrame
);
2479 bNxtAlpha
= IsNoAlphaLine(*pNextFrame
);
2480 nNxtLevel
= CalcLevel(*pNextFrame
);
2482 if (!bEmptyLine
&& HasBreakAttr(*m_pCurTextFrame
))
2484 if (!bNxtEmpty
&& HasBreakAttr(*pNextFrame
))
2494 eStat
= !m_bMoreLines
? IS_ONE_LINE
: TST_ENUMERIC
;
2500 eStat
= TST_ENUMERIC
;
2501 if( !bReplaceStyles
)
2504 const OUString
sClrStr( DelLeadingBlanks(m_pCurTextFrame
->GetText()) );
2506 if( sClrStr
.isEmpty() )
2509 eStat
= READ_NEXT_PARA
;
2510 break; // read next paragraph
2513 // check if headline
2514 if (!bEmptyLine
|| !IsFirstCharCapital(*m_pCurTextFrame
)
2515 || IsBlanksInString(*m_pCurTextFrame
))
2519 const OUString
sEndClrStr( DelTrailingBlanks(sClrStr
) );
2520 const sal_Unicode cLast
= sEndClrStr
[sEndClrStr
.getLength() - 1];
2522 // not, then check if headline
2526 eStat
= READ_NEXT_PARA
;
2529 else if( 256 <= cLast
|| !strchr( ",.;", cLast
) )
2531 if( bNxtEmpty
|| bNxtAlpha
2532 || (pNextFrame
&& IsEnumericChar(*pNextFrame
)))
2536 if( nLevel
>= MAXLEVEL
)
2537 nLevel
= MAXLEVEL
-1;
2539 if( USHRT_MAX
== nLastHeadLvl
)
2541 else if( nLastCalcHeadLvl
< nLevel
)
2543 if( nLastHeadLvl
+1 < MAXLEVEL
)
2547 else if( nLastCalcHeadLvl
> nLevel
)
2552 nLastCalcHeadLvl
= nLevel
;
2554 if( m_aFlags
.bAFormatByInput
)
2555 BuildHeadLine( nLevel
);
2557 BuildHeadLine( nLastHeadLvl
);
2558 eStat
= READ_NEXT_PARA
;
2568 if (IsEnumericChar(*m_pCurTextFrame
))
2570 if( nLevel
>= MAXLEVEL
)
2571 nLevel
= MAXLEVEL
-1;
2572 BuildEnum( nLevel
, nDigitLvl
);
2573 eStat
= READ_NEXT_PARA
;
2575 else if( bReplaceStyles
)
2576 eStat
= nLevel
? TST_IDENT
: TST_NEG_IDENT
;
2578 eStat
= READ_NEXT_PARA
;
2583 // Spaces at the beginning, check again for indentation
2584 if( m_bMoreLines
&& nLevel
)
2586 SwTwips nSz
= aFInfo
.GetFirstIndent();
2587 if( 0 < nSz
) // positive 1st line indentation
2589 else if( 0 > nSz
) // negative 1st line indentation
2590 BuildNegIndent( aFInfo
.GetLineStart() );
2591 else // is indentation
2593 eStat
= READ_NEXT_PARA
;
2595 else if (nLevel
&& pNextFrame
&&
2596 !bNxtEmpty
&& !bNxtAlpha
&& !nNxtLevel
&&
2597 !IsEnumericChar(*pNextFrame
))
2599 // is an indentation
2601 eStat
= READ_NEXT_PARA
;
2604 eStat
= TST_TXT_BODY
;
2608 // no spaces at the beginning, check again for negative indentation
2610 if( m_bMoreLines
&& !nLevel
)
2612 SwTwips nSz
= aFInfo
.GetFirstIndent();
2613 if( 0 < nSz
) // positive 1st line indentation
2615 else if( 0 > nSz
) // negative 1st line indentation
2616 BuildNegIndent( aFInfo
.GetLineStart() );
2617 else // is _no_ indentation
2619 eStat
= READ_NEXT_PARA
;
2621 else if (!nLevel
&& pNextFrame
&&
2622 !bNxtEmpty
&& !bNxtAlpha
&& nNxtLevel
&&
2623 !IsEnumericChar(*pNextFrame
))
2625 // is a negative indentation
2626 BuildNegIndent( aFInfo
.GetLineStart() );
2627 eStat
= READ_NEXT_PARA
;
2630 eStat
= TST_TXT_BODY
;
2638 SwTwips nSz
= aFInfo
.GetFirstIndent();
2639 if( 0 < nSz
) // positive 1st line indentation
2641 else if( 0 > nSz
) // negative 1st line indentation
2642 BuildNegIndent( aFInfo
.GetLineStart() );
2643 else if( nLevel
) // is indentation
2652 eStat
= READ_NEXT_PARA
;
2658 // so far: if there were templates assigned, keep these and go to next node
2660 eStat
= READ_NEXT_PARA
;
2661 // delete all blanks at beginning/end and in between
2662 //JP 29.04.98: first only "all in between"
2663 DelMoreLinesBlanks();
2665 // handle hard attributes
2666 if (m_pCurTextFrame
->GetTextNodeForParaProps()->HasSwAttrSet())
2668 SvxFirstLineIndentItem
const*const pFirstLineIndent(
2669 m_pCurTextFrame
->GetTextNodeForParaProps()
2670 ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_FIRSTLINE
, false));
2671 SvxTextLeftMarginItem
const*const pTextLeftMargin(
2672 m_pCurTextFrame
->GetTextNodeForParaProps()
2673 ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_TEXTLEFT
, false));
2674 short nSz(pFirstLineIndent
? pFirstLineIndent
->GetTextFirstLineOffset() : 0);
2675 if( bReplaceStyles
&&
2677 (pTextLeftMargin
&& 0 != pTextLeftMargin
->GetTextLeft())))
2679 // then use one of our templates
2680 if( 0 < nSz
) // positive 1st line indentation
2682 else if( 0 > nSz
) // negative 1st line indentation
2684 BuildNegIndent( aFInfo
.GetLineStart() );
2686 else if (pTextLeftMargin
&& pTextLeftMargin
->GetTextLeft()) // is indentation
2692 // force auto correct
2703 if( m_aFlags
.bWithRedlining
)
2704 m_pDoc
->SetAutoFormatRedline( false );
2705 m_pDoc
->getIDocumentRedlineAccess().SetRedlineFlags( eOldMode
);
2707 // restore undo (in case it has been changed)
2708 m_pDoc
->GetIDocumentUndoRedo().DoUndo(bUndoState
);
2710 // disable display of percentage again
2711 if( !m_aFlags
.bAFormatByInput
)
2712 ::EndProgress( m_pDoc
->GetDocShell() );
2715 void SwEditShell::AutoFormat( const SvxSwAutoFormatFlags
* pAFlags
)
2717 std::optional
<SwWait
> oWait
;
2719 CurrShell
aCurr( this );
2721 StartUndo( SwUndoId::AUTOFORMAT
);
2723 SvxSwAutoFormatFlags aAFFlags
; // use default values or add params?
2726 aAFFlags
= *pAFlags
;
2727 if( !aAFFlags
.bAFormatByInput
)
2728 oWait
.emplace( *GetDoc()->GetDocShell(), true );
2731 SwPaM
* pCursor
= GetCursor();
2732 // There are more than one or a selection is open
2733 if( pCursor
->GetNext() != pCursor
|| pCursor
->HasMark() )
2735 for(SwPaM
& rPaM
: GetCursor()->GetRingContainer())
2737 if( rPaM
.HasMark() )
2739 SwAutoFormat
aFormat( this, aAFFlags
, &rPaM
.Start()->GetNode(),
2740 &rPaM
.End()->GetNode() );
2746 SwAutoFormat
aFormat( this, std::move(aAFFlags
) );
2749 EndUndo( SwUndoId::AUTOFORMAT
);
2753 void SwEditShell::AutoFormatBySplitNode()
2755 CurrShell
aCurr( this );
2756 SwPaM
* pCursor
= GetCursor();
2757 if( pCursor
->IsMultiSelection() || !pCursor
->Move( fnMoveBackward
, GoInNode
) )
2761 StartUndo( SwUndoId::AUTOFORMAT
);
2763 bool bRange
= false;
2765 SwPosition
* pMarkPos
= pCursor
->GetMark();
2766 if( pMarkPos
->GetContentIndex() )
2768 pMarkPos
->SetContent(0);
2773 // then go one node backwards
2774 SwNodeIndex
aNdIdx(pCursor
->GetMark()->GetNode());
2775 sw::GotoPrevLayoutTextFrame(aNdIdx
, GetLayout());
2776 SwTextNode
* pTextNd
= aNdIdx
.GetNode().GetTextNode();
2777 if (pTextNd
&& !pTextNd
->GetText().isEmpty())
2779 pCursor
->GetMark()->Assign( aNdIdx
);
2786 Push(); // save cursor
2788 SvxSwAutoFormatFlags aAFFlags
= *GetAutoFormatFlags(); // use default values so far
2790 SwAutoFormat
aFormat( this, std::move(aAFFlags
), &pCursor
->GetMark()->GetNode(),
2791 &pCursor
->GetPoint()->GetNode() );
2792 SvxAutoCorrect
* pACorr
= SvxAutoCorrCfg::Get().GetAutoCorrect();
2793 if( pACorr
&& !pACorr
->IsAutoCorrFlag( ACFlags::CapitalStartSentence
| ACFlags::CapitalStartWord
|
2794 ACFlags::AddNonBrkSpace
| ACFlags::ChgOrdinalNumber
| ACFlags::TransliterateRTL
|
2795 ACFlags::ChgToEnEmDash
| ACFlags::SetINetAttr
| ACFlags::Autocorrect
|
2796 ACFlags::SetDOIAttr
))
2800 AutoCorrect( *pACorr
,false, u
'\0' );
2802 //JP 30.09.96: DoTable() builds on PopCursor and MoveCursor!
2803 Pop(PopMode::DeleteCurrent
);
2804 pCursor
= GetCursor();
2806 pCursor
->DeleteMark();
2807 pCursor
->Move( fnMoveForward
, GoInNode
);
2809 EndUndo( SwUndoId::AUTOFORMAT
);
2814 SvxSwAutoFormatFlags
* SwEditShell::GetAutoFormatFlags()
2816 if (!s_pAutoFormatFlags
)
2817 s_pAutoFormatFlags
= new SvxSwAutoFormatFlags
;
2819 return s_pAutoFormatFlags
;
2822 void SwEditShell::SetAutoFormatFlags(SvxSwAutoFormatFlags
const * pFlags
)
2824 SvxSwAutoFormatFlags
* pEditFlags
= GetAutoFormatFlags();
2826 pEditFlags
->bSetNumRule
= pFlags
->bSetNumRule
;
2827 pEditFlags
->bChgEnumNum
= pFlags
->bChgEnumNum
;
2828 pEditFlags
->bSetBorder
= pFlags
->bSetBorder
;
2829 pEditFlags
->bCreateTable
= pFlags
->bCreateTable
;
2830 pEditFlags
->bReplaceStyles
= pFlags
->bReplaceStyles
;
2831 pEditFlags
->bAFormatByInpDelSpacesAtSttEnd
=
2832 pFlags
->bAFormatByInpDelSpacesAtSttEnd
;
2833 pEditFlags
->bAFormatByInpDelSpacesBetweenLines
=
2834 pFlags
->bAFormatByInpDelSpacesBetweenLines
;
2836 //JP 15.12.98: copy BulletChar and Font into "normal" ones
2837 // because AutoFormat can only work with the latter!
2838 pEditFlags
->cBullet
= pFlags
->cByInputBullet
;
2839 pEditFlags
->aBulletFont
= pFlags
->aByInputBulletFont
;
2840 pEditFlags
->cByInputBullet
= pFlags
->cByInputBullet
;
2841 pEditFlags
->aByInputBulletFont
= pFlags
->aByInputBulletFont
;
2844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */