Update git submodules
[LibreOffice.git] / sw / source / core / edit / edattr.cxx
blob624a2e663ddb671a44d9a5e956050ed8c7b4cecb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <memory>
21 #include <hintids.hxx>
22 #include <editeng/tstpitem.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <com/sun/star/i18n/ScriptType.hpp>
25 #include <com/sun/star/i18n/XBreakIterator.hpp>
26 #include <osl/diagnose.h>
27 #include <txatbase.hxx>
28 #include <txtftn.hxx>
29 #include <fmtftn.hxx>
30 #include <editsh.hxx>
31 #include <edimp.hxx>
32 #include <doc.hxx>
33 #include <swundo.hxx>
34 #include <ndtxt.hxx>
35 #include <ftnidx.hxx>
36 #include <expfld.hxx>
37 #include <rootfrm.hxx>
38 #include <cntfrm.hxx>
39 #include <breakit.hxx>
40 #include <fmtfld.hxx>
41 #include <txtfrm.hxx>
42 #include <scriptinfo.hxx>
43 #include <svl/itemiter.hxx>
44 #include <svl/languageoptions.hxx>
45 #include <charfmt.hxx>
46 #include <numrule.hxx>
49 * hard Formatting (Attributes)
52 // if selection is bigger as max nodes or more than max selections
53 // => no attributes
54 static sal_uInt16 getMaxLookup()
56 return 10000;
59 bool SwEditShell::GetPaMAttr( SwPaM* pPaM, SfxItemSet& rSet,
60 const bool bMergeIndentValuesOfNumRule ) const
62 // ??? pPaM can be different from the Cursor ???
63 if( GetCursorCnt() > getMaxLookup() )
65 rSet.ClearItem();
66 return false;
69 SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
70 SfxItemSet *pSet = &rSet;
72 for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
74 // #i27615# if the cursor is in front of the numbering label
75 // the attributes to get are those from the numbering format.
76 if (rCurrentPaM.IsInFrontOfLabel())
78 SwTextNode const*const pTextNd = sw::GetParaPropsNode(*GetLayout(),
79 rCurrentPaM.GetPoint()->GetNode());
81 if (pTextNd)
83 SwNumRule * pNumRule = pTextNd->GetNumRule();
85 if (pNumRule)
87 int nListLevel = pTextNd->GetActualListLevel();
89 if (nListLevel < 0)
90 nListLevel = 0;
92 if (nListLevel >= MAXLEVEL)
93 nListLevel = MAXLEVEL - 1;
95 const OUString aCharFormatName =
96 pNumRule->Get(o3tl::narrowing<sal_uInt16>(nListLevel)).GetCharFormatName();
97 SwCharFormat * pCharFormat =
98 GetDoc()->FindCharFormatByName(aCharFormatName);
100 if (pCharFormat)
101 rSet.Put(pCharFormat->GetAttrSet());
105 continue;
108 SwNodeOffset nSttNd = rCurrentPaM.Start()->GetNodeIndex(),
109 nEndNd = rCurrentPaM.End()->GetNodeIndex();
110 sal_Int32 nSttCnt = rCurrentPaM.Start()->GetContentIndex();
111 sal_Int32 nEndCnt = rCurrentPaM.End()->GetContentIndex();
113 if( sal_Int32(nEndNd - nSttNd) >= getMaxLookup() )
115 rSet.ClearItem();
116 return false;
119 // at first node the node enter his values into the GetSet (Initial)
120 // all additional nodes are additional merged to GetSet
121 for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n )
123 SwNode* pNd = GetDoc()->GetNodes()[ n ];
124 switch( pNd->GetNodeType() )
126 case SwNodeType::Text:
128 const sal_Int32 nStt = (n == nSttNd) ? nSttCnt : 0;
129 const sal_Int32 nEnd = (n == nEndNd)
130 ? nEndCnt
131 : pNd->GetTextNode()->GetText().getLength();
133 static_cast<SwTextNode*>(pNd)->GetParaAttr(*pSet, nStt, nEnd,
134 false, true,
135 bMergeIndentValuesOfNumRule,
136 GetLayout());
138 break;
139 case SwNodeType::Grf:
140 case SwNodeType::Ole:
141 static_cast<SwContentNode*>(pNd)->GetAttr( *pSet );
142 break;
144 default:
145 pNd = nullptr;
148 if( pNd )
150 if( pSet != &rSet )
152 if (!GetLayout()->HasMergedParas()
153 || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
155 rSet.MergeValues( aSet );
159 if( aSet.Count() )
160 aSet.ClearItem();
162 pSet = &aSet;
167 return true;
170 bool SwEditShell::GetCurAttr( SfxItemSet& rSet,
171 const bool bMergeIndentValuesOfNumRule ) const
173 return GetPaMAttr( GetCursor(), rSet, bMergeIndentValuesOfNumRule );
176 void SwEditShell::GetCurParAttr( SfxItemSet& rSet) const
178 GetPaMParAttr( GetCursor(), rSet );
181 void SwEditShell::GetPaMParAttr( SwPaM* pPaM, SfxItemSet& rSet ) const
183 // number of nodes the function has explored so far
184 sal_uInt16 numberOfLookup = 0;
186 SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
187 SfxItemSet* pSet = &rSet;
189 for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
190 { // for all the point and mark (selections)
192 // get the start and the end node of the current selection
193 SwNodeOffset nSttNd = rCurrentPaM.GetMark()->GetNodeIndex(),
194 nEndNd = rCurrentPaM.GetPoint()->GetNodeIndex();
196 // reverse start and end if there number aren't sorted correctly
197 if( nSttNd > nEndNd )
198 std::swap(nSttNd, nEndNd);
200 // for all the nodes in the current selection
201 // get the node (paragraph) attributes
202 // and merge them in rSet
203 for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n )
205 // get the node
206 SwNode* pNd = GetDoc()->GetNodes()[ n ];
208 if (GetLayout()->HasMergedParas()
209 && pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
211 continue;
214 if( pNd->IsTextNode() )
216 // get the node (paragraph) attributes
217 sw::GetAttrMerged(*pSet, *pNd->GetTextNode(), GetLayout());
219 if( pSet != &rSet && aSet.Count() )
221 rSet.MergeValues( aSet );
222 aSet.ClearItem();
225 pSet = &aSet;
228 ++numberOfLookup;
230 // if the maximum number of node that can be inspected has been reached
231 if (numberOfLookup >= getMaxLookup())
232 return;
237 SwTextFormatColl* SwEditShell::GetCurTextFormatColl( ) const
239 return GetPaMTextFormatColl( GetCursor() );
242 SwTextFormatColl* SwEditShell::GetPaMTextFormatColl( SwPaM* pPaM ) const
244 // number of nodes the function have explored so far
245 sal_uInt16 numberOfLookup = 0;
247 for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
248 { // for all the point and mark (selections)
250 // get the start and the end node of the current selection
251 SwNodeOffset nSttNd = rCurrentPaM.Start()->GetNodeIndex(),
252 nEndNd = rCurrentPaM.End()->GetNodeIndex();
254 // for all the nodes in the current Point and Mark
255 for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n )
257 // get the node
258 SwNode* pNd = GetDoc()->GetNodes()[ n ];
260 ++numberOfLookup;
262 // if the maximum number of node that can be inspected has been reached
263 if (numberOfLookup >= getMaxLookup())
264 return nullptr;
266 if( pNd->IsTextNode() )
268 SwTextNode *const pTextNode(sw::GetParaPropsNode(*GetLayout(), *pNd));
269 // if it's a text node get its named paragraph format
270 SwTextFormatColl *const pFormat = pTextNode->GetTextColl();
272 // if the paragraph format exist stop here and return it
273 if( pFormat != nullptr )
274 return pFormat;
279 // if none of the selected node contain a named paragraph format
280 return nullptr;
283 std::vector<std::pair< const SfxPoolItem*, std::unique_ptr<SwPaM> >> SwEditShell::GetItemWithPaM( sal_uInt16 nWhich )
285 assert(isCHRATR(nWhich)); // sw_redlinehide: only thing that works
286 std::vector<std::pair< const SfxPoolItem*, std::unique_ptr<SwPaM> >> vItem;
287 for(SwPaM& rCurrentPaM : GetCursor()->GetRingContainer())
288 { // for all the point and mark (selections)
290 // get the start and the end node of the current selection
291 SwNodeOffset nSttNd = rCurrentPaM.Start()->GetNodeIndex(),
292 nEndNd = rCurrentPaM.End()->GetNodeIndex();
293 sal_Int32 nSttCnt = rCurrentPaM.Start()->GetContentIndex();
294 sal_Int32 nEndCnt = rCurrentPaM.End()->GetContentIndex();
296 const SfxPoolItem* pItem = nullptr;
298 // for all the nodes in the current selection
299 for( SwNodeOffset n = nSttNd; n <= nEndNd; ++n )
301 SwNode* pNd = GetDoc()->GetNodes()[ n ];
302 if( pNd->IsTextNode() )
304 SwTextNode* pTextNd = static_cast< SwTextNode* >( pNd );
305 const sal_Int32 nStt = (n == nSttNd) ? nSttCnt : 0;
306 const sal_Int32 nEnd = (n == nEndNd)
307 ? nEndCnt : pTextNd->GetText().getLength();
308 SwTextFrame const* pFrame;
309 const SwScriptInfo *const pScriptInfo =
310 SwScriptInfo::GetScriptInfo(*pTextNd, &pFrame);
311 TextFrameIndex const iStt(pScriptInfo
312 ? pFrame->MapModelToView(pTextNd, nStt)
313 : TextFrameIndex(-1/*invalid, do not use*/));
314 sal_uInt8 nScript = pScriptInfo
315 ? pScriptInfo->ScriptType(iStt)
316 : css::i18n::ScriptType::WEAK;
317 nWhich = GetWhichOfScript( nWhich, nScript );
319 // item from attribute set
320 if( pTextNd->HasSwAttrSet() )
322 pItem = pTextNd->GetSwAttrSet().GetItem( nWhich );
323 vItem.emplace_back( pItem, std::make_unique<SwPaM>(*pNd, nStt, *pNd, nEnd) );
326 if( !pTextNd->HasHints() )
327 continue;
329 // items with limited range
330 const size_t nSize = pTextNd->GetpSwpHints()->Count();
331 for( size_t m = 0; m < nSize; m++ )
333 const SwTextAttr* pHt = pTextNd->GetpSwpHints()->Get(m);
334 if( pHt->Which() == RES_TXTATR_AUTOFMT ||
335 pHt->Which() == RES_TXTATR_CHARFMT ||
336 pHt->Which() == RES_TXTATR_INETFMT )
338 const sal_Int32 nAttrStart = pHt->GetStart();
339 const sal_Int32* pAttrEnd = pHt->End();
341 // Ignore items not in selection
342 if( nAttrStart > nEnd )
343 break;
344 if( *pAttrEnd <= nStt )
345 continue;
347 nScript = pScriptInfo
348 ? pScriptInfo->ScriptType(iStt)
349 : css::i18n::ScriptType::WEAK;
350 nWhich = GetWhichOfScript( nWhich, nScript );
351 const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
352 if( pAutoSet )
354 SfxItemIter aItemIter( *pAutoSet );
355 pItem = aItemIter.GetCurItem();
356 while( pItem )
358 if( pItem->Which() == nWhich )
360 sal_Int32 nStart = 0, nStop = 0;
361 if( nAttrStart < nStt ) // Attribute starts before selection
362 nStart = nStt;
363 else
364 nStart = nAttrStart;
365 if( *pAttrEnd > nEnd ) // Attribute ends after selection
366 nStop = nEnd;
367 else
368 nStop = *pAttrEnd;
369 vItem.emplace_back( pItem, std::make_unique<SwPaM>(*pNd, nStart, *pNd, nStop) );
370 break;
372 pItem = aItemIter.NextItem();
374 // default item
375 if( !pItem && !pTextNd->HasSwAttrSet() )
377 pItem = pAutoSet->GetPool()->GetUserDefaultItem( nWhich );
378 vItem.emplace_back( pItem, std::make_unique<SwPaM>(*pNd, nStt, *pNd, nEnd) );
386 return vItem;
389 bool SwEditShell::GetCurFootnote( SwFormatFootnote* pFillFootnote )
391 // The cursor must be positioned on the current footnotes anchor:
392 SwPaM* pCursor = GetCursor();
393 SwTextNode* pTextNd = pCursor->GetPointNode().GetTextNode();
394 if( !pTextNd )
395 return false;
397 SwTextAttr *const pFootnote = pTextNd->GetTextAttrForCharAt(
398 pCursor->GetPoint()->GetContentIndex(), RES_TXTATR_FTN);
399 if( pFootnote && pFillFootnote )
401 // Transfer data from the attribute
402 const SwFormatFootnote &rFootnote = static_cast<SwTextFootnote*>(pFootnote)->GetFootnote();
403 pFillFootnote->SetNumber( rFootnote );
404 pFillFootnote->SetEndNote( rFootnote.IsEndNote() );
406 return nullptr != pFootnote;
409 bool SwEditShell::SetCurFootnote( const SwFormatFootnote& rFillFootnote )
411 bool bChgd = false;
412 StartAllAction();
414 for(const SwPaM& rCursor : GetCursor()->GetRingContainer())
416 bChgd |=
417 mxDoc->SetCurFootnote(rCursor, rFillFootnote.GetNumStr(), rFillFootnote.IsEndNote());
421 EndAllAction();
422 return bChgd;
425 bool SwEditShell::HasFootnotes( bool bEndNotes ) const
427 const SwFootnoteIdxs &rIdxs = mxDoc->GetFootnoteIdxs();
428 for ( auto pIdx : rIdxs )
430 const SwFormatFootnote &rFootnote = pIdx->GetFootnote();
431 if ( bEndNotes == rFootnote.IsEndNote() )
432 return true;
434 return false;
437 /// Give a List of all footnotes and their beginning texts
438 size_t SwEditShell::GetSeqFootnoteList( SwSeqFieldList& rList, bool bEndNotes )
440 rList.Clear();
442 IDocumentRedlineAccess & rIDRA(mxDoc->getIDocumentRedlineAccess());
444 const size_t nFootnoteCnt = mxDoc->GetFootnoteIdxs().size();
445 SwTextFootnote* pTextFootnote;
446 for( size_t n = 0; n < nFootnoteCnt; ++n )
448 pTextFootnote = mxDoc->GetFootnoteIdxs()[ n ];
449 const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote();
450 if ( rFootnote.IsEndNote() != bEndNotes )
451 continue;
453 const SwNodeIndex* pIdx = pTextFootnote->GetStartNode();
454 if( pIdx )
456 SwNodeIndex aIdx( *pIdx, 1 );
457 SwTextNode* pTextNd = aIdx.GetNode().GetTextNode();
458 if( !pTextNd )
459 pTextNd = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
461 if( pTextNd )
463 if (GetLayout()->IsHideRedlines()
464 && sw::IsFootnoteDeleted(rIDRA, *pTextFootnote))
466 continue;
469 OUString sText(rFootnote.GetViewNumStr(*mxDoc, GetLayout()));
470 if( !sText.isEmpty() )
471 sText += " ";
472 sText += pTextNd->GetExpandText(GetLayout());
474 SeqFieldLstElem aNew( sText, pTextFootnote->GetSeqRefNo() );
475 while( rList.InsertSort( aNew ) )
476 aNew.sDlgEntry += " ";
481 return rList.Count();
484 /// Adjust left margin via object bar (similar to adjustment of numerations).
485 bool SwEditShell::IsMoveLeftMargin( bool bRight, bool bModulus ) const
487 bool bRet = true;
489 constexpr sal_uInt16 constTwips_2cm = o3tl::toTwips(20, o3tl::Length::mm);
490 constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
492 const SvxTabStopItem& rTabItem = GetDoc()->GetDefault( RES_PARATR_TABSTOP );
493 sal_uInt16 nDefDist = o3tl::narrowing<sal_uInt16>(
494 rTabItem.Count() ? rTabItem[0].GetTabPos() : constTwips_2cm);
496 if( !nDefDist )
497 return false;
499 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
501 SwNodeOffset nSttNd = rPaM.Start()->GetNodeIndex(),
502 nEndNd = rPaM.End()->GetNodeIndex();
504 SwContentNode* pCNd;
505 for( SwNodeOffset n = nSttNd; bRet && n <= nEndNd; ++n )
507 pCNd = GetDoc()->GetNodes()[ n ]->GetTextNode();
508 if( nullptr != pCNd )
510 pCNd = sw::GetParaPropsNode(*GetLayout(), *pCNd);
511 const SvxLRSpaceItem& rLS = pCNd->GetAttr( RES_LR_SPACE );
512 if( bRight )
514 tools::Long nNext = rLS.ResolveTextLeft({}) + nDefDist;
515 if( bModulus )
516 nNext = ( nNext / nDefDist ) * nDefDist;
517 SwFrame* pFrame = pCNd->getLayoutFrame( GetLayout() );
518 if ( pFrame )
520 const SwTwips nFrameWidth = pFrame->IsVertical() ?
521 pFrame->getFrameArea().Height() :
522 pFrame->getFrameArea().Width();
523 bRet = nFrameWidth > (nNext + constTwips_5mm);
525 else
526 bRet = false;
531 if( !bRet )
532 break;
535 return bRet;
538 void SwEditShell::MoveLeftMargin( bool bRight, bool bModulus )
540 StartAllAction();
541 StartUndo( SwUndoId::START );
543 SwPaM* pCursor = GetCursor();
544 if( pCursor->GetNext() != pCursor ) // Multiple selection ?
546 SwPamRanges aRangeArr( *pCursor );
547 SwPaM aPam( *pCursor->GetPoint() );
548 for( size_t n = 0; n < aRangeArr.Count(); ++n )
549 GetDoc()->MoveLeftMargin( aRangeArr.SetPam( n, aPam ),
550 bRight, bModulus, GetLayout() );
552 else
553 GetDoc()->MoveLeftMargin( *pCursor, bRight, bModulus, GetLayout() );
555 EndUndo( SwUndoId::END );
556 EndAllAction();
559 static SvtScriptType lcl_SetScriptFlags( sal_uInt16 nType )
561 switch( nType )
563 case css::i18n::ScriptType::LATIN:
564 return SvtScriptType::LATIN;
565 case css::i18n::ScriptType::ASIAN:
566 return SvtScriptType::ASIAN;
567 case css::i18n::ScriptType::COMPLEX:
568 return SvtScriptType::COMPLEX;
569 default:
570 return SvtScriptType::NONE;
574 static bool lcl_IsNoEndTextAttrAtPos(SwRootFrame const& rLayout,
575 const SwTextNode& rTNd, sal_Int32 const nPos,
576 SvtScriptType &rScrpt, bool bInSelection, bool bNum )
578 bool bRet = false;
579 OUString sExp;
581 // consider numbering
582 if ( bNum )
584 bRet = false;
585 SwTextNode const*const pPropsNode(sw::GetParaPropsNode(rLayout, rTNd));
586 if (pPropsNode->IsInList())
588 OSL_ENSURE( pPropsNode->GetNumRule(),
589 "<lcl_IsNoEndTextAttrAtPos(..)> - no list style found at text node. Serious defect." );
590 const SwNumRule* pNumRule = pPropsNode->GetNumRule();
591 if(pNumRule)
593 int nListLevel = pPropsNode->GetActualListLevel();
595 if (nListLevel < 0)
596 nListLevel = 0;
598 if (nListLevel >= MAXLEVEL)
599 nListLevel = MAXLEVEL - 1;
601 const SwNumFormat &rNumFormat = pNumRule->Get( o3tl::narrowing<sal_uInt16>(nListLevel) );
602 if( SVX_NUM_BITMAP != rNumFormat.GetNumberingType() )
604 if ( SVX_NUM_CHAR_SPECIAL == rNumFormat.GetNumberingType() )
606 sal_UCS4 cBullet = rNumFormat.GetBulletChar();
607 sExp = OUString(&cBullet, 1);
609 else
610 sExp = pPropsNode->GetNumString(true, MAXLEVEL, &rLayout);
616 // and fields
617 if (nPos < rTNd.GetText().getLength() && CH_TXTATR_BREAKWORD == rTNd.GetText()[nPos])
619 const SwTextAttr* const pAttr = rTNd.GetTextAttrForCharAt( nPos );
620 if (pAttr)
622 bRet = true; // all other than fields can be
623 // defined as weak-script ?
624 if ( RES_TXTATR_FIELD == pAttr->Which() )
626 const SwField* const pField = pAttr->GetFormatField().GetField();
627 if (pField)
629 sExp += pField->ExpandField(true, &rLayout);
635 const sal_Int32 nEnd = sExp.getLength();
636 if ( nEnd )
638 if( bInSelection )
640 sal_uInt16 nScript;
641 for( sal_Int32 n = 0; n < nEnd;
642 n = g_pBreakIt->GetBreakIter()->endOfScript( sExp, n, nScript ))
644 nScript = g_pBreakIt->GetBreakIter()->getScriptType( sExp, n );
645 rScrpt |= lcl_SetScriptFlags( nScript );
648 else
649 rScrpt |= lcl_SetScriptFlags( g_pBreakIt->GetBreakIter()->
650 getScriptType( sExp, nEnd-1 ));
653 return bRet;
656 /// returns the script type of the selection
657 SvtScriptType SwEditShell::GetScriptType() const
659 SvtScriptType nRet = SvtScriptType::NONE;
662 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
664 auto [pStart, pEnd] = rPaM.StartEnd(); // SwPosition*
665 if( pStart == pEnd || *pStart == *pEnd )
667 const SwTextNode* pTNd = pStart->GetNode().GetTextNode();
668 if( pTNd )
670 // try to get SwScriptInfo
671 SwTextFrame const* pFrame;
672 const SwScriptInfo *const pScriptInfo =
673 SwScriptInfo::GetScriptInfo(*pTNd, &pFrame);
675 sal_Int32 nPos = pStart->GetContentIndex();
676 //Task 90448: we need the scripttype of the previous
677 // position, if no selection exist!
678 if( nPos )
680 SwContentIndex aIdx( pStart->GetContentNode(), pStart->GetContentIndex() );
681 if( pTNd->GoPrevious( aIdx, SwCursorSkipMode::Chars ) )
682 nPos = aIdx.GetIndex();
685 sal_uInt16 nScript;
687 if (!pTNd->GetText().isEmpty())
689 nScript = pScriptInfo
690 ? pScriptInfo->ScriptType(pFrame->MapModelToView(pTNd, nPos))
691 : g_pBreakIt->GetBreakIter()->getScriptType( pTNd->GetText(), nPos );
693 else
694 nScript = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() );
696 if (!lcl_IsNoEndTextAttrAtPos(*GetLayout(), *pTNd, nPos, nRet, false, false))
697 nRet |= lcl_SetScriptFlags( nScript );
700 else
702 SwNodeOffset nEndIdx = pEnd->GetNodeIndex();
703 SwNodeIndex aIdx( pStart->GetNode() );
704 for( ; aIdx.GetIndex() <= nEndIdx; ++aIdx )
705 if( aIdx.GetNode().IsTextNode() )
707 const SwTextNode* pTNd = aIdx.GetNode().GetTextNode();
708 const OUString& rText = pTNd->GetText();
710 // try to get SwScriptInfo
711 SwTextFrame const* pFrame;
712 const SwScriptInfo *const pScriptInfo =
713 SwScriptInfo::GetScriptInfo(*pTNd, &pFrame);
715 sal_Int32 nChg = aIdx == pStart->GetNode()
716 ? pStart->GetContentIndex()
717 : 0;
718 sal_Int32 nEndPos = aIdx == nEndIdx
719 ? pEnd->GetContentIndex()
720 : rText.getLength();
722 OSL_ENSURE( nEndPos <= rText.getLength(),
723 "Index outside the range - endless loop!" );
724 if (nEndPos > rText.getLength())
725 nEndPos = rText.getLength();
727 bool const isUntilEnd(pScriptInfo
728 ? pFrame->MapViewToModelPos(TextFrameIndex(pFrame->GetText().getLength())) <= *pEnd
729 : rText.getLength() == nEndPos);
730 sal_uInt16 nScript;
731 while( nChg < nEndPos )
733 TextFrameIndex iChg(pScriptInfo
734 ? pFrame->MapModelToView(pTNd, nChg)
735 : TextFrameIndex(-1/*invalid, do not use*/));
736 nScript = pScriptInfo ?
737 pScriptInfo->ScriptType( iChg ) :
738 g_pBreakIt->GetBreakIter()->getScriptType(
739 rText, nChg );
741 if (!lcl_IsNoEndTextAttrAtPos(*GetLayout(), *pTNd, nChg, nRet, true,
742 TextFrameIndex(0) == iChg && isUntilEnd))
744 nRet |= lcl_SetScriptFlags( nScript );
747 if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
748 SvtScriptType::COMPLEX) == nRet )
749 break;
751 sal_Int32 nFieldPos = nChg+1;
753 if (pScriptInfo)
755 iChg = pScriptInfo->NextScriptChg(iChg);
756 if (iChg == TextFrameIndex(COMPLETE_STRING))
758 nChg = pTNd->Len();
760 else
762 std::pair<SwTextNode*, sal_Int32> const tmp(
763 pFrame->MapViewToModel(iChg));
764 nChg = (tmp.first == pTNd)
765 ? tmp.second
766 : pTNd->Len();
769 else
771 nChg = g_pBreakIt->GetBreakIter()->endOfScript(
772 rText, nChg, nScript );
775 nFieldPos = rText.indexOf(
776 CH_TXTATR_BREAKWORD, nFieldPos);
777 if ((-1 != nFieldPos) && (nFieldPos < nChg))
778 nChg = nFieldPos;
780 if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
781 SvtScriptType::COMPLEX) == nRet )
782 break;
785 if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
786 SvtScriptType::COMPLEX) == nRet )
787 break;
791 if( nRet == SvtScriptType::NONE )
792 nRet = SvtLanguageOptions::GetScriptTypeOfLanguage( LANGUAGE_SYSTEM );
793 return nRet;
796 LanguageType SwEditShell::GetCurLang() const
798 const SwPaM* pCursor = GetCursor();
799 const SwPosition& rPos = *pCursor->GetPoint();
800 const SwTextNode* pTNd = rPos.GetNode().GetTextNode();
801 LanguageType nLang;
802 if( pTNd )
804 //JP 24.9.2001: if exist no selection, then get the language before
805 // the current character!
806 sal_Int32 nPos = rPos.GetContentIndex();
807 if( nPos && !pCursor->HasMark() )
808 --nPos;
809 nLang = pTNd->GetLang( nPos );
811 else
812 nLang = LANGUAGE_DONTKNOW;
813 return nLang;
816 sal_uInt16 SwEditShell::GetScalingOfSelectedText() const
818 const SwPaM* pCursor = GetCursor();
819 const SwPosition* pStart = pCursor->Start();
820 const SwTextNode* pTNd = pStart->GetNode().GetTextNode();
821 OSL_ENSURE( pTNd, "no textnode available" );
823 sal_uInt16 nScaleWidth;
824 if( pTNd )
826 SwTextFrame *const pFrame(static_cast<SwTextFrame *>(
827 pTNd->getLayoutFrame(GetLayout(), pStart)));
828 assert(pFrame); // shell cursor must be positioned in node with frame
829 TextFrameIndex const nStart(pFrame->MapModelToViewPos(*pStart));
830 TextFrameIndex const nEnd(
831 sw::FrameContainsNode(*pFrame, pCursor->End()->GetNodeIndex())
832 ? pFrame->MapModelToViewPos(*pCursor->End())
833 : TextFrameIndex(pFrame->GetText().getLength()));
834 nScaleWidth = pFrame->GetScalingOfSelectedText(nStart, nEnd);
836 else
837 nScaleWidth = 100; // default are no scaling -> 100%
838 return nScaleWidth;
841 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */