1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <hintids.hxx>
22 #include <editeng/tstpitem.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <editeng/scripttypeitem.hxx>
25 #include <com/sun/star/i18n/ScriptType.hpp>
26 #include <com/sun/star/i18n/XBreakIterator.hpp>
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 <txtfld.hxx>
41 #include <fmtfld.hxx>
42 #include <txtfrm.hxx>
43 #include <scriptinfo.hxx>
44 #include <svl/ctloptions.hxx>
45 #include <svl/itemiter.hxx>
46 #include <charfmt.hxx>
47 #include <numrule.hxx>
48 
49 #include <algorithm>
50 #include <charatr.hxx>
51 
52 /*
53  * hard Formatting (Attributes)
54  */
55 
56 // if selection is bigger as max nodes or more than max selections
57 // => no attributes
getMaxLookup()58 static sal_uInt16 getMaxLookup()
59 {
60     return 10000;
61 }
62 
GetPaMAttr(SwPaM * pPaM,SfxItemSet & rSet,const bool bMergeIndentValuesOfNumRule) const63 bool SwEditShell::GetPaMAttr( SwPaM* pPaM, SfxItemSet& rSet,
64                               const bool bMergeIndentValuesOfNumRule ) const
65 {
66     // ??? pPaM can be different from the Cursor ???
67     if( GetCursorCnt() > getMaxLookup() )
68     {
69         rSet.InvalidateAllItems();
70         return false;
71     }
72 
73     SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
74     SfxItemSet *pSet = &rSet;
75 
76     for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
77     {
78         // #i27615# if the cursor is in front of the numbering label
79         // the attributes to get are those from the numbering format.
80         if (rCurrentPaM.IsInFrontOfLabel())
81         {
82             SwTextNode const*const pTextNd = sw::GetParaPropsNode(*GetLayout(),
83                     rCurrentPaM.GetPoint()->nNode);
84 
85             if (pTextNd)
86             {
87                 SwNumRule * pNumRule = pTextNd->GetNumRule();
88 
89                 if (pNumRule)
90                 {
91                     int nListLevel = pTextNd->GetActualListLevel();
92 
93                     if (nListLevel < 0)
94                         nListLevel = 0;
95 
96                     if (nListLevel >= MAXLEVEL)
97                         nListLevel = MAXLEVEL - 1;
98 
99                     const OUString & aCharFormatName =
100                         pNumRule->Get(static_cast<sal_uInt16>(nListLevel)).GetCharFormatName();
101                     SwCharFormat * pCharFormat =
102                         GetDoc()->FindCharFormatByName(aCharFormatName);
103 
104                     if (pCharFormat)
105                         rSet.Put(pCharFormat->GetAttrSet());
106                 }
107             }
108 
109             continue;
110         }
111 
112         sal_uLong nSttNd = rCurrentPaM.GetMark()->nNode.GetIndex(),
113               nEndNd = rCurrentPaM.GetPoint()->nNode.GetIndex();
114         sal_Int32 nSttCnt = rCurrentPaM.GetMark()->nContent.GetIndex();
115         sal_Int32 nEndCnt = rCurrentPaM.GetPoint()->nContent.GetIndex();
116 
117         if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
118         {
119             std::swap(nSttNd, nEndNd);
120             std::swap(nSttCnt, nEndCnt);
121         }
122 
123         if( nEndNd - nSttNd >= getMaxLookup() )
124         {
125             rSet.ClearItem();
126             rSet.InvalidateAllItems();
127             return false;
128         }
129 
130         // at first node the node enter his values into the GetSet (Initial)
131         // all additional nodes are additional merged to GetSet
132         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
133         {
134             SwNode* pNd = GetDoc()->GetNodes()[ n ];
135             switch( pNd->GetNodeType() )
136             {
137             case SwNodeType::Text:
138                 {
139                     const sal_Int32 nStt = (n == nSttNd) ? nSttCnt : 0;
140                     const sal_Int32 nEnd = (n == nEndNd)
141                         ? nEndCnt
142                         : pNd->GetTextNode()->GetText().getLength();
143 
144                     static_cast<SwTextNode*>(pNd)->GetParaAttr(*pSet, nStt, nEnd,
145                                                 false, true,
146                                                 bMergeIndentValuesOfNumRule,
147                                                 GetLayout());
148                 }
149                 break;
150             case SwNodeType::Grf:
151             case SwNodeType::Ole:
152                 static_cast<SwContentNode*>(pNd)->GetAttr( *pSet );
153                 break;
154 
155             default:
156                 pNd = nullptr;
157             }
158 
159             if( pNd )
160             {
161                 if( pSet != &rSet )
162                 {
163                     if (!GetLayout()->IsHideRedlines()
164                         || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
165                     {
166                         rSet.MergeValues( aSet );
167                     }
168                 }
169 
170                 if( aSet.Count() )
171                     aSet.ClearItem();
172             }
173             pSet = &aSet;
174         }
175 
176     }
177 
178     return true;
179 }
180 
GetCurAttr(SfxItemSet & rSet,const bool bMergeIndentValuesOfNumRule) const181 bool SwEditShell::GetCurAttr( SfxItemSet& rSet,
182                               const bool bMergeIndentValuesOfNumRule ) const
183 {
184     return GetPaMAttr( GetCursor(), rSet, bMergeIndentValuesOfNumRule );
185 }
186 
GetCurParAttr(SfxItemSet & rSet) const187 void SwEditShell::GetCurParAttr( SfxItemSet& rSet) const
188 {
189     GetPaMParAttr( GetCursor(), rSet );
190 }
191 
GetPaMParAttr(SwPaM * pPaM,SfxItemSet & rSet) const192 bool SwEditShell::GetPaMParAttr( SwPaM* pPaM, SfxItemSet& rSet ) const
193 {
194     // number of nodes the function has explored so far
195     sal_uInt16 numberOfLookup = 0;
196 
197     SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
198     SfxItemSet* pSet = &rSet;
199 
200     for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
201     { // for all the point and mark (selections)
202 
203         // get the start and the end node of the current selection
204         sal_uLong nSttNd = rCurrentPaM.GetMark()->nNode.GetIndex(),
205               nEndNd = rCurrentPaM.GetPoint()->nNode.GetIndex();
206 
207         // reverse start and end if there number aren't sorted correctly
208         if( nSttNd > nEndNd )
209             std::swap(nSttNd, nEndNd);
210 
211         // for all the nodes in the current selection
212         // get the node (paragraph) attributes
213         // and merge them in rSet
214         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
215         {
216             // get the node
217             SwNode* pNd = GetDoc()->GetNodes()[ n ];
218 
219             if (GetLayout()->IsHideRedlines()
220                 && pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
221             {
222                 continue;
223             }
224 
225             if( pNd->IsTextNode() )
226             {
227                 // get the node (paragraph) attributes
228                 sw::GetAttrMerged(*pSet, *pNd->GetTextNode(), GetLayout());
229 
230                 if( pSet != &rSet && aSet.Count() )
231                 {
232                     rSet.MergeValues( aSet );
233                     aSet.ClearItem();
234                 }
235 
236                 pSet = &aSet;
237             }
238 
239             ++numberOfLookup;
240 
241             // if the maximum number of node that can be inspected has been reached
242             if (numberOfLookup >= getMaxLookup())
243                 return false;
244         }
245     }
246 
247     return true;
248 }
249 
GetCurTextFormatColl() const250 SwTextFormatColl* SwEditShell::GetCurTextFormatColl( ) const
251 {
252     return GetPaMTextFormatColl( GetCursor() );
253 }
254 
GetPaMTextFormatColl(SwPaM * pPaM) const255 SwTextFormatColl* SwEditShell::GetPaMTextFormatColl( SwPaM* pPaM ) const
256 {
257     // number of nodes the function have explored so far
258     sal_uInt16 numberOfLookup = 0;
259 
260     for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
261     { // for all the point and mark (selections)
262 
263         // get the start and the end node of the current selection
264         sal_uLong nSttNd = rCurrentPaM.GetMark()->nNode.GetIndex(),
265               nEndNd = rCurrentPaM.GetPoint()->nNode.GetIndex();
266 
267         // reverse start and end if they aren't sorted correctly
268         if( nSttNd > nEndNd )
269             std::swap(nSttNd, nEndNd);
270 
271         // for all the nodes in the current Point and Mark
272         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
273         {
274             // get the node
275             SwNode* pNd = GetDoc()->GetNodes()[ n ];
276 
277             ++numberOfLookup;
278 
279             // if the maximum number of node that can be inspected has been reached
280             if (numberOfLookup >= getMaxLookup())
281                 return nullptr;
282 
283             if( pNd->IsTextNode() )
284             {
285                 SwTextNode *const pTextNode(sw::GetParaPropsNode(*GetLayout(), SwNodeIndex(*pNd)));
286                 // if it's a text node get its named paragraph format
287                 SwTextFormatColl *const pFormat = pTextNode->GetTextColl();
288 
289                 // if the paragraph format exist stop here and return it
290                 if( pFormat != nullptr )
291                     return pFormat;
292             }
293         }
294     }
295 
296     // if none of the selected node contain a named paragraph format
297     return nullptr;
298 }
299 
GetItemWithPaM(sal_uInt16 nWhich)300 std::vector<std::pair< const SfxPoolItem*, std::unique_ptr<SwPaM> >> SwEditShell::GetItemWithPaM( sal_uInt16 nWhich )
301 {
302     assert(isCHRATR(nWhich)); // sw_redlinehide: only thing that works
303     std::vector<std::pair< const SfxPoolItem*, std::unique_ptr<SwPaM> >> vItem;
304     for(SwPaM& rCurrentPaM : GetCursor()->GetRingContainer())
305     { // for all the point and mark (selections)
306 
307         // get the start and the end node of the current selection
308         sal_uLong nSttNd = rCurrentPaM.Start()->nNode.GetIndex(),
309               nEndNd = rCurrentPaM.End()->nNode.GetIndex();
310         sal_Int32 nSttCnt = rCurrentPaM.Start()->nContent.GetIndex();
311         sal_Int32 nEndCnt = rCurrentPaM.End()->nContent.GetIndex();
312 
313         SwPaM* pNewPaM = nullptr;
314         const SfxPoolItem* pItem = nullptr;
315 
316         // for all the nodes in the current selection
317         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
318         {
319             SwNode* pNd = GetDoc()->GetNodes()[ n ];
320             if( pNd->IsTextNode() )
321             {
322                 SwTextNode* pTextNd = static_cast< SwTextNode* >( pNd );
323                 const sal_Int32 nStt = (n == nSttNd) ? nSttCnt : 0;
324                 const sal_Int32 nEnd = (n == nEndNd)
325                     ? nEndCnt : pTextNd->GetText().getLength();
326                 SwTextFrame const* pFrame;
327                 const SwScriptInfo *const pScriptInfo =
328                     SwScriptInfo::GetScriptInfo(*pTextNd, &pFrame);
329                 TextFrameIndex const iStt(pScriptInfo
330                         ? pFrame->MapModelToView(pTextNd, nStt)
331                         : TextFrameIndex(-1/*invalid, do not use*/));
332                 sal_uInt8 nScript = pScriptInfo
333                     ? pScriptInfo->ScriptType(iStt)
334                     : css::i18n::ScriptType::WEAK;
335                 nWhich = GetWhichOfScript( nWhich, nScript );
336 
337                 // item from attribute set
338                 if( pTextNd->HasSwAttrSet() )
339                 {
340                     pNewPaM = new SwPaM(*pNd, nStt, *pNd, nEnd);
341                     pItem = pTextNd->GetSwAttrSet().GetItem( nWhich );
342                     vItem.emplace_back( pItem, std::unique_ptr<SwPaM>(pNewPaM) );
343                 }
344 
345                 if( !pTextNd->HasHints() )
346                     continue;
347 
348                 // items with limited range
349                 const size_t nSize = pTextNd->GetpSwpHints()->Count();
350                 for( size_t m = 0; m < nSize; m++ )
351                 {
352                     const SwTextAttr* pHt = pTextNd->GetpSwpHints()->Get(m);
353                     if( pHt->Which() == RES_TXTATR_AUTOFMT ||
354                         pHt->Which() == RES_TXTATR_CHARFMT ||
355                         pHt->Which() == RES_TXTATR_INETFMT )
356                     {
357                         const sal_Int32 nAttrStart = pHt->GetStart();
358                         const sal_Int32* pAttrEnd = pHt->End();
359 
360                         // Ignore items not in selection
361                         if( nAttrStart > nEnd )
362                             break;
363                         if( *pAttrEnd <= nStt )
364                             continue;
365 
366                         nScript = pScriptInfo
367                             ? pScriptInfo->ScriptType(iStt)
368                             : css::i18n::ScriptType::WEAK;
369                         nWhich = GetWhichOfScript( nWhich, nScript );
370                         const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
371                         if( pAutoSet )
372                         {
373                             SfxItemIter aItemIter( *pAutoSet );
374                             pItem = aItemIter.GetCurItem();
375                             while( pItem )
376                             {
377                                 if( pItem->Which() == nWhich )
378                                 {
379                                     sal_Int32 nStart = 0, nStop = 0;
380                                     if( nAttrStart < nStt ) // Attribute starts before selection
381                                         nStart = nStt;
382                                     else
383                                         nStart = nAttrStart;
384                                     if( *pAttrEnd > nEnd ) // Attribute ends after selection
385                                         nStop = nEnd;
386                                     else
387                                         nStop = *pAttrEnd;
388                                     pNewPaM = new SwPaM(*pNd, nStart, *pNd, nStop);
389                                     vItem.emplace_back( pItem, std::unique_ptr<SwPaM>(pNewPaM) );
390                                     break;
391                                 }
392                                 pItem = aItemIter.NextItem();
393                             }
394                             // default item
395                             if( !pItem && !pTextNd->HasSwAttrSet() )
396                             {
397                                 pNewPaM = new SwPaM(*pNd, nStt, *pNd, nEnd);
398                                 pItem = pAutoSet->GetPool()->GetPoolDefaultItem( nWhich );
399                                 vItem.emplace_back( pItem,  std::unique_ptr<SwPaM>(pNewPaM) );
400                             }
401                         }
402                     }
403                 }
404             }
405         }
406     }
407     return vItem;
408 }
409 
GetCurFootnote(SwFormatFootnote * pFillFootnote)410 bool SwEditShell::GetCurFootnote( SwFormatFootnote* pFillFootnote )
411 {
412     // The cursor must be positioned on the current footnotes anchor:
413     SwPaM* pCursor = GetCursor();
414     SwTextNode* pTextNd = pCursor->GetNode().GetTextNode();
415     if( !pTextNd )
416         return false;
417 
418     SwTextAttr *const pFootnote = pTextNd->GetTextAttrForCharAt(
419         pCursor->GetPoint()->nContent.GetIndex(), RES_TXTATR_FTN);
420     if( pFootnote && pFillFootnote )
421     {
422         // Transfer data from the attribute
423         const SwFormatFootnote &rFootnote = static_cast<SwTextFootnote*>(pFootnote)->GetFootnote();
424         pFillFootnote->SetNumber( rFootnote );
425         pFillFootnote->SetEndNote( rFootnote.IsEndNote() );
426     }
427     return nullptr != pFootnote;
428 }
429 
SetCurFootnote(const SwFormatFootnote & rFillFootnote)430 bool SwEditShell::SetCurFootnote( const SwFormatFootnote& rFillFootnote )
431 {
432     bool bChgd = false;
433     StartAllAction();
434 
435     for(const SwPaM& rCursor : GetCursor()->GetRingContainer())
436     {
437         bChgd |=
438             mxDoc->SetCurFootnote(rCursor, rFillFootnote.GetNumStr(), rFillFootnote.IsEndNote());
439 
440     }
441 
442     EndAllAction();
443     return bChgd;
444 }
445 
HasFootnotes(bool bEndNotes) const446 bool SwEditShell::HasFootnotes( bool bEndNotes ) const
447 {
448     const SwFootnoteIdxs &rIdxs = mxDoc->GetFootnoteIdxs();
449     for ( auto pIdx : rIdxs )
450     {
451         const SwFormatFootnote &rFootnote = pIdx->GetFootnote();
452         if ( bEndNotes == rFootnote.IsEndNote() )
453             return true;
454     }
455     return false;
456 }
457 
458 /// Give a List of all footnotes and their beginning texts
GetSeqFootnoteList(SwSeqFieldList & rList,bool bEndNotes)459 size_t SwEditShell::GetSeqFootnoteList( SwSeqFieldList& rList, bool bEndNotes )
460 {
461     rList.Clear();
462 
463     IDocumentRedlineAccess & rIDRA(mxDoc->getIDocumentRedlineAccess());
464 
465     const size_t nFootnoteCnt = mxDoc->GetFootnoteIdxs().size();
466     SwTextFootnote* pTextFootnote;
467     for( size_t n = 0; n < nFootnoteCnt; ++n )
468     {
469         pTextFootnote = mxDoc->GetFootnoteIdxs()[ n ];
470         const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote();
471         if ( rFootnote.IsEndNote() != bEndNotes )
472             continue;
473 
474         SwNodeIndex* pIdx = pTextFootnote->GetStartNode();
475         if( pIdx )
476         {
477             SwNodeIndex aIdx( *pIdx, 1 );
478             SwTextNode* pTextNd = aIdx.GetNode().GetTextNode();
479             if( !pTextNd )
480                 pTextNd = static_cast<SwTextNode*>(mxDoc->GetNodes().GoNext( &aIdx ));
481 
482             if( pTextNd )
483             {
484                 if (GetLayout()->IsHideRedlines()
485                     && sw::IsFootnoteDeleted(rIDRA, *pTextFootnote))
486                 {
487                     continue;
488                 }
489 
490                 OUString sText(rFootnote.GetViewNumStr(*mxDoc, GetLayout()));
491                 if( !sText.isEmpty() )
492                     sText += " ";
493                 sText += pTextNd->GetExpandText(GetLayout());
494 
495                 SeqFieldLstElem aNew( sText, pTextFootnote->GetSeqRefNo() );
496                 while( rList.InsertSort( aNew ) )
497                     aNew.sDlgEntry += " ";
498             }
499         }
500     }
501 
502     return rList.Count();
503 }
504 
505 /// Adjust left margin via object bar (similar to adjustment of numerations).
IsMoveLeftMargin(bool bRight,bool bModulus) const506 bool SwEditShell::IsMoveLeftMargin( bool bRight, bool bModulus ) const
507 {
508     bool bRet = true;
509 
510     const SvxTabStopItem& rTabItem = GetDoc()->GetDefault( RES_PARATR_TABSTOP );
511     sal_uInt16 nDefDist = static_cast<sal_uInt16>(rTabItem.Count() ? rTabItem[0].GetTabPos() : 1134);
512     if( !nDefDist )
513         return false;
514 
515     for(SwPaM& rPaM : GetCursor()->GetRingContainer())
516     {
517         sal_uLong nSttNd = rPaM.GetMark()->nNode.GetIndex(),
518               nEndNd = rPaM.GetPoint()->nNode.GetIndex();
519 
520         if( nSttNd > nEndNd )
521             std::swap(nSttNd, nEndNd);
522 
523         SwContentNode* pCNd;
524         for( sal_uLong n = nSttNd; bRet && n <= nEndNd; ++n )
525             if( nullptr != ( pCNd = GetDoc()->GetNodes()[ n ]->GetTextNode() ))
526             {
527                 pCNd = sw::GetParaPropsNode(*GetLayout(), *pCNd);
528                 const SvxLRSpaceItem& rLS = static_cast<const SvxLRSpaceItem&>(
529                                             pCNd->GetAttr( RES_LR_SPACE ));
530                 if( bRight )
531                 {
532                     long nNext = rLS.GetTextLeft() + nDefDist;
533                     if( bModulus )
534                         nNext = ( nNext / nDefDist ) * nDefDist;
535                     SwFrame* pFrame = pCNd->getLayoutFrame( GetLayout() );
536                     if ( pFrame )
537                     {
538                         const sal_uInt16 nFrameWidth = static_cast<sal_uInt16>( pFrame->IsVertical() ?
539                                                  pFrame->getFrameArea().Height() :
540                                                  pFrame->getFrameArea().Width() );
541                         bRet = nFrameWidth > ( nNext + MM50 );
542                     }
543                     else
544                         bRet = false;
545                 }
546             }
547 
548         if( !bRet )
549             break;
550 
551     }
552     return bRet;
553 }
554 
MoveLeftMargin(bool bRight,bool bModulus)555 void SwEditShell::MoveLeftMargin( bool bRight, bool bModulus )
556 {
557     StartAllAction();
558     StartUndo( SwUndoId::START );
559 
560     SwPaM* pCursor = GetCursor();
561     if( pCursor->GetNext() != pCursor )         // Multiple selection ?
562     {
563         SwPamRanges aRangeArr( *pCursor );
564         SwPaM aPam( *pCursor->GetPoint() );
565         for( size_t n = 0; n < aRangeArr.Count(); ++n )
566             GetDoc()->MoveLeftMargin( aRangeArr.SetPam( n, aPam ),
567                                         bRight, bModulus, GetLayout() );
568     }
569     else
570         GetDoc()->MoveLeftMargin( *pCursor, bRight, bModulus, GetLayout() );
571 
572     EndUndo( SwUndoId::END );
573     EndAllAction();
574 }
575 
lcl_SetScriptFlags(sal_uInt16 nType)576 static SvtScriptType lcl_SetScriptFlags( sal_uInt16 nType )
577 {
578     switch( nType )
579     {
580         case css::i18n::ScriptType::LATIN:
581             return SvtScriptType::LATIN;
582         case css::i18n::ScriptType::ASIAN:
583             return SvtScriptType::ASIAN;
584         case css::i18n::ScriptType::COMPLEX:
585             return SvtScriptType::COMPLEX;
586         default:
587             return SvtScriptType::NONE;
588     }
589 }
590 
lcl_IsNoEndTextAttrAtPos(SwRootFrame const & rLayout,const SwTextNode & rTNd,sal_Int32 const nPos,SvtScriptType & rScrpt,bool bInSelection,bool bNum)591 static bool lcl_IsNoEndTextAttrAtPos(SwRootFrame const& rLayout,
592         const SwTextNode& rTNd, sal_Int32 const nPos,
593                             SvtScriptType &rScrpt, bool bInSelection, bool bNum )
594 {
595     bool bRet = false;
596     OUString sExp;
597 
598     // consider numbering
599     if ( bNum )
600     {
601         bRet = false;
602         SwTextNode const*const pPropsNode(sw::GetParaPropsNode(rLayout, rTNd));
603         if (pPropsNode->IsInList())
604         {
605             OSL_ENSURE( pPropsNode->GetNumRule(),
606                     "<lcl_IsNoEndTextAttrAtPos(..)> - no list style found at text node. Serious defect." );
607             const SwNumRule* pNumRule = pPropsNode->GetNumRule();
608             if(pNumRule)
609             {
610                 int nListLevel = pPropsNode->GetActualListLevel();
611 
612                 if (nListLevel < 0)
613                     nListLevel = 0;
614 
615                 if (nListLevel >= MAXLEVEL)
616                     nListLevel = MAXLEVEL - 1;
617 
618                 const SwNumFormat &rNumFormat = pNumRule->Get( static_cast<sal_uInt16>(nListLevel) );
619                 if( SVX_NUM_BITMAP != rNumFormat.GetNumberingType() )
620                 {
621                     if ( SVX_NUM_CHAR_SPECIAL == rNumFormat.GetNumberingType() )
622                         sExp = OUString(rNumFormat.GetBulletChar());
623                     else
624                         sExp = pPropsNode->GetNumString(true, MAXLEVEL, &rLayout);
625                 }
626             }
627         }
628     }
629 
630     // and fields
631     if (nPos < rTNd.GetText().getLength() && CH_TXTATR_BREAKWORD == rTNd.GetText()[nPos])
632     {
633         const SwTextAttr* const pAttr = rTNd.GetTextAttrForCharAt( nPos );
634         if (pAttr)
635         {
636             bRet = true; // all other than fields can be
637                          // defined as weak-script ?
638             if ( RES_TXTATR_FIELD == pAttr->Which() )
639             {
640                 const SwField* const pField = pAttr->GetFormatField().GetField();
641                 if (pField)
642                 {
643                     sExp += pField->ExpandField(true, &rLayout);
644                 }
645             }
646         }
647     }
648 
649     const sal_Int32 nEnd = sExp.getLength();
650     if ( nEnd )
651     {
652         if( bInSelection )
653         {
654             sal_uInt16 nScript;
655             for( sal_Int32 n = 0; n < nEnd;
656                  n = g_pBreakIt->GetBreakIter()->endOfScript( sExp, n, nScript ))
657             {
658                 nScript = g_pBreakIt->GetBreakIter()->getScriptType( sExp, n );
659                 rScrpt |= lcl_SetScriptFlags( nScript );
660             }
661         }
662         else
663             rScrpt |= lcl_SetScriptFlags( g_pBreakIt->GetBreakIter()->
664                                         getScriptType( sExp, nEnd-1 ));
665     }
666 
667     return bRet;
668 }
669 
670 /// returns the script type of the selection
GetScriptType() const671 SvtScriptType SwEditShell::GetScriptType() const
672 {
673     SvtScriptType nRet = SvtScriptType::NONE;
674 
675     {
676         for(SwPaM& rPaM : GetCursor()->GetRingContainer())
677         {
678             const SwPosition *pStt = rPaM.Start(),
679                              *pEnd = pStt == rPaM.GetMark()
680                                     ? rPaM.GetPoint()
681                                     : rPaM.GetMark();
682             if( pStt == pEnd || *pStt == *pEnd )
683             {
684                 const SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
685                 if( pTNd )
686                 {
687                     // try to get SwScriptInfo
688                     SwTextFrame const* pFrame;
689                     const SwScriptInfo *const pScriptInfo =
690                         SwScriptInfo::GetScriptInfo(*pTNd, &pFrame);
691 
692                     sal_Int32 nPos = pStt->nContent.GetIndex();
693                     //Task 90448: we need the scripttype of the previous
694                     //              position, if no selection exist!
695                     if( nPos )
696                     {
697                         SwIndex aIdx( pStt->nContent );
698                         if( pTNd->GoPrevious( &aIdx, CRSR_SKIP_CHARS ) )
699                             nPos = aIdx.GetIndex();
700                     }
701 
702                     sal_uInt16 nScript;
703 
704                     if (!pTNd->GetText().isEmpty())
705                     {
706                         nScript = pScriptInfo
707                             ? pScriptInfo->ScriptType(pFrame->MapModelToView(pTNd, nPos))
708                             : g_pBreakIt->GetBreakIter()->getScriptType( pTNd->GetText(), nPos );
709                     }
710                     else
711                         nScript = SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() );
712 
713                     if (!lcl_IsNoEndTextAttrAtPos(*GetLayout(), *pTNd, nPos, nRet, false, false))
714                         nRet |= lcl_SetScriptFlags( nScript );
715                 }
716             }
717             else
718             {
719                 sal_uLong nEndIdx = pEnd->nNode.GetIndex();
720                 SwNodeIndex aIdx( pStt->nNode );
721                 for( ; aIdx.GetIndex() <= nEndIdx; ++aIdx )
722                     if( aIdx.GetNode().IsTextNode() )
723                     {
724                         const SwTextNode* pTNd = aIdx.GetNode().GetTextNode();
725                         const OUString& rText = pTNd->GetText();
726 
727                         // try to get SwScriptInfo
728                         SwTextFrame const* pFrame;
729                         const SwScriptInfo *const pScriptInfo =
730                             SwScriptInfo::GetScriptInfo(*pTNd, &pFrame);
731 
732                         sal_Int32 nChg = aIdx == pStt->nNode
733                                                 ? pStt->nContent.GetIndex()
734                                                 : 0;
735                         sal_Int32 nEndPos = aIdx == nEndIdx
736                                                 ? pEnd->nContent.GetIndex()
737                                                 : rText.getLength();
738 
739                         OSL_ENSURE( nEndPos <= rText.getLength(),
740                                 "Index outside the range - endless loop!" );
741                         if (nEndPos > rText.getLength())
742                             nEndPos = rText.getLength();
743 
744                         bool const isUntilEnd(pScriptInfo
745                             ? pFrame->MapViewToModelPos(TextFrameIndex(pFrame->GetText().getLength())) <= *pEnd
746                             : rText.getLength() == nEndPos);
747                         sal_uInt16 nScript;
748                         while( nChg < nEndPos )
749                         {
750                             TextFrameIndex iChg(pScriptInfo
751                                     ? pFrame->MapModelToView(pTNd, nChg)
752                                     : TextFrameIndex(-1/*invalid, do not use*/));
753                             nScript = pScriptInfo ?
754                                       pScriptInfo->ScriptType( iChg ) :
755                                       g_pBreakIt->GetBreakIter()->getScriptType(
756                                                                 rText, nChg );
757 
758                             if (!lcl_IsNoEndTextAttrAtPos(*GetLayout(), *pTNd, nChg, nRet, true,
759                                       TextFrameIndex(0) == iChg && isUntilEnd))
760                             {
761                                 nRet |= lcl_SetScriptFlags( nScript );
762                             }
763 
764                             if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
765                                 SvtScriptType::COMPLEX) == nRet )
766                                 break;
767 
768                             sal_Int32 nFieldPos = nChg+1;
769 
770                             if (pScriptInfo)
771                             {
772                                 iChg = pScriptInfo->NextScriptChg(iChg);
773                                 if (iChg == TextFrameIndex(COMPLETE_STRING))
774                                 {
775                                     nChg = pTNd->Len();
776                                 }
777                                 else
778                                 {
779                                     std::pair<SwTextNode*, sal_Int32> const tmp(
780                                         pFrame->MapViewToModel(iChg));
781                                     nChg = (tmp.first == pTNd)
782                                         ? tmp.second
783                                         : pTNd->Len();
784                                 }
785                             }
786                             else
787                             {
788                                 nChg = g_pBreakIt->GetBreakIter()->endOfScript(
789                                                     rText, nChg, nScript );
790                             }
791 
792                             nFieldPos = rText.indexOf(
793                                             CH_TXTATR_BREAKWORD, nFieldPos);
794                             if ((-1 != nFieldPos) && (nFieldPos < nChg))
795                                 nChg = nFieldPos;
796                         }
797                         if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
798                                 SvtScriptType::COMPLEX) == nRet )
799                             break;
800                     }
801             }
802             if( (SvtScriptType::LATIN | SvtScriptType::ASIAN |
803                                 SvtScriptType::COMPLEX) == nRet )
804                 break;
805 
806         }
807     }
808     if( nRet == SvtScriptType::NONE )
809         nRet = SvtLanguageOptions::GetScriptTypeOfLanguage( LANGUAGE_SYSTEM );
810     return nRet;
811 }
812 
GetCurLang() const813 LanguageType SwEditShell::GetCurLang() const
814 {
815     const SwPaM* pCursor = GetCursor();
816     const SwPosition& rPos = *pCursor->GetPoint();
817     const SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode();
818     LanguageType nLang;
819     if( pTNd )
820     {
821         //JP 24.9.2001: if exist no selection, then get the language before
822         //              the current character!
823         sal_Int32 nPos = rPos.nContent.GetIndex();
824         if( nPos && !pCursor->HasMark() )
825             --nPos;
826         nLang = pTNd->GetLang( nPos );
827     }
828     else
829         nLang = LANGUAGE_DONTKNOW;
830     return nLang;
831 }
832 
GetScalingOfSelectedText() const833 sal_uInt16 SwEditShell::GetScalingOfSelectedText() const
834 {
835     const SwPaM* pCursor = GetCursor();
836     const SwPosition* pStt = pCursor->Start();
837     const SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
838     OSL_ENSURE( pTNd, "no textnode available" );
839 
840     sal_uInt16 nScaleWidth;
841     if( pTNd )
842     {
843         SwTextFrame *const pFrame(static_cast<SwTextFrame *>(
844                     pTNd->getLayoutFrame(GetLayout(), pStt)));
845         assert(pFrame); // shell cursor must be positioned in node with frame
846         TextFrameIndex const nStart(pFrame->MapModelToViewPos(*pStt));
847         TextFrameIndex const nEnd(
848             sw::FrameContainsNode(*pFrame, pCursor->End()->nNode.GetIndex())
849                 ? pFrame->MapModelToViewPos(*pCursor->End())
850                 : TextFrameIndex(pFrame->GetText().getLength()));
851         nScaleWidth = pFrame->GetScalingOfSelectedText(nStart, nEnd);
852     }
853     else
854         nScaleWidth = 100;              // default are no scaling -> 100%
855     return nScaleWidth;
856 }
857 
858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
859