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