xref: /trunk/main/sw/source/core/edit/edattr.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 
34 #include <editeng/tstpitem.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/scripttypeitem.hxx>
37 #include <com/sun/star/i18n/ScriptType.hdl>
38 #include <txatbase.hxx>
39 #include <txtftn.hxx>
40 #include <fmtftn.hxx>
41 #include <editsh.hxx>
42 #include <edimp.hxx>    // fuer MACROS
43 #include <doc.hxx>
44 #include <swundo.hxx>   // fuer UNDO-Ids
45 #include <ndtxt.hxx>
46 #include <ftnidx.hxx>
47 #include <expfld.hxx>
48 #include <rootfrm.hxx>
49 #include <cntfrm.hxx>
50 #include <breakit.hxx>
51 #include <txtfld.hxx>
52 #include <fmtfld.hxx>
53 #include <crsskip.hxx>
54 #include <txtfrm.hxx>       // SwTxtFrm
55 #include <scriptinfo.hxx>
56 #include <svl/ctloptions.hxx>
57 #include <charfmt.hxx>  // #i27615#
58 #include <numrule.hxx>
59 
60 
61 /*************************************
62  * harte Formatierung (Attribute)
63  *************************************/
64 
65 // wenn Selektion groesser Max Nodes oder mehr als Max Selektionen
66 // => keine Attribute
67 const sal_uInt16& getMaxLookup()
68 {
69     static const sal_uInt16 nMaxLookup = 1000;
70     return nMaxLookup;
71 }
72 
73 // --> OD 2008-01-16 #newlistlevelattrs#
74 sal_Bool SwEditShell::GetCurAttr( SfxItemSet& rSet,
75                               const bool bMergeIndentValuesOfNumRule ) const
76 // <--
77 {
78     if( GetCrsrCnt() > getMaxLookup() )
79     {
80         rSet.InvalidateAllItems();
81         return sal_False;
82     }
83 
84     SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
85     SfxItemSet *pSet = &rSet;
86 
87     FOREACHPAM_START(this)
88 
89         // #i27615# if the cursor is in front of the numbering label
90         // the attributes to get are those from the numbering format.
91         if (PCURCRSR->IsInFrontOfLabel())
92         {
93             SwTxtNode * pTxtNd =
94                 PCURCRSR->GetPoint()->nNode.GetNode().GetTxtNode();
95 
96             if (pTxtNd)
97             {
98                 SwNumRule * pNumRule = pTxtNd->GetNumRule();
99 
100                 if (pNumRule)
101                 {
102                     const String & aCharFmtName =
103                         pNumRule->Get(static_cast<sal_uInt16>(pTxtNd->GetActualListLevel())).GetCharFmtName();
104                     SwCharFmt * pCharFmt =
105                         GetDoc()->FindCharFmtByName(aCharFmtName);
106 
107                     if (pCharFmt)
108                         rSet.Put(pCharFmt->GetAttrSet());
109                 }
110             }
111 
112             continue;
113         }
114 
115         sal_uLong nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
116               nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
117         xub_StrLen nSttCnt = PCURCRSR->GetMark()->nContent.GetIndex(),
118                    nEndCnt = PCURCRSR->GetPoint()->nContent.GetIndex();
119 
120         if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
121         {
122             sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
123             nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (xub_StrLen)nTmp;
124         }
125 
126         if( nEndNd - nSttNd >= getMaxLookup() )
127         {
128             rSet.ClearItem();
129             rSet.InvalidateAllItems();
130             return sal_False;
131         }
132 
133         // beim 1.Node traegt der Node die Werte in den GetSet ein (Initial)
134         // alle weiteren Nodes werden zum GetSet zu gemergt
135         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
136         {
137             SwNode* pNd = GetDoc()->GetNodes()[ n ];
138             switch( pNd->GetNodeType() )
139             {
140             case ND_TEXTNODE:
141                 {
142                     xub_StrLen nStt = n == nSttNd ? nSttCnt : 0,
143                                nEnd = n == nEndNd ? nEndCnt
144                                         : ((SwTxtNode*)pNd)->GetTxt().Len();
145                     // --> OD 2008-01-16 #newlistlevelattrs#
146                     ((SwTxtNode*)pNd)->GetAttr( *pSet, nStt, nEnd,
147                                                 sal_False, sal_True,
148                                                 bMergeIndentValuesOfNumRule );
149                     // <--
150                 }
151                 break;
152             case ND_GRFNODE:
153             case ND_OLENODE:
154                 ((SwCntntNode*)pNd)->GetAttr( *pSet );
155                 break;
156 
157             default:
158                 pNd = 0;
159             }
160 
161             if( pNd )
162             {
163                 if( pSet != &rSet )
164                     rSet.MergeValues( aSet );
165 
166                 if( aSet.Count() )
167                     aSet.ClearItem();
168             }
169             pSet = &aSet;
170         }
171 
172     FOREACHPAM_END()
173 
174     return sal_True;
175 }
176 
177 SwTxtFmtColl* SwEditShell::GetCurTxtFmtColl() const
178 {
179     SwTxtFmtColl *pFmt = 0;
180 
181     if ( GetCrsrCnt() > getMaxLookup() )
182         return 0;
183 
184     FOREACHPAM_START(this)
185 
186         sal_uLong nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
187               nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
188         xub_StrLen nSttCnt = PCURCRSR->GetMark()->nContent.GetIndex(),
189                    nEndCnt = PCURCRSR->GetPoint()->nContent.GetIndex();
190 
191         if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
192         {
193             sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
194             nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (xub_StrLen)nTmp;
195         }
196 
197         if( nEndNd - nSttNd >= getMaxLookup() )
198         {
199             pFmt = 0;
200             break;
201         }
202 
203         for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
204         {
205             SwNode* pNd = GetDoc()->GetNodes()[ n ];
206             if( pNd->IsTxtNode() )
207             {
208                 if( !pFmt )
209                     pFmt = ((SwTxtNode*)pNd)->GetTxtColl();
210                 else if( pFmt == ((SwTxtNode*)pNd)->GetTxtColl() ) // ???
211                     break;
212             }
213         }
214 
215     FOREACHPAM_END()
216     return pFmt;
217 }
218 
219 
220 
221 sal_Bool SwEditShell::GetCurFtn( SwFmtFtn* pFillFtn )
222 {
223     // der Cursor muss auf dem akt. Fussnoten-Anker stehen:
224     SwPaM* pCrsr = GetCrsr();
225     SwTxtNode* pTxtNd = pCrsr->GetNode()->GetTxtNode();
226     if( !pTxtNd )
227         return sal_False;
228 
229     SwTxtAttr *const pFtn = pTxtNd->GetTxtAttrForCharAt(
230         pCrsr->GetPoint()->nContent.GetIndex(), RES_TXTATR_FTN);
231     if( pFtn && pFillFtn )
232     {
233         // Daten vom Attribut uebertragen
234         const SwFmtFtn &rFtn = ((SwTxtFtn*)pFtn)->GetFtn();
235         pFillFtn->SetNumber( rFtn );
236         pFillFtn->SetEndNote( rFtn.IsEndNote() );
237     }
238     return 0 != pFtn;
239 }
240 
241 
242 bool SwEditShell::SetCurFtn( const SwFmtFtn& rFillFtn )
243 {
244     bool bChgd = false;
245     StartAllAction();
246 
247     SwPaM* pCrsr = GetCrsr(), *pFirst = pCrsr;
248     do {
249         bChgd |=  pDoc->SetCurFtn( *pCrsr, rFillFtn.GetNumStr(),
250                                             rFillFtn.GetNumber(),
251                                             rFillFtn.IsEndNote() );
252 
253     } while( pFirst != ( pCrsr = (SwPaM*)pCrsr->GetNext() ));
254 
255     EndAllAction();
256     return bChgd;
257 }
258 
259 
260 
261 /*sal_uInt16 SwEditShell::GetFtnCnt( sal_Bool bEndNotes = sal_False ) const
262 {
263     const SwFtnIdxs &rIdxs = pDoc->GetFtnIdxs();
264     sal_uInt16 nCnt = 0;
265     for ( sal_uInt16 i = 0; i < rIdxs.Count(); ++i )
266     {
267         const SwFmtFtn &rFtn = rIdxs[i]->GetFtn();
268         if ( bEndNotes == rFtn.IsEndNote() )
269             nCnt++;
270     }
271     return nCnt;
272 } */
273 
274 
275 bool SwEditShell::HasFtns( bool bEndNotes ) const
276 {
277     const SwFtnIdxs &rIdxs = pDoc->GetFtnIdxs();
278     for ( sal_uInt16 i = 0; i < rIdxs.Count(); ++i )
279     {
280         const SwFmtFtn &rFtn = rIdxs[i]->GetFtn();
281         if ( bEndNotes == rFtn.IsEndNote() )
282             return sal_True;
283     }
284     return sal_False;
285 }
286 
287 
288     // gebe Liste aller Fussnoten und deren Anfangstexte
289 sal_uInt16 SwEditShell::GetSeqFtnList( SwSeqFldList& rList, bool bEndNotes )
290 {
291     if( rList.Count() )
292         rList.Remove( 0, rList.Count() );
293 
294     sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
295     SwTxtFtn* pTxtFtn;
296     for( n = 0; n < nFtnCnt; ++n )
297     {
298         pTxtFtn = pDoc->GetFtnIdxs()[ n ];
299         const SwFmtFtn& rFtn = pTxtFtn->GetFtn();
300         if ( rFtn.IsEndNote() != bEndNotes )
301             continue;
302 
303         SwNodeIndex* pIdx = pTxtFtn->GetStartNode();
304         if( pIdx )
305         {
306             SwNodeIndex aIdx( *pIdx, 1 );
307             SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode();
308             if( !pTxtNd )
309                 pTxtNd = (SwTxtNode*)pDoc->GetNodes().GoNext( &aIdx );
310 
311             if( pTxtNd )
312             {
313                 String sTxt( rFtn.GetViewNumStr( *pDoc ));
314                 if( sTxt.Len() )
315                     sTxt += ' ';
316                 sTxt += pTxtNd->GetExpandTxt( 0, USHRT_MAX );
317 
318                 _SeqFldLstElem* pNew = new _SeqFldLstElem( sTxt,
319                                             pTxtFtn->GetSeqRefNo() );
320                 while( rList.InsertSort( pNew ) )
321                     pNew->sDlgEntry += ' ';
322             }
323         }
324     }
325 
326     return rList.Count();
327 }
328 
329 
330 // linken Rand ueber Objectleiste einstellen (aenhlich dem Stufen von
331 // Numerierungen)
332 sal_Bool SwEditShell::IsMoveLeftMargin( sal_Bool bRight, sal_Bool bModulus ) const
333 {
334     sal_Bool bRet = sal_True;
335 
336     const SvxTabStopItem& rTabItem = (SvxTabStopItem&)GetDoc()->
337                                 GetDefault( RES_PARATR_TABSTOP );
338     sal_uInt16 nDefDist = static_cast<sal_uInt16>(rTabItem.Count() ? rTabItem[0].GetTabPos() : 1134);
339     if( !nDefDist )
340         return sal_False;
341 
342     FOREACHPAM_START(this)
343 
344         sal_uLong nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
345               nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
346 
347         if( nSttNd > nEndNd )
348         {
349             sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
350         }
351 
352         SwCntntNode* pCNd;
353         for( sal_uLong n = nSttNd; bRet && n <= nEndNd; ++n )
354             if( 0 != ( pCNd = GetDoc()->GetNodes()[ n ]->GetTxtNode() ))
355             {
356                 const SvxLRSpaceItem& rLS = (SvxLRSpaceItem&)
357                                             pCNd->GetAttr( RES_LR_SPACE );
358                 if( bRight )
359                 {
360                     long nNext = rLS.GetTxtLeft() + nDefDist;
361                     if( bModulus )
362                         nNext = ( nNext / nDefDist ) * nDefDist;
363                     SwFrm* pFrm = pCNd->getLayoutFrm( GetLayout() );
364                     if ( pFrm )
365                     {
366                         const sal_uInt16 nFrmWidth = static_cast<sal_uInt16>( pFrm->IsVertical() ?
367                                                  pFrm->Frm().Height() :
368                                                  pFrm->Frm().Width() );
369                         bRet = nFrmWidth > ( nNext + MM50 );
370                     }
371                     else
372                         bRet = sal_False;
373                 }
374             }
375 
376         if( !bRet )
377             break;
378 
379     FOREACHPAM_END()
380     return bRet;
381 }
382 
383 void SwEditShell::MoveLeftMargin( sal_Bool bRight, sal_Bool bModulus )
384 {
385     StartAllAction();
386     StartUndo( UNDO_START );
387 
388     SwPaM* pCrsr = GetCrsr();
389     if( pCrsr->GetNext() != pCrsr )         // Mehrfachselektion ?
390     {
391         SwPamRanges aRangeArr( *pCrsr );
392         SwPaM aPam( *pCrsr->GetPoint() );
393         for( sal_uInt16 n = 0; n < aRangeArr.Count(); ++n )
394             GetDoc()->MoveLeftMargin( aRangeArr.SetPam( n, aPam ),
395                                         bRight, bModulus );
396     }
397     else
398         GetDoc()->MoveLeftMargin( *pCrsr, bRight, bModulus );
399 
400     EndUndo( UNDO_END );
401     EndAllAction();
402 }
403 
404 
405 inline sal_uInt16 lcl_SetScriptFlags( sal_uInt16 nType )
406 {
407     sal_uInt16 nRet;
408     switch( nType )
409     {
410     case ::com::sun::star::i18n::ScriptType::LATIN:     nRet = SCRIPTTYPE_LATIN;    break;
411     case ::com::sun::star::i18n::ScriptType::ASIAN:     nRet = SCRIPTTYPE_ASIAN;    break;
412     case ::com::sun::star::i18n::ScriptType::COMPLEX:   nRet = SCRIPTTYPE_COMPLEX;  break;
413     default: nRet = 0;
414     }
415     return nRet;
416 }
417 
418 sal_Bool lcl_IsNoEndTxtAttrAtPos( const SwTxtNode& rTNd, xub_StrLen nPos,
419                             sal_uInt16 &rScrpt, sal_Bool bInSelection, sal_Bool bNum )
420 {
421     sal_Bool bRet = sal_False;
422     const String& rTxt = rTNd.GetTxt();
423     String sExp;
424 
425     // consider numbering
426     if ( bNum )
427     {
428         bRet = sal_False;
429 
430         // --> OD 2008-03-19 #refactorlists#
431         if ( rTNd.IsInList() )
432         {
433             ASSERT( rTNd.GetNumRule(),
434                     "<lcl_IsNoEndTxtAttrAtPos(..)> - no list style found at text node. Serious defect -> please inform OD." );
435             const SwNumRule* pNumRule = rTNd.GetNumRule();
436             const SwNumFmt &rNumFmt = pNumRule->Get( static_cast<sal_uInt16>(rTNd.GetActualListLevel()) );
437             if( SVX_NUM_BITMAP != rNumFmt.GetNumberingType() )
438             {
439                 if ( SVX_NUM_CHAR_SPECIAL == rNumFmt.GetNumberingType() )
440                     sExp = rNumFmt.GetBulletChar();
441                 else
442                     sExp = rTNd.GetNumString();
443             }
444         }
445     }
446 
447     // and fields
448     if ( CH_TXTATR_BREAKWORD == rTxt.GetChar( nPos ) )
449     {
450         const SwTxtAttr* const pAttr = rTNd.GetTxtAttrForCharAt( nPos );
451         if (pAttr)
452         {
453             bRet = sal_True; // all other than fields can be
454                          // defined as weak-script ?
455             if ( RES_TXTATR_FIELD == pAttr->Which() )
456             {
457                 const SwField* const pFld = pAttr->GetFld().GetFld();
458                 if (pFld)
459                 {
460                     sExp += pFld->ExpandField(true);
461                 }
462             }
463         }
464     }
465 
466     xub_StrLen nEnd = sExp.Len();
467     if ( nEnd )
468     {
469         xub_StrLen n;
470         if( bInSelection )
471         {
472             sal_uInt16 nScript;
473             for( n = 0; n < nEnd; n = (xub_StrLen)
474                     pBreakIt->GetBreakIter()->endOfScript( sExp, n, nScript ))
475             {
476                 nScript = pBreakIt->GetBreakIter()->getScriptType( sExp, n );
477                 rScrpt |= lcl_SetScriptFlags( nScript );
478             }
479         }
480         else
481             rScrpt |= lcl_SetScriptFlags( pBreakIt->GetBreakIter()->
482                                         getScriptType( sExp, nEnd-1 ));
483     }
484 
485     return bRet;
486 }
487 
488 
489 // returns the scripttpye of the selection
490 sal_uInt16 SwEditShell::GetScriptType() const
491 {
492     sal_uInt16 nRet = 0;
493     //if( pBreakIt->GetBreakIter().is() )
494     {
495         FOREACHPAM_START(this)
496 
497             const SwPosition *pStt = PCURCRSR->Start(),
498                              *pEnd = pStt == PCURCRSR->GetMark()
499                                     ? PCURCRSR->GetPoint()
500                                     : PCURCRSR->GetMark();
501             if( pStt == pEnd || *pStt == *pEnd )
502             {
503                 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
504                 if( pTNd )
505                 {
506                     // try to get SwScriptInfo
507                     const SwScriptInfo* pScriptInfo = SwScriptInfo::GetScriptInfo( *pTNd );
508 
509                     xub_StrLen nPos = pStt->nContent.GetIndex();
510                     //Task 90448: we need the scripttype of the previous
511                     //              position, if no selection exist!
512                     if( nPos )
513                     {
514                         SwIndex aIdx( pStt->nContent );
515                         if( pTNd->GoPrevious( &aIdx, CRSR_SKIP_CHARS ) )
516                             nPos = aIdx.GetIndex();
517                     }
518 
519                     sal_uInt16 nScript;
520 
521                     if ( pTNd->GetTxt().Len() )
522                     {
523                         nScript = pScriptInfo ?
524                                   pScriptInfo->ScriptType( nPos ) :
525                                   pBreakIt->GetBreakIter()->getScriptType( pTNd->GetTxt(), nPos );
526                     }
527                     else
528                         nScript = GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() );
529 
530                     if( !lcl_IsNoEndTxtAttrAtPos( *pTNd, nPos, nRet, sal_False, sal_False ))
531                         nRet |= lcl_SetScriptFlags( nScript );
532                 }
533             }
534             else if ( pBreakIt->GetBreakIter().is() )
535             {
536                 sal_uLong nEndIdx = pEnd->nNode.GetIndex();
537                 SwNodeIndex aIdx( pStt->nNode );
538                 for( ; aIdx.GetIndex() <= nEndIdx; aIdx++ )
539                     if( aIdx.GetNode().IsTxtNode() )
540                     {
541                         const SwTxtNode* pTNd = aIdx.GetNode().GetTxtNode();
542                         const String& rTxt = pTNd->GetTxt();
543 
544                         // try to get SwScriptInfo
545                         const SwScriptInfo* pScriptInfo = SwScriptInfo::GetScriptInfo( *pTNd );
546 
547                         xub_StrLen nChg = aIdx == pStt->nNode
548                                                 ? pStt->nContent.GetIndex()
549                                                 : 0,
550                                     nEndPos = aIdx == nEndIdx
551                                                 ? pEnd->nContent.GetIndex()
552                                                 : rTxt.Len();
553 
554                         ASSERT( nEndPos <= rTxt.Len(), "Index outside the range - endless loop!" );
555                         if( nEndPos > rTxt.Len() )
556                             nEndPos = rTxt.Len();
557 
558                         sal_uInt16 nScript;
559                         while( nChg < nEndPos )
560                         {
561                             nScript = pScriptInfo ?
562                                       pScriptInfo->ScriptType( nChg ) :
563                                       pBreakIt->GetBreakIter()->getScriptType(
564                                                                 rTxt, nChg );
565 
566                             if( !lcl_IsNoEndTxtAttrAtPos( *pTNd, nChg, nRet, sal_True,
567                                                           0 == nChg && rTxt.Len() == nEndPos ) )
568                                 nRet |= lcl_SetScriptFlags( nScript );
569 
570                             if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
571                                 SCRIPTTYPE_COMPLEX) == nRet )
572                                 break;
573 
574                             xub_StrLen nFldPos = nChg+1;
575 
576                             nChg = pScriptInfo ?
577                                    pScriptInfo->NextScriptChg( nChg ) :
578                                    (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(
579                                                     rTxt, nChg, nScript );
580 
581                             nFldPos = rTxt.Search(
582                                             CH_TXTATR_BREAKWORD, nFldPos );
583                             if( nFldPos < nChg )
584                                 nChg = nFldPos;
585                         }
586                         if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
587                                 SCRIPTTYPE_COMPLEX) == nRet )
588                             break;
589                     }
590             }
591             if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
592                                 SCRIPTTYPE_COMPLEX) == nRet )
593                 break;
594 
595         FOREACHPAM_END()
596     }
597     if( !nRet )
598         nRet = SvtLanguageOptions::GetScriptTypeOfLanguage( LANGUAGE_SYSTEM );
599     return nRet;
600 }
601 
602 
603 sal_uInt16 SwEditShell::GetCurLang() const
604 {
605     const SwPaM* pCrsr = GetCrsr();
606     const SwPosition& rPos = *pCrsr->GetPoint();
607     const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
608     sal_uInt16 nLang;
609     if( pTNd )
610     {
611         //JP 24.9.2001: if exist no selection, then get the language before
612         //              the current character!
613         xub_StrLen nPos = rPos.nContent.GetIndex();
614         if( nPos && !pCrsr->HasMark() )
615             --nPos;
616         nLang = pTNd->GetLang( nPos );
617     }
618     else
619         nLang = LANGUAGE_DONTKNOW;
620     return nLang;
621 }
622 
623 sal_uInt16 SwEditShell::GetScalingOfSelectedText() const
624 {
625     const SwPaM* pCrsr = GetCrsr();
626     const SwPosition* pStt = pCrsr->Start();
627     const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
628     ASSERT( pTNd, "no textnode available" );
629 
630     sal_uInt16 nScaleWidth;
631     if( pTNd )
632     {
633         xub_StrLen nStt = pStt->nContent.GetIndex(), nEnd;
634         const SwPosition* pEnd = pStt == pCrsr->GetPoint()
635                                         ? pCrsr->GetMark()
636                                         : pCrsr->GetPoint();
637         if( pStt->nNode == pEnd->nNode )
638             nEnd = pEnd->nContent.GetIndex();
639         else
640             nEnd = pTNd->GetTxt().Len();
641         nScaleWidth = pTNd->GetScalingOfSelectedText( nStt, nEnd );
642     }
643     else
644         nScaleWidth = 100;              // default are no scaling -> 100%
645     return nScaleWidth;
646 }
647