merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / edit / edattr.cxx
blobf12766f6ae70ae1e7b5eb8e71080d80f1b1bfddf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: edattr.cxx,v $
10 * $Revision: 1.47 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
37 #ifndef _SVX_TSTPITEM_HXX //autogen
38 #include <svx/tstpitem.hxx>
39 #endif
40 #include <svx/lrspitem.hxx>
41 #include <svx/scripttypeitem.hxx>
42 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
43 #include <com/sun/star/i18n/ScriptType.hdl>
44 #endif
45 #include <txatbase.hxx>
46 #include <txtftn.hxx>
47 #include <fmtftn.hxx>
48 #include <editsh.hxx>
49 #include <edimp.hxx> // fuer MACROS
50 #include <doc.hxx>
51 #include <swundo.hxx> // fuer UNDO-Ids
52 #include <ndtxt.hxx>
53 #include <ftnidx.hxx>
54 #include <expfld.hxx>
55 #include <rootfrm.hxx>
56 #include <cntfrm.hxx>
57 #include <breakit.hxx>
58 #include <txtfld.hxx>
59 #include <fmtfld.hxx>
60 #include <crsskip.hxx>
61 #include <txtfrm.hxx> // SwTxtFrm
62 #include <scriptinfo.hxx>
63 #include <svtools/ctloptions.hxx>
64 #include <charfmt.hxx> // #i27615#
65 #include <numrule.hxx>
68 /*************************************
69 * harte Formatierung (Attribute)
70 *************************************/
72 // wenn Selektion groesser Max Nodes oder mehr als Max Selektionen
73 // => keine Attribute
74 const USHORT& getMaxLookup()
76 static const USHORT nMaxLookup = 1000;
77 return nMaxLookup;
80 // --> OD 2008-01-16 #newlistlevelattrs#
81 BOOL SwEditShell::GetCurAttr( SfxItemSet& rSet,
82 const bool bMergeIndentValuesOfNumRule ) const
83 // <--
85 if( GetCrsrCnt() > getMaxLookup() )
87 rSet.InvalidateAllItems();
88 return FALSE;
91 SfxItemSet aSet( *rSet.GetPool(), rSet.GetRanges() );
92 SfxItemSet *pSet = &rSet;
94 FOREACHPAM_START(this)
96 // #i27615# if the cursor is in front of the numbering label
97 // the attributes to get are those from the numbering format.
98 if (PCURCRSR->IsInFrontOfLabel())
100 SwTxtNode * pTxtNd =
101 PCURCRSR->GetPoint()->nNode.GetNode().GetTxtNode();
103 if (pTxtNd)
105 SwNumRule * pNumRule = pTxtNd->GetNumRule();
107 if (pNumRule)
109 const String & aCharFmtName =
110 pNumRule->Get(static_cast<USHORT>(pTxtNd->GetActualListLevel())).GetCharFmtName();
111 SwCharFmt * pCharFmt =
112 GetDoc()->FindCharFmtByName(aCharFmtName);
114 if (pCharFmt)
115 rSet.Put(pCharFmt->GetAttrSet());
119 continue;
122 ULONG nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
123 nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
124 xub_StrLen nSttCnt = PCURCRSR->GetMark()->nContent.GetIndex(),
125 nEndCnt = PCURCRSR->GetPoint()->nContent.GetIndex();
127 if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
129 ULONG nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
130 nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (xub_StrLen)nTmp;
133 if( nEndNd - nSttNd >= getMaxLookup() )
135 rSet.ClearItem();
136 rSet.InvalidateAllItems();
137 return FALSE;
140 // beim 1.Node traegt der Node die Werte in den GetSet ein (Initial)
141 // alle weiteren Nodes werden zum GetSet zu gemergt
142 for( ULONG n = nSttNd; n <= nEndNd; ++n )
144 SwNode* pNd = GetDoc()->GetNodes()[ n ];
145 switch( pNd->GetNodeType() )
147 case ND_TEXTNODE:
149 xub_StrLen nStt = n == nSttNd ? nSttCnt : 0,
150 nEnd = n == nEndNd ? nEndCnt
151 : ((SwTxtNode*)pNd)->GetTxt().Len();
152 // --> OD 2008-01-16 #newlistlevelattrs#
153 ((SwTxtNode*)pNd)->GetAttr( *pSet, nStt, nEnd,
154 FALSE, TRUE,
155 bMergeIndentValuesOfNumRule );
156 // <--
158 break;
159 case ND_GRFNODE:
160 case ND_OLENODE:
161 ((SwCntntNode*)pNd)->GetAttr( *pSet );
162 break;
164 default:
165 pNd = 0;
168 if( pNd )
170 if( pSet != &rSet )
171 rSet.MergeValues( aSet );
173 if( aSet.Count() )
174 aSet.ClearItem();
176 pSet = &aSet;
179 FOREACHPAM_END()
181 return TRUE;
184 SwTxtFmtColl* SwEditShell::GetCurTxtFmtColl() const
186 SwTxtFmtColl *pFmt = 0;
188 if ( GetCrsrCnt() > getMaxLookup() )
189 return 0;
191 FOREACHPAM_START(this)
193 ULONG nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
194 nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
195 xub_StrLen nSttCnt = PCURCRSR->GetMark()->nContent.GetIndex(),
196 nEndCnt = PCURCRSR->GetPoint()->nContent.GetIndex();
198 if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
200 ULONG nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
201 nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (xub_StrLen)nTmp;
204 if( nEndNd - nSttNd >= getMaxLookup() )
206 pFmt = 0;
207 break;
210 for( ULONG n = nSttNd; n <= nEndNd; ++n )
212 SwNode* pNd = GetDoc()->GetNodes()[ n ];
213 if( pNd->IsTxtNode() )
215 if( !pFmt )
216 pFmt = ((SwTxtNode*)pNd)->GetTxtColl();
217 else if( pFmt == ((SwTxtNode*)pNd)->GetTxtColl() ) // ???
218 break;
222 FOREACHPAM_END()
223 return pFmt;
228 BOOL SwEditShell::GetCurFtn( SwFmtFtn* pFillFtn )
230 // der Cursor muss auf dem akt. Fussnoten-Anker stehen:
231 SwPaM* pCrsr = GetCrsr();
232 SwTxtNode* pTxtNd = pCrsr->GetNode()->GetTxtNode();
233 if( !pTxtNd )
234 return FALSE;
236 SwTxtAttr *pFtn = pTxtNd->GetTxtAttr( pCrsr->GetPoint()->nContent,
237 RES_TXTATR_FTN );
238 if( pFtn && pFillFtn )
240 // Daten vom Attribut uebertragen
241 const SwFmtFtn &rFtn = ((SwTxtFtn*)pFtn)->GetFtn();
242 pFillFtn->SetNumber( rFtn );
243 pFillFtn->SetEndNote( rFtn.IsEndNote() );
245 return 0 != pFtn;
249 bool SwEditShell::SetCurFtn( const SwFmtFtn& rFillFtn )
251 bool bChgd = false;
252 StartAllAction();
254 SwPaM* pCrsr = GetCrsr(), *pFirst = pCrsr;
255 do {
256 bChgd |= pDoc->SetCurFtn( *pCrsr, rFillFtn.GetNumStr(),
257 rFillFtn.GetNumber(),
258 rFillFtn.IsEndNote() );
260 } while( pFirst != ( pCrsr = (SwPaM*)pCrsr->GetNext() ));
262 EndAllAction();
263 return bChgd;
268 /*USHORT SwEditShell::GetFtnCnt( BOOL bEndNotes = FALSE ) const
270 const SwFtnIdxs &rIdxs = pDoc->GetFtnIdxs();
271 USHORT nCnt = 0;
272 for ( USHORT i = 0; i < rIdxs.Count(); ++i )
274 const SwFmtFtn &rFtn = rIdxs[i]->GetFtn();
275 if ( bEndNotes == rFtn.IsEndNote() )
276 nCnt++;
278 return nCnt;
279 } */
282 bool SwEditShell::HasFtns( bool bEndNotes ) const
284 const SwFtnIdxs &rIdxs = pDoc->GetFtnIdxs();
285 for ( USHORT i = 0; i < rIdxs.Count(); ++i )
287 const SwFmtFtn &rFtn = rIdxs[i]->GetFtn();
288 if ( bEndNotes == rFtn.IsEndNote() )
289 return TRUE;
291 return FALSE;
295 // gebe Liste aller Fussnoten und deren Anfangstexte
296 USHORT SwEditShell::GetSeqFtnList( SwSeqFldList& rList, bool bEndNotes )
298 if( rList.Count() )
299 rList.Remove( 0, rList.Count() );
301 USHORT n, nFtnCnt = pDoc->GetFtnIdxs().Count();
302 SwTxtFtn* pTxtFtn;
303 for( n = 0; n < nFtnCnt; ++n )
305 pTxtFtn = pDoc->GetFtnIdxs()[ n ];
306 const SwFmtFtn& rFtn = pTxtFtn->GetFtn();
307 if ( rFtn.IsEndNote() != bEndNotes )
308 continue;
310 SwNodeIndex* pIdx = pTxtFtn->GetStartNode();
311 if( pIdx )
313 SwNodeIndex aIdx( *pIdx, 1 );
314 SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode();
315 if( !pTxtNd )
316 pTxtNd = (SwTxtNode*)pDoc->GetNodes().GoNext( &aIdx );
318 if( pTxtNd )
320 String sTxt( rFtn.GetViewNumStr( *pDoc ));
321 if( sTxt.Len() )
322 sTxt += ' ';
323 sTxt += pTxtNd->GetExpandTxt( 0, USHRT_MAX );
325 _SeqFldLstElem* pNew = new _SeqFldLstElem( sTxt,
326 pTxtFtn->GetSeqRefNo() );
327 while( rList.InsertSort( pNew ) )
328 pNew->sDlgEntry += ' ';
333 return rList.Count();
337 // linken Rand ueber Objectleiste einstellen (aenhlich dem Stufen von
338 // Numerierungen)
339 BOOL SwEditShell::IsMoveLeftMargin( BOOL bRight, BOOL bModulus ) const
341 BOOL bRet = TRUE;
343 const SvxTabStopItem& rTabItem = (SvxTabStopItem&)GetDoc()->
344 GetDefault( RES_PARATR_TABSTOP );
345 USHORT nDefDist = static_cast<USHORT>(rTabItem.Count() ? rTabItem[0].GetTabPos() : 1134);
346 if( !nDefDist )
347 return FALSE;
349 FOREACHPAM_START(this)
351 ULONG nSttNd = PCURCRSR->GetMark()->nNode.GetIndex(),
352 nEndNd = PCURCRSR->GetPoint()->nNode.GetIndex();
354 if( nSttNd > nEndNd )
356 ULONG nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
359 SwCntntNode* pCNd;
360 for( ULONG n = nSttNd; bRet && n <= nEndNd; ++n )
361 if( 0 != ( pCNd = GetDoc()->GetNodes()[ n ]->GetTxtNode() ))
363 const SvxLRSpaceItem& rLS = (SvxLRSpaceItem&)
364 pCNd->GetAttr( RES_LR_SPACE );
365 if( bRight )
367 long nNext = rLS.GetTxtLeft() + nDefDist;
368 if( bModulus )
369 nNext = ( nNext / nDefDist ) * nDefDist;
370 SwFrm* pFrm = pCNd->GetFrm();
371 if ( pFrm )
373 const USHORT nFrmWidth = static_cast<USHORT>( pFrm->IsVertical() ?
374 pFrm->Frm().Height() :
375 pFrm->Frm().Width() );
376 bRet = nFrmWidth > ( nNext + MM50 );
378 else
379 bRet = FALSE;
383 if( !bRet )
384 break;
386 FOREACHPAM_END()
387 return bRet;
390 void SwEditShell::MoveLeftMargin( BOOL bRight, BOOL bModulus )
392 StartAllAction();
393 StartUndo( UNDO_START );
395 SwPaM* pCrsr = GetCrsr();
396 if( pCrsr->GetNext() != pCrsr ) // Mehrfachselektion ?
398 SwPamRanges aRangeArr( *pCrsr );
399 SwPaM aPam( *pCrsr->GetPoint() );
400 for( USHORT n = 0; n < aRangeArr.Count(); ++n )
401 GetDoc()->MoveLeftMargin( aRangeArr.SetPam( n, aPam ),
402 bRight, bModulus );
404 else
405 GetDoc()->MoveLeftMargin( *pCrsr, bRight, bModulus );
407 EndUndo( UNDO_END );
408 EndAllAction();
412 inline USHORT lcl_SetScriptFlags( USHORT nType )
414 USHORT nRet;
415 switch( nType )
417 case ::com::sun::star::i18n::ScriptType::LATIN: nRet = SCRIPTTYPE_LATIN; break;
418 case ::com::sun::star::i18n::ScriptType::ASIAN: nRet = SCRIPTTYPE_ASIAN; break;
419 case ::com::sun::star::i18n::ScriptType::COMPLEX: nRet = SCRIPTTYPE_COMPLEX; break;
420 default: nRet = 0;
422 return nRet;
425 BOOL lcl_IsNoEndTxtAttrAtPos( const SwTxtNode& rTNd, xub_StrLen nPos,
426 USHORT &rScrpt, BOOL bInSelection, BOOL bNum )
428 BOOL bRet = FALSE;
429 const String& rTxt = rTNd.GetTxt();
430 String sExp;
432 // consider numbering
433 if ( bNum )
435 bRet = FALSE;
437 // --> OD 2008-03-19 #refactorlists#
438 if ( rTNd.IsInList() )
440 ASSERT( rTNd.GetNumRule(),
441 "<lcl_IsNoEndTxtAttrAtPos(..)> - no list style found at text node. Serious defect -> please inform OD." );
442 const SwNumRule* pNumRule = rTNd.GetNumRule();
443 const SwNumFmt &rNumFmt = pNumRule->Get( static_cast<USHORT>(rTNd.GetActualListLevel()) );
444 if( SVX_NUM_BITMAP != rNumFmt.GetNumberingType() )
446 if ( SVX_NUM_CHAR_SPECIAL == rNumFmt.GetNumberingType() )
447 sExp = rNumFmt.GetBulletChar();
448 else
449 sExp = rTNd.GetNumString();
454 // and fields
455 if ( CH_TXTATR_BREAKWORD == rTxt.GetChar( nPos ) )
457 const SwTxtAttr* const pAttr = rTNd.GetTxtAttrForCharAt( nPos );
458 if (pAttr)
460 bRet = TRUE; // all other than fields can be
461 // defined as weak-script ?
462 if ( RES_TXTATR_FIELD == pAttr->Which() )
464 const SwField* const pFld = pAttr->GetFld().GetFld();
465 if (pFld)
467 sExp += pFld->Expand();
473 xub_StrLen nEnd = sExp.Len();
474 if ( nEnd )
476 xub_StrLen n;
477 if( bInSelection )
479 USHORT nScript;
480 for( n = 0; n < nEnd; n = (xub_StrLen)
481 pBreakIt->GetBreakIter()->endOfScript( sExp, n, nScript ))
483 nScript = pBreakIt->GetBreakIter()->getScriptType( sExp, n );
484 rScrpt |= lcl_SetScriptFlags( nScript );
487 else
488 rScrpt |= lcl_SetScriptFlags( pBreakIt->GetBreakIter()->
489 getScriptType( sExp, nEnd-1 ));
492 return bRet;
496 // returns the scripttpye of the selection
497 USHORT SwEditShell::GetScriptType() const
499 USHORT nRet = 0;
500 //if( pBreakIt->GetBreakIter().is() )
502 FOREACHPAM_START(this)
504 const SwPosition *pStt = PCURCRSR->Start(),
505 *pEnd = pStt == PCURCRSR->GetMark()
506 ? PCURCRSR->GetPoint()
507 : PCURCRSR->GetMark();
508 if( pStt == pEnd || *pStt == *pEnd )
510 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
511 if( pTNd )
513 // try to get SwScriptInfo
514 const SwScriptInfo* pScriptInfo = SwScriptInfo::GetScriptInfo( *pTNd );
516 xub_StrLen nPos = pStt->nContent.GetIndex();
517 //Task 90448: we need the scripttype of the previous
518 // position, if no selection exist!
519 if( nPos )
521 SwIndex aIdx( pStt->nContent );
522 if( pTNd->GoPrevious( &aIdx, CRSR_SKIP_CHARS ) )
523 nPos = aIdx.GetIndex();
526 USHORT nScript;
528 if ( pTNd->GetTxt().Len() )
530 nScript = pScriptInfo ?
531 pScriptInfo->ScriptType( nPos ) :
532 pBreakIt->GetBreakIter()->getScriptType( pTNd->GetTxt(), nPos );
534 else
535 nScript = GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() );
537 if( !lcl_IsNoEndTxtAttrAtPos( *pTNd, nPos, nRet, FALSE, FALSE ))
538 nRet |= lcl_SetScriptFlags( nScript );
541 else if ( pBreakIt->GetBreakIter().is() )
543 ULONG nEndIdx = pEnd->nNode.GetIndex();
544 SwNodeIndex aIdx( pStt->nNode );
545 for( ; aIdx.GetIndex() <= nEndIdx; aIdx++ )
546 if( aIdx.GetNode().IsTxtNode() )
548 const SwTxtNode* pTNd = aIdx.GetNode().GetTxtNode();
549 const String& rTxt = pTNd->GetTxt();
551 // try to get SwScriptInfo
552 const SwScriptInfo* pScriptInfo = SwScriptInfo::GetScriptInfo( *pTNd );
554 xub_StrLen nChg = aIdx == pStt->nNode
555 ? pStt->nContent.GetIndex()
556 : 0,
557 nEndPos = aIdx == nEndIdx
558 ? pEnd->nContent.GetIndex()
559 : rTxt.Len();
561 ASSERT( nEndPos <= rTxt.Len(), "Index outside the range - endless loop!" );
562 if( nEndPos > rTxt.Len() )
563 nEndPos = rTxt.Len();
565 USHORT nScript;
566 while( nChg < nEndPos )
568 nScript = pScriptInfo ?
569 pScriptInfo->ScriptType( nChg ) :
570 pBreakIt->GetBreakIter()->getScriptType(
571 rTxt, nChg );
573 if( !lcl_IsNoEndTxtAttrAtPos( *pTNd, nChg, nRet, TRUE,
574 0 == nChg && rTxt.Len() == nEndPos ) )
575 nRet |= lcl_SetScriptFlags( nScript );
577 if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
578 SCRIPTTYPE_COMPLEX) == nRet )
579 break;
581 xub_StrLen nFldPos = nChg+1;
583 nChg = pScriptInfo ?
584 pScriptInfo->NextScriptChg( nChg ) :
585 (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(
586 rTxt, nChg, nScript );
588 nFldPos = rTxt.Search(
589 CH_TXTATR_BREAKWORD, nFldPos );
590 if( nFldPos < nChg )
591 nChg = nFldPos;
593 if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
594 SCRIPTTYPE_COMPLEX) == nRet )
595 break;
598 if( (SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN |
599 SCRIPTTYPE_COMPLEX) == nRet )
600 break;
602 FOREACHPAM_END()
604 if( !nRet )
605 nRet = SvtLanguageOptions::GetScriptTypeOfLanguage( LANGUAGE_SYSTEM );
606 return nRet;
610 USHORT SwEditShell::GetCurLang() const
612 const SwPaM* pCrsr = GetCrsr();
613 const SwPosition& rPos = *pCrsr->GetPoint();
614 const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
615 USHORT nLang;
616 if( pTNd )
618 //JP 24.9.2001: if exist no selection, then get the language before
619 // the current character!
620 xub_StrLen nPos = rPos.nContent.GetIndex();
621 if( nPos && !pCrsr->HasMark() )
622 --nPos;
623 nLang = pTNd->GetLang( nPos );
625 else
626 nLang = LANGUAGE_DONTKNOW;
627 return nLang;
630 USHORT SwEditShell::GetScalingOfSelectedText() const
632 const SwPaM* pCrsr = GetCrsr();
633 const SwPosition* pStt = pCrsr->Start();
634 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
635 ASSERT( pTNd, "no textnode available" );
637 USHORT nScaleWidth;
638 if( pTNd )
640 xub_StrLen nStt = pStt->nContent.GetIndex(), nEnd;
641 const SwPosition* pEnd = pStt == pCrsr->GetPoint()
642 ? pCrsr->GetMark()
643 : pCrsr->GetPoint();
644 if( pStt->nNode == pEnd->nNode )
645 nEnd = pEnd->nContent.GetIndex();
646 else
647 nEnd = pTNd->GetTxt().Len();
648 nScaleWidth = pTNd->GetScalingOfSelectedText( nStt, nEnd );
650 else
651 nScaleWidth = 100; // default are no scaling -> 100%
652 return nScaleWidth;