merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / text / txtfld.cxx
blob4eae178d3e60172bee50ed3bdecee50f44879747
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: txtfld.cxx,v $
10 * $Revision: 1.30.136.1 $
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"
36 #include <fmtfld.hxx>
37 #include <txtfld.hxx>
38 #include <charfmt.hxx>
40 #include "viewsh.hxx" // NewFldPortion, GetDoc()
41 #include "doc.hxx" // NewFldPortion, GetSysFldType()
42 #include "rootfrm.hxx" // Info ueber virt. PageNumber
43 #include "pagefrm.hxx" // NewFldPortion, GetVirtPageNum()
44 #include "ndtxt.hxx" // NewNumberPortion, pHints->GetNum()
45 #include "fldbas.hxx" // SwField
46 #include "viewopt.hxx" // SwViewOptions
47 #include "flyfrm.hxx" //IsInBody()
48 #include "viewimp.hxx"
49 #include "txtatr.hxx" // SwTxtFld
50 #include "txtcfg.hxx"
51 #include "swfont.hxx" // NewFldPortion, new SwFont
52 #include "fntcache.hxx" // NewFldPortion, SwFntAccess
53 #include "porfld.hxx"
54 #include "porftn.hxx" // NewExtraPortion
55 #include "porref.hxx" // NewExtraPortion
56 #include "portox.hxx" // NewExtraPortion
57 #include "porhyph.hxx" // NewExtraPortion
58 #include "porfly.hxx" // NewExtraPortion
59 #include "itrform2.hxx" // SwTxtFormatter
60 #include "chpfld.hxx"
61 #include "dbfld.hxx"
62 #include "expfld.hxx"
63 #include "docufld.hxx"
64 #include "pagedesc.hxx" // NewFldPortion, GetNum()
65 #include <pormulti.hxx> // SwMultiPortion
66 #include "fmtmeta.hxx" // lcl_NewMetaPortion
69 /*************************************************************************
70 * SwTxtFormatter::NewFldPortion()
71 *************************************************************************/
74 sal_Bool lcl_IsInBody( SwFrm *pFrm )
76 if ( pFrm->IsInDocBody() )
77 return sal_True;
78 else
80 const SwFrm *pTmp = pFrm;
81 const SwFlyFrm *pFly;
82 while ( 0 != (pFly = pTmp->FindFlyFrm()) )
83 pTmp = pFly->GetAnchorFrm();
84 return pTmp->IsInDocBody();
89 SwExpandPortion *SwTxtFormatter::NewFldPortion( SwTxtFormatInfo &rInf,
90 const SwTxtAttr *pHint ) const
92 SwExpandPortion *pRet = 0;
93 SwFrm *pFrame = (SwFrm*)pFrm;
94 SwField *pFld = (SwField*)pHint->GetFld().GetFld();
95 const sal_Bool bName = rInf.GetOpt().IsFldName();
97 SwCharFmt* pChFmt = 0;
98 sal_Bool bNewFlyPor = sal_False,
99 bINet = sal_False;
101 // set language
102 ((SwTxtFormatter*)this)->SeekAndChg( rInf );
103 if (pFld->GetLanguage() != GetFnt()->GetLanguage())
105 pFld->SetLanguage( GetFnt()->GetLanguage() );
106 // let the visual note know about its new language
107 if (pFld->GetTyp()->Which()==RES_POSTITFLD)
108 const_cast<SwFmtFld*> (&pHint->GetFld())->Broadcast( SwFmtFldHint( &pHint->GetFld(), SWFMTFLD_LANGUAGE ) );
111 ViewShell *pSh = rInf.GetVsh();
112 sal_Bool bPlaceHolder = sal_False;
114 switch( pFld->GetTyp()->Which() )
116 case RES_SCRIPTFLD:
117 case RES_POSTITFLD:
118 pRet = new SwPostItsPortion( RES_SCRIPTFLD == pFld->GetTyp()->Which() );
119 break;
121 case RES_COMBINED_CHARS:
123 String sStr( pFld->GetCntnt( bName ));
124 if( bName )
125 pRet = new SwFldPortion( sStr );
126 else
127 pRet = new SwCombinedPortion( sStr );
129 break;
131 case RES_HIDDENTXTFLD:
132 pRet = new SwHiddenPortion(pFld->GetCntnt( bName ));
133 break;
135 case RES_CHAPTERFLD:
136 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
138 ((SwChapterField*)pFld)->ChangeExpansion( pFrame,
139 &((SwTxtFld*)pHint)->GetTxtNode() );
141 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
142 break;
144 case RES_DOCSTATFLD:
145 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
146 ((SwDocStatField*)pFld)->ChangeExpansion( pFrame );
147 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
148 break;
150 case RES_PAGENUMBERFLD:
152 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
154 SwPageNumberFieldType *pPageNr = (SwPageNumberFieldType *)pFld->GetTyp();
156 const SwRootFrm* pTmpRootFrm = pSh->GetLayout();
157 const sal_Bool bVirt = pTmpRootFrm->IsVirtPageNum();
159 SwDoc* pDoc = pSh->GetDoc();
160 MSHORT nVirtNum = pFrame->GetVirtPageNum();
161 MSHORT nNumPages = pTmpRootFrm->GetPageNum();
162 sal_Int16 nNumFmt = -1;
163 if(SVX_NUM_PAGEDESC == pFld->GetFormat())
164 nNumFmt = pFrame->FindPageFrm()->GetPageDesc()->GetNumType().GetNumberingType();
166 pPageNr->ChangeExpansion( pDoc, nVirtNum, nNumPages,
167 bVirt, nNumFmt > -1 ? &nNumFmt : 0);
169 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
170 break;
172 case RES_GETEXPFLD:
174 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
176 SwGetExpField* pExpFld = (SwGetExpField*)pFld;
177 if( !::lcl_IsInBody( pFrame ) )
179 pExpFld->ChgBodyTxtFlag( sal_False );
180 pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) );
182 else if( !pExpFld->IsInBodyTxt() )
184 // war vorher anders, also erst expandieren, dann umsetzen!!
185 pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) );
186 pExpFld->ChgBodyTxtFlag( sal_True );
189 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
190 break;
192 case RES_DBFLD:
194 if( !bName )
196 SwDBField* pDBFld = (SwDBField*)pFld;
197 pDBFld->ChgBodyTxtFlag( ::lcl_IsInBody( pFrame ) );
198 /* Solange das ChangeExpansion auskommentiert ist.
199 * Aktualisieren in Kopf/Fuszeilen geht aktuell nicht.
200 if( !::lcl_IsInBody( pFrame ) )
202 pDBFld->ChgBodyTxtFlag( sal_False );
203 pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
205 else if( !pDBFld->IsInBodyTxt() )
207 // war vorher anders, also erst expandieren, dann umsetzen!!
208 pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
209 pDBFld->ChgBodyTxtFlag( sal_True );
213 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
214 break;
216 case RES_REFPAGEGETFLD:
217 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() )
218 ((SwRefPageGetField*)pFld)->ChangeExpansion( pFrame, (SwTxtFld*)pHint );
219 pRet = new SwFldPortion( pFld->GetCntnt( bName ) );
220 break;
222 case RES_JUMPEDITFLD:
223 if( !bName )
224 pChFmt = ((SwJumpEditField*)pFld)->GetCharFmt();
225 bNewFlyPor = sal_True;
226 bPlaceHolder = sal_True;
227 break;
229 default:
231 pRet = new SwFldPortion(pFld->GetCntnt( bName ) );
235 if( bNewFlyPor )
237 SwFont *pTmpFnt = 0;
238 if( !bName )
240 pTmpFnt = new SwFont( *pFnt );
241 if( bINet )
243 SwAttrPool* pPool = pChFmt->GetAttrSet().GetPool();
244 SfxItemSet aSet( *pPool, RES_CHRATR_BEGIN, RES_CHRATR_END );
245 SfxItemSet aTmpSet( aSet );
246 pFrm->GetTxtNode()->GetAttr(aSet,rInf.GetIdx(),rInf.GetIdx()+1);
247 aTmpSet.Set( pChFmt->GetAttrSet() );
248 aTmpSet.Differentiate( aSet );
249 if( aTmpSet.Count() )
250 pTmpFnt->SetDiffFnt( &aTmpSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() );
252 else
253 pTmpFnt->SetDiffFnt( &pChFmt->GetAttrSet(), pFrm->GetTxtNode()->getIDocumentSettingAccess() );
255 pRet = new SwFldPortion( pFld->GetCntnt( bName ), pTmpFnt, bPlaceHolder );
258 return pRet;
261 /*************************************************************************
262 * SwTxtFormatter::TryNewNoLengthPortion()
263 *************************************************************************/
265 SwFldPortion * lcl_NewMetaPortion(SwTxtAttr & rHint, const bool bPrefix)
267 ::sw::Meta *const pMeta(
268 static_cast<SwFmtMeta &>(rHint.GetAttr()).GetMeta() );
269 ::rtl::OUString fix;
270 ::sw::MetaField *const pField( dynamic_cast< ::sw::MetaField * >(pMeta) );
271 OSL_ENSURE(pField, "lcl_NewMetaPortion: no meta field?");
272 if (pField)
274 pField->GetPrefixAndSuffix((bPrefix) ? &fix : 0, (bPrefix) ? 0 : &fix);
276 return new SwFldPortion( fix );
279 /** Try to create a new portion with zero length, for an end of a hint
280 (where there is no CH_TXTATR). Because there may be multiple hint ends at a
281 given index, m_nHintEndIndex is used to keep track of the already created
282 portions. But the portions created here may actually be deleted again,
283 due to UnderFlow. In that case, m_nHintEndIndex must be decremented,
284 so the portion will be created again on the next line.
286 SwExpandPortion *
287 SwTxtFormatter::TryNewNoLengthPortion(SwTxtFormatInfo & rInfo)
289 if (pHints)
291 const xub_StrLen nIdx(rInfo.GetIdx());
292 while (m_nHintEndIndex < pHints->GetEndCount())
294 SwTxtAttr & rHint( *pHints->GetEnd(m_nHintEndIndex) );
295 xub_StrLen const nEnd( *rHint.GetAnyEnd() );
296 if (nEnd > nIdx)
298 break;
300 ++m_nHintEndIndex;
301 if (nEnd == nIdx)
303 if (RES_TXTATR_METAFIELD == rHint.Which())
305 SwFldPortion *const pPortion(
306 lcl_NewMetaPortion(rHint, false));
307 pPortion->SetNoLength(); // no CH_TXTATR at hint end!
308 return pPortion;
313 return 0;
316 /*************************************************************************
317 * SwTxtFormatter::NewExtraPortion()
318 *************************************************************************/
320 SwLinePortion *SwTxtFormatter::NewExtraPortion( SwTxtFormatInfo &rInf )
322 SwTxtAttr *pHint = GetAttr( rInf.GetIdx() );
323 SwLinePortion *pRet = 0;
324 if( !pHint )
326 #if OSL_DEBUG_LEVEL > 1
327 // aDbstream << "NewExtraPortion: hint not found?" << endl;
328 #endif
329 pRet = new SwTxtPortion;
330 pRet->SetLen( 1 );
331 rInf.SetLen( 1 );
332 return pRet;
335 switch( pHint->Which() )
337 case RES_TXTATR_FLYCNT :
339 pRet = NewFlyCntPortion( rInf, pHint );
340 break;
342 case RES_TXTATR_FTN :
344 pRet = NewFtnPortion( rInf, pHint );
345 break;
347 case RES_TXTATR_FIELD :
349 pRet = NewFldPortion( rInf, pHint );
350 break;
352 case RES_TXTATR_REFMARK :
354 pRet = new SwIsoRefPortion;
355 break;
357 case RES_TXTATR_TOXMARK :
359 pRet = new SwIsoToxPortion;
360 break;
362 case RES_TXTATR_METAFIELD:
364 pRet = lcl_NewMetaPortion( *pHint, true );
365 break;
367 default: ;
369 if( !pRet )
371 #if OSL_DEBUG_LEVEL > 1
372 // aDbstream << "NewExtraPortion: unknown hint" << endl;
373 #endif
374 const XubString aNothing;
375 pRet = new SwFldPortion( aNothing );
376 rInf.SetLen( 1 );
378 return pRet;
381 /*************************************************************************
382 * SwTxtFormatter::NewNumberPortion()
383 *************************************************************************/
386 SwNumberPortion *SwTxtFormatter::NewNumberPortion( SwTxtFormatInfo &rInf ) const
388 if( rInf.IsNumDone() || rInf.GetTxtStart() != nStart
389 || rInf.GetTxtStart() != rInf.GetIdx() )
390 return 0;
392 SwNumberPortion *pRet = 0;
393 const SwTxtNode* pTxtNd = GetTxtFrm()->GetTxtNode();
394 const SwNumRule* pNumRule = pTxtNd->GetNumRule();
396 // hat ein "gueltige" Nummer ?
397 if( pTxtNd->IsNumbered() && pTxtNd->IsCountedInList())
399 const SwNumFmt &rNumFmt = pNumRule->Get( static_cast<USHORT>(pTxtNd->GetActualListLevel()) );
400 const sal_Bool bLeft = SVX_ADJUST_LEFT == rNumFmt.GetNumAdjust();
401 const sal_Bool bCenter = SVX_ADJUST_CENTER == rNumFmt.GetNumAdjust();
402 // --> OD 2008-01-23 #newlistlevelattrs#
403 const bool bLabelAlignmentPosAndSpaceModeActive(
404 rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT );
405 const KSHORT nMinDist = bLabelAlignmentPosAndSpaceModeActive
406 ? 0 : rNumFmt.GetCharTextDistance();
407 // <--
409 if( SVX_NUM_BITMAP == rNumFmt.GetNumberingType() )
411 // --> OD 2008-01-23 #newlistlevelattrs#
412 pRet = new SwGrfNumPortion( (SwFrm*)GetTxtFrm(),
413 pTxtNd->GetLabelFollowedBy(),
414 rNumFmt.GetBrush(),
415 rNumFmt.GetGraphicOrientation(),
416 rNumFmt.GetGraphicSize(),
417 bLeft, bCenter, nMinDist,
418 bLabelAlignmentPosAndSpaceModeActive );
419 // <--
420 long nTmpA = rInf.GetLast()->GetAscent();
421 long nTmpD = rInf.GetLast()->Height() - nTmpA;
422 if( !rInf.IsTest() )
423 ((SwGrfNumPortion*)pRet)->SetBase( nTmpA, nTmpD, nTmpA, nTmpD );
425 else
427 // Der SwFont wird dynamisch angelegt und im CTOR uebergeben,
428 // weil das CharFmt nur einen SV-Font zurueckliefert.
429 // Im Dtor vom SwNumberPortion wird der SwFont deletet.
430 SwFont *pNumFnt = 0;
431 const SwAttrSet* pFmt = rNumFmt.GetCharFmt() ?
432 &rNumFmt.GetCharFmt()->GetAttrSet() :
433 NULL;
434 const IDocumentSettingAccess* pIDSA = pTxtNd->getIDocumentSettingAccess();
436 if( SVX_NUM_CHAR_SPECIAL == rNumFmt.GetNumberingType() )
438 const Font *pFmtFnt = rNumFmt.GetBulletFont();
441 // Build a new bullet font basing on the current paragraph font:
443 pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA );
445 // --> FME 2005-08-11 #i53199#
446 if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) )
448 // i18463:
449 // Underline style of paragraph font should not be considered
450 // Overline style of paragraph font should not be considered
451 // Weight style of paragraph font should not be considered
452 // Posture style of paragraph font should not be considered
453 pNumFnt->SetUnderline( UNDERLINE_NONE );
454 pNumFnt->SetOverline( UNDERLINE_NONE );
455 pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
456 pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
457 pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
458 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
459 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
460 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
464 // Apply the explicit attributes from the character style
465 // associated with the numering to the new bullet font.
467 if( pFmt )
468 pNumFnt->SetDiffFnt( pFmt, pIDSA );
470 if ( pFmtFnt )
472 const BYTE nAct = pNumFnt->GetActual();
473 pNumFnt->SetFamily( pFmtFnt->GetFamily(), nAct );
474 pNumFnt->SetName( pFmtFnt->GetName(), nAct );
475 pNumFnt->SetStyleName( pFmtFnt->GetStyleName(), nAct );
476 pNumFnt->SetCharSet( pFmtFnt->GetCharSet(), nAct );
477 pNumFnt->SetPitch( pFmtFnt->GetPitch(), nAct );
480 // we do not allow a vertical font
481 pNumFnt->SetVertical( pNumFnt->GetOrientation(),
482 pFrm->IsVertical() );
484 // --> OD 2008-01-23 #newlistelevelattrs#
485 pRet = new SwBulletPortion( rNumFmt.GetBulletChar(),
486 pTxtNd->GetLabelFollowedBy(),
487 pNumFnt,
488 bLeft, bCenter, nMinDist,
489 bLabelAlignmentPosAndSpaceModeActive );
490 // <--
492 else
494 // --> OD 2006-06-02 #b6432095#
495 // use method <SwNumRule::MakeNumString(..)> instead of
496 // method <SwTxtNode::GetNumString()>, because for levels with
497 // numbering none the prefix and the suffix strings have to be provided.
498 // XubString aTxt( pTxtNd->GetNumString() );
499 XubString aTxt( pNumRule->MakeNumString( *(pTxtNd->GetNum()) ) );
500 // <--
501 // --> OD 2008-01-23 #newlistlevelattrs#
502 if ( aTxt.Len() > 0 )
504 aTxt.Insert( pTxtNd->GetLabelFollowedBy() );
506 // <--
508 // 7974: Nicht nur eine Optimierung...
509 // Eine Numberportion ohne Text wird die Breite von 0
510 // erhalten. Die nachfolgende Textportion wird im BreakLine
511 // in das BreakCut laufen, obwohl rInf.GetLast()->GetFlyPortion()
512 // vorliegt!
513 if( aTxt.Len() )
516 // Build a new numbering font basing on the current paragraph font:
518 pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA );
520 // --> FME 2005-08-11 #i53199#
521 if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) )
523 // i18463:
524 // Underline style of paragraph font should not be considered
525 pNumFnt->SetUnderline( UNDERLINE_NONE );
526 // Overline style of paragraph font should not be considered
527 pNumFnt->SetOverline( UNDERLINE_NONE );
532 // Apply the explicit attributes from the character style
533 // associated with the numering to the new bullet font.
535 if( pFmt )
536 pNumFnt->SetDiffFnt( pFmt, pIDSA );
538 // we do not allow a vertical font
539 pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
541 // --> OD 2008-01-23 #newlistlevelattrs#
542 pRet = new SwNumberPortion( aTxt, pNumFnt,
543 bLeft, bCenter, nMinDist,
544 bLabelAlignmentPosAndSpaceModeActive );
545 // <--
550 return pRet;