nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / fields / expfld.cxx
blob0e486a2963e1139a0bd21c818b4944306a96dbdc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <limits>
24 #include <UndoTable.hxx>
25 #include <hintids.hxx>
26 #include <o3tl/any.hxx>
27 #include <unotools/collatorwrapper.hxx>
28 #include <unotools/charclass.hxx>
29 #include <editeng/langitem.hxx>
30 #include <editeng/fontitem.hxx>
31 #include <com/sun/star/text/SetVariableType.hpp>
32 #include <unofield.hxx>
33 #include <frmfmt.hxx>
34 #include <fmtfld.hxx>
35 #include <txtfld.hxx>
36 #include <fmtanchr.hxx>
37 #include <txtftn.hxx>
38 #include <doc.hxx>
39 #include <IDocumentFieldsAccess.hxx>
40 #include <layfrm.hxx>
41 #include <pagefrm.hxx>
42 #include <cntfrm.hxx>
43 #include <txtfrm.hxx>
44 #include <rootfrm.hxx>
45 #include <tabfrm.hxx>
46 #include <flyfrm.hxx>
47 #include <ftnfrm.hxx>
48 #include <rowfrm.hxx>
49 #include <expfld.hxx>
50 #include <usrfld.hxx>
51 #include <ndtxt.hxx>
52 #include <calc.hxx>
53 #include <pam.hxx>
54 #include <docfld.hxx>
55 #include <swtable.hxx>
56 #include <breakit.hxx>
57 #include <SwStyleNameMapper.hxx>
58 #include <unofldmid.h>
59 #include <numrule.hxx>
60 #include <calbck.hxx>
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::text;
65 static sal_Int16 lcl_SubTypeToAPI(sal_uInt16 nSubType)
67 sal_Int16 nRet = 0;
68 switch(nSubType)
70 case nsSwGetSetExpType::GSE_EXPR:
71 nRet = SetVariableType::VAR; // 0
72 break;
73 case nsSwGetSetExpType::GSE_SEQ:
74 nRet = SetVariableType::SEQUENCE; // 1
75 break;
76 case nsSwGetSetExpType::GSE_FORMULA:
77 nRet = SetVariableType::FORMULA; // 2
78 break;
79 case nsSwGetSetExpType::GSE_STRING:
80 nRet = SetVariableType::STRING; // 3
81 break;
83 return nRet;
86 static sal_Int32 lcl_APIToSubType(const uno::Any& rAny)
88 sal_Int16 nVal = 0;
89 rAny >>= nVal;
90 sal_Int32 nSet = 0;
91 switch(nVal)
93 case SetVariableType::VAR: nSet = nsSwGetSetExpType::GSE_EXPR; break;
94 case SetVariableType::SEQUENCE: nSet = nsSwGetSetExpType::GSE_SEQ; break;
95 case SetVariableType::FORMULA: nSet = nsSwGetSetExpType::GSE_FORMULA; break;
96 case SetVariableType::STRING: nSet = nsSwGetSetExpType::GSE_STRING; break;
97 default:
98 OSL_FAIL("wrong value");
99 nSet = -1;
101 return nSet;
104 OUString ReplacePoint( const OUString& rTmpName, bool bWithCommandType )
106 // replace first and last (if bWithCommandType: last two) dot
107 // since table names may contain dots
109 sal_Int32 nIndex = rTmpName.lastIndexOf('.');
110 if (nIndex<0)
112 return rTmpName;
115 OUString sRes = rTmpName.replaceAt(nIndex, 1, OUString(DB_DELIM));
117 if (bWithCommandType)
119 nIndex = sRes.lastIndexOf('.', nIndex);
120 if (nIndex<0)
122 return sRes;
124 sRes = sRes.replaceAt(nIndex, 1, OUString(DB_DELIM));
127 nIndex = sRes.indexOf('.');
128 if (nIndex>=0)
130 sRes = sRes.replaceAt(nIndex, 1, OUString(DB_DELIM));
132 return sRes;
135 static SwTextNode* GetFirstTextNode( const SwDoc& rDoc, SwPosition& rPos,
136 const SwContentFrame *pCFrame, Point &rPt )
138 SwTextNode* pTextNode = nullptr;
139 if ( !pCFrame )
141 const SwNodes& rNodes = rDoc.GetNodes();
142 rPos.nNode = *rNodes.GetEndOfContent().StartOfSectionNode();
143 SwContentNode* pCNd;
144 while( nullptr != (pCNd = rNodes.GoNext( &rPos.nNode ) ) &&
145 nullptr == ( pTextNode = pCNd->GetTextNode() ) )
147 OSL_ENSURE( pTextNode, "Where is the 1. TextNode?" );
148 rPos.nContent.Assign( pTextNode, 0 );
150 else if ( !pCFrame->isFrameAreaDefinitionValid() )
152 assert(pCFrame->IsTextFrame());
153 rPos = static_cast<SwTextFrame const*>(pCFrame)->MapViewToModelPos(TextFrameIndex(0));
155 else
157 pCFrame->GetModelPositionForViewPoint( &rPos, rPt );
158 pTextNode = rPos.nNode.GetNode().GetTextNode();
160 return pTextNode;
163 const SwTextNode* GetBodyTextNode( const SwDoc& rDoc, SwPosition& rPos,
164 const SwFrame& rFrame )
166 const SwLayoutFrame* pLayout = rFrame.GetUpper();
167 const SwTextNode* pTextNode = nullptr;
169 while( pLayout )
171 if( pLayout->IsFlyFrame() )
173 // get the FlyFormat
174 const SwFrameFormat* pFlyFormat = static_cast<const SwFlyFrame*>(pLayout)->GetFormat();
175 OSL_ENSURE( pFlyFormat, "Could not find FlyFormat, where is the field?" );
177 const SwFormatAnchor &rAnchor = pFlyFormat->GetAnchor();
179 if( RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId() )
181 // the fly needs to be attached somewhere, so ask it
182 pLayout = static_cast<const SwLayoutFrame*>(static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame());
183 continue;
185 else if ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
186 (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
187 (RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()))
189 OSL_ENSURE( rAnchor.GetContentAnchor(), "no valid position" );
190 rPos = *rAnchor.GetContentAnchor();
191 pTextNode = rPos.nNode.GetNode().GetTextNode();
192 if ( RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() )
194 const_cast<SwTextNode*>(pTextNode)->MakeStartIndex(
195 &rPos.nContent );
198 // do not break yet, might be as well in Header/Footer/Footnote/Fly
199 pLayout = static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame()
200 ? static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame()->GetUpper() : nullptr;
201 continue;
203 else
205 pLayout->FindPageFrame()->GetContentPosition(
206 pLayout->getFrameArea().Pos(), rPos );
207 pTextNode = rPos.nNode.GetNode().GetTextNode();
210 else if( pLayout->IsFootnoteFrame() )
212 // get the anchor's node
213 const SwTextFootnote* pFootnote = static_cast<const SwFootnoteFrame*>(pLayout)->GetAttr();
214 pTextNode = &pFootnote->GetTextNode();
215 rPos.nNode = *pTextNode;
216 rPos.nContent = pFootnote->GetStart();
218 else if( pLayout->IsHeaderFrame() || pLayout->IsFooterFrame() )
220 const SwContentFrame* pContentFrame;
221 const SwPageFrame* pPgFrame = pLayout->FindPageFrame();
222 if( pLayout->IsHeaderFrame() )
224 const SwTabFrame *pTab;
225 if( nullptr != ( pContentFrame = pPgFrame->FindFirstBodyContent()) &&
226 nullptr != (pTab = pContentFrame->FindTabFrame()) && pTab->IsFollow() &&
227 pTab->GetTable()->GetRowsToRepeat() > 0 &&
228 pTab->IsInHeadline( *pContentFrame ) )
230 // take the next line
231 const SwLayoutFrame* pRow = pTab->GetFirstNonHeadlineRow();
232 pContentFrame = pRow->ContainsContent();
235 else
236 pContentFrame = pPgFrame->FindLastBodyContent();
238 if( pContentFrame )
240 assert(pContentFrame->IsTextFrame());
241 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pContentFrame));
242 rPos = pFrame->MapViewToModelPos(TextFrameIndex(pFrame->GetText().getLength()));
243 pTextNode = rPos.nNode.GetNode().GetTextNode();
244 assert(pTextNode);
246 else
248 Point aPt( pLayout->getFrameArea().Pos() );
249 aPt.AdjustY( 1 ); // get out of the header
250 pContentFrame = pPgFrame->GetContentPos( aPt, false, true );
251 pTextNode = GetFirstTextNode( rDoc, rPos, pContentFrame, aPt );
254 else
256 pLayout = pLayout->GetUpper();
257 continue;
259 break; // found, so finish loop
261 return pTextNode;
264 SwGetExpFieldType::SwGetExpFieldType(SwDoc* pDc)
265 : SwValueFieldType( pDc, SwFieldIds::GetExp )
269 std::unique_ptr<SwFieldType> SwGetExpFieldType::Copy() const
271 return std::make_unique<SwGetExpFieldType>(GetDoc());
274 void SwGetExpFieldType::Modify( const SfxPoolItem*, const SfxPoolItem* pNew )
276 if( pNew && RES_DOCPOS_UPDATE == pNew->Which() )
277 NotifyClients( nullptr, pNew );
278 // do not expand anything else
281 SwGetExpField::SwGetExpField(SwGetExpFieldType* pTyp, const OUString& rFormel,
282 sal_uInt16 nSub, sal_uLong nFormat)
283 : SwFormulaField( pTyp, nFormat, 0.0 )
284 , m_fValueRLHidden(0.0)
286 m_bIsInBodyText( true ),
287 m_nSubType(nSub),
288 m_bLateInitialization( false )
290 SetFormula( rFormel );
293 void SwGetExpField::ChgExpStr(const OUString& rExpand, SwRootFrame const*const pLayout)
295 if (!pLayout || pLayout->IsHideRedlines())
297 m_sExpandRLHidden = rExpand;
299 if (!pLayout || !pLayout->IsHideRedlines())
301 m_sExpand = rExpand;
305 OUString SwGetExpField::ExpandImpl(SwRootFrame const*const pLayout) const
307 if(m_nSubType & nsSwExtendedSubType::SUB_CMD)
308 return GetFormula();
310 return (pLayout && pLayout->IsHideRedlines()) ? m_sExpandRLHidden : m_sExpand;
313 OUString SwGetExpField::GetFieldName() const
315 const SwFieldTypesEnum nType =
316 (nsSwGetSetExpType::GSE_FORMULA & m_nSubType)
317 ? SwFieldTypesEnum::Formel
318 : SwFieldTypesEnum::Get;
320 return SwFieldType::GetTypeStr(nType) + " " + GetFormula();
323 std::unique_ptr<SwField> SwGetExpField::Copy() const
325 std::unique_ptr<SwGetExpField> pTmp(new SwGetExpField(static_cast<SwGetExpFieldType*>(GetTyp()),
326 GetFormula(), m_nSubType, GetFormat()));
327 pTmp->SetLanguage(GetLanguage());
328 pTmp->m_fValueRLHidden = m_fValueRLHidden;
329 pTmp->SwValueField::SetValue(GetValue());
330 pTmp->m_sExpand = m_sExpand;
331 pTmp->m_sExpandRLHidden = m_sExpandRLHidden;
332 pTmp->m_bIsInBodyText = m_bIsInBodyText;
333 pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
334 if( m_bLateInitialization )
335 pTmp->SetLateInitialization();
337 return std::unique_ptr<SwField>(pTmp.release());
340 void SwGetExpField::ChangeExpansion( const SwFrame& rFrame, const SwTextField& rField )
342 if( m_bIsInBodyText ) // only fields in Footer, Header, FootNote, Flys
343 return;
345 OSL_ENSURE( !rFrame.IsInDocBody(), "Flag incorrect, frame is in DocBody" );
347 // determine document (or is there an easier way?)
348 const SwTextNode* pTextNode = &rField.GetTextNode();
349 SwDoc& rDoc = const_cast<SwDoc&>(pTextNode->GetDoc());
351 // create index for determination of the TextNode
352 SwPosition aPos( SwNodeIndex( rDoc.GetNodes() ) );
353 pTextNode = GetBodyTextNode( rDoc, aPos, rFrame );
355 // If no layout exists, ChangeExpansion is called for header and
356 // footer lines via layout formatting without existing TextNode.
357 if(!pTextNode)
358 return;
359 // #i82544#
360 if( m_bLateInitialization )
362 SwFieldType* pSetExpField = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, GetFormula(), false);
363 if( pSetExpField )
365 m_bLateInitialization = false;
366 if( !(GetSubType() & nsSwGetSetExpType::GSE_STRING) &&
367 static_cast< SwSetExpFieldType* >(pSetExpField)->GetType() == nsSwGetSetExpType::GSE_STRING )
368 SetSubType( nsSwGetSetExpType::GSE_STRING );
372 SwRootFrame const& rLayout(*rFrame.getRootFrame());
373 OUString & rExpand(rLayout.IsHideRedlines() ? m_sExpandRLHidden : m_sExpand);
374 SetGetExpField aEndField( aPos.nNode, &rField, &aPos.nContent );
375 if(GetSubType() & nsSwGetSetExpType::GSE_STRING)
377 SwHashTable<HashStr> aHashTable(0);
378 rDoc.getIDocumentFieldsAccess().FieldsToExpand(aHashTable, aEndField, rLayout);
379 rExpand = LookString( aHashTable, GetFormula() );
381 else
383 // fill calculator with values
384 SwCalc aCalc( rDoc );
385 rDoc.getIDocumentFieldsAccess().FieldsToCalc(aCalc, aEndField, &rLayout);
387 // calculate value
388 SetValue(aCalc.Calculate(GetFormula()).GetDouble(), &rLayout);
390 // analyse based on format
391 rExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
392 GetValue(&rLayout), GetFormat(), GetLanguage());
396 OUString SwGetExpField::GetPar2() const
398 return GetFormula();
401 void SwGetExpField::SetPar2(const OUString& rStr)
403 SetFormula(rStr);
406 sal_uInt16 SwGetExpField::GetSubType() const
408 return m_nSubType;
411 void SwGetExpField::SetSubType(sal_uInt16 nType)
413 m_nSubType = nType;
416 void SwGetExpField::SetLanguage(LanguageType nLng)
418 if (m_nSubType & nsSwExtendedSubType::SUB_CMD)
419 SwField::SetLanguage(nLng);
420 else
421 SwValueField::SetLanguage(nLng);
424 bool SwGetExpField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
426 switch( nWhichId )
428 case FIELD_PROP_DOUBLE:
429 rAny <<= GetValue();
430 break;
431 case FIELD_PROP_FORMAT:
432 rAny <<= static_cast<sal_Int32>(GetFormat());
433 break;
434 case FIELD_PROP_USHORT1:
435 rAny <<= static_cast<sal_Int16>(m_nSubType);
436 break;
437 case FIELD_PROP_PAR1:
438 rAny <<= GetFormula();
439 break;
440 case FIELD_PROP_SUBTYPE:
442 sal_Int16 nRet = lcl_SubTypeToAPI(GetSubType() & 0xff);
443 rAny <<= nRet;
445 break;
446 case FIELD_PROP_BOOL2:
447 rAny <<= 0 != (m_nSubType & nsSwExtendedSubType::SUB_CMD);
448 break;
449 case FIELD_PROP_PAR4:
450 rAny <<= m_sExpand;
451 break;
452 default:
453 return SwField::QueryValue(rAny, nWhichId);
455 return true;
458 bool SwGetExpField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
460 sal_Int32 nTmp = 0;
461 switch( nWhichId )
463 case FIELD_PROP_DOUBLE:
464 SwValueField::SetValue(*o3tl::doAccess<double>(rAny));
465 m_fValueRLHidden = *o3tl::doAccess<double>(rAny);
466 break;
467 case FIELD_PROP_FORMAT:
468 rAny >>= nTmp;
469 SetFormat(nTmp);
470 break;
471 case FIELD_PROP_USHORT1:
472 rAny >>= nTmp;
473 m_nSubType = static_cast<sal_uInt16>(nTmp);
474 break;
475 case FIELD_PROP_PAR1:
477 OUString sTmp;
478 rAny >>= sTmp;
479 SetFormula(sTmp);
480 break;
482 case FIELD_PROP_SUBTYPE:
483 nTmp = lcl_APIToSubType(rAny);
484 if( nTmp >=0 )
485 SetSubType( static_cast<sal_uInt16>((GetSubType() & 0xff00) | nTmp));
486 break;
487 case FIELD_PROP_BOOL2:
488 if(*o3tl::doAccess<bool>(rAny))
489 m_nSubType |= nsSwExtendedSubType::SUB_CMD;
490 else
491 m_nSubType &= (~nsSwExtendedSubType::SUB_CMD);
492 break;
493 case FIELD_PROP_PAR4:
495 OUString sTmp;
496 rAny >>= sTmp;
497 ChgExpStr(sTmp, nullptr);
498 break;
500 default:
501 return SwField::PutValue(rAny, nWhichId);
503 return true;
506 SwSetExpFieldType::SwSetExpFieldType( SwDoc* pDc, const OUString& rName, sal_uInt16 nTyp )
507 : SwValueFieldType( pDc, SwFieldIds::SetExp ),
508 m_sName( rName ),
509 m_sDelim( "." ),
510 m_nType(nTyp), m_nLevel( UCHAR_MAX ),
511 m_bDeleted( false )
513 if( ( nsSwGetSetExpType::GSE_SEQ | nsSwGetSetExpType::GSE_STRING ) & m_nType )
514 EnableFormat(false); // do not use Numberformatter
517 std::unique_ptr<SwFieldType> SwSetExpFieldType::Copy() const
519 std::unique_ptr<SwSetExpFieldType> pNew(new SwSetExpFieldType(GetDoc(), m_sName, m_nType));
520 pNew->m_bDeleted = m_bDeleted;
521 pNew->m_sDelim = m_sDelim;
522 pNew->m_nLevel = m_nLevel;
524 return pNew;
527 OUString SwSetExpFieldType::GetName() const
529 return m_sName;
532 const OUString& SwSetExpField::GetExpStr(SwRootFrame const*const pLayout) const
534 return (pLayout && pLayout->IsHideRedlines()) ? msExpandRLHidden : msExpand;
537 void SwSetExpField::ChgExpStr(const OUString& rExpand, SwRootFrame const*const pLayout)
539 if (!pLayout || pLayout->IsHideRedlines())
541 msExpandRLHidden = rExpand;
543 if (!pLayout || !pLayout->IsHideRedlines())
545 msExpand = rExpand;
549 void SwSetExpFieldType::Modify( const SfxPoolItem*, const SfxPoolItem* )
551 // do not expand further
554 void SwSetExpFieldType::SetSeqFormat(sal_uLong nFormat)
556 std::vector<SwFormatField*> vFields;
557 GatherFields(vFields, false);
558 for(auto pFormatField: vFields)
559 pFormatField->GetField()->ChangeFormat(nFormat);
562 sal_uLong SwSetExpFieldType::GetSeqFormat() const
564 if( !HasWriterListeners() )
565 return SVX_NUM_ARABIC;
567 std::vector<SwFormatField*> vFields;
568 GatherFields(vFields, false);
569 return vFields.front()->GetField()->GetFormat();
572 void SwSetExpFieldType::SetSeqRefNo( SwSetExpField& rField )
574 if( !HasWriterListeners() || !(nsSwGetSetExpType::GSE_SEQ & m_nType) )
575 return;
577 std::vector<sal_uInt16> aArr;
579 // check if number is already used and if a new one needs to be created
580 std::vector<SwFormatField*> vFields;
581 GatherFields(vFields);
582 for(SwFormatField* pF: vFields)
583 if(pF->GetField() != &rField)
584 InsertSort(aArr, static_cast<SwSetExpField*>(pF->GetField())->GetSeqNumber());
586 // check first if number already exists
587 sal_uInt16 nNum = rField.GetSeqNumber();
588 if( USHRT_MAX != nNum )
590 std::vector<sal_uInt16>::size_type n {0};
592 for( n = 0; n < aArr.size(); ++n )
593 if( aArr[ n ] >= nNum )
594 break;
596 if( n == aArr.size() || aArr[ n ] > nNum )
597 return; // no -> use it
600 // flagged all numbers, so determine the right number
601 std::vector<sal_uInt16>::size_type n = aArr.size();
602 OSL_ENSURE( n <= std::numeric_limits<sal_uInt16>::max(), "Array is too big for using a sal_uInt16 index" );
604 if ( n > 0 && aArr[ n-1 ] != n-1 )
606 for( n = 0; n < aArr.size(); ++n )
607 if( n != aArr[ n ] )
608 break;
611 rField.SetSeqNumber( n );
614 size_t SwSetExpFieldType::GetSeqFieldList(SwSeqFieldList& rList,
615 SwRootFrame const*const pLayout)
617 rList.Clear();
619 IDocumentRedlineAccess const& rIDRA(GetDoc()->getIDocumentRedlineAccess());
621 std::vector<SwFormatField*> vFields;
622 GatherFields(vFields);
623 for(SwFormatField* pF: vFields)
625 const SwTextNode* pNd;
626 if( nullptr != ( pNd = pF->GetTextField()->GetpTextNode() )
627 && (!pLayout || !pLayout->IsHideRedlines()
628 || !sw::IsFieldDeletedInModel(rIDRA, *pF->GetTextField())))
630 SeqFieldLstElem aNew(
631 pNd->GetExpandText(pLayout),
632 static_cast<SwSetExpField*>(pF->GetField())->GetSeqNumber() );
633 rList.InsertSort( aNew );
636 return rList.Count();
639 void SwSetExpFieldType::SetChapter(SwSetExpField& rField, const SwNode& rNd,
640 SwRootFrame const*const pLayout)
642 const SwTextNode* pTextNd = rNd.FindOutlineNodeOfLevel(m_nLevel, pLayout);
643 if( !pTextNd )
644 return;
646 SwNumRule * pRule = pTextNd->GetNumRule();
648 if (!pRule)
649 return;
651 // --> OD 2005-11-02 #i51089 - TUNING#
652 if (SwNodeNum const*const pNum = pTextNd->GetNum(pLayout))
654 // only get the number, without pre-/post-fixstrings
655 OUString const sNumber(pRule->MakeNumString(*pNum, false));
657 if( !sNumber.isEmpty() )
658 rField.ChgExpStr(sNumber + m_sDelim + rField.GetExpStr(pLayout), pLayout);
660 else
662 OSL_ENSURE(pTextNd->GetNum(nullptr), "<SwSetExpFieldType::SetChapter(..)> - text node with numbering rule, but without number. This is a serious defect");
666 void SwSetExpFieldType::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
668 switch( nWhichId )
670 case FIELD_PROP_SUBTYPE:
672 sal_Int16 nRet = lcl_SubTypeToAPI(GetType());
673 rAny <<= nRet;
675 break;
676 case FIELD_PROP_PAR2:
677 rAny <<= GetDelimiter();
678 break;
679 case FIELD_PROP_SHORT1:
681 sal_Int8 nRet = m_nLevel < MAXLEVEL? m_nLevel : -1;
682 rAny <<= nRet;
684 break;
685 default:
686 assert(false);
690 void SwSetExpFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
692 switch( nWhichId )
694 case FIELD_PROP_SUBTYPE:
696 sal_Int32 nSet = lcl_APIToSubType(rAny);
697 if(nSet >=0)
698 SetType(static_cast<sal_uInt16>(nSet));
700 break;
701 case FIELD_PROP_PAR2:
703 OUString sTmp;
704 rAny >>= sTmp;
705 if( !sTmp.isEmpty() )
706 SetDelimiter( sTmp );
707 else
708 SetDelimiter( " " );
710 break;
711 case FIELD_PROP_SHORT1:
713 sal_Int8 nLvl = 0;
714 rAny >>= nLvl;
715 if(nLvl < 0 || nLvl >= MAXLEVEL)
716 SetOutlineLvl(UCHAR_MAX);
717 else
718 SetOutlineLvl(nLvl);
720 break;
721 default:
722 assert(false);
726 bool SwSeqFieldList::InsertSort( SeqFieldLstElem aNew )
728 OUStringBuffer aBuf(aNew.sDlgEntry);
729 const sal_Int32 nLen = aBuf.getLength();
730 for (sal_Int32 i = 0; i < nLen; ++i)
732 if (aBuf[i]<' ')
734 aBuf[i]=' ';
737 aNew.sDlgEntry = aBuf.makeStringAndClear();
739 size_t nPos = 0;
740 bool bRet = SeekEntry( aNew, &nPos );
741 if( !bRet )
742 maData.insert( maData.begin() + nPos, aNew );
743 return bRet;
746 bool SwSeqFieldList::SeekEntry( const SeqFieldLstElem& rNew, size_t* pP ) const
748 size_t nO = maData.size();
749 size_t nU = 0;
750 if( nO > 0 )
752 CollatorWrapper & rCaseColl = ::GetAppCaseCollator(),
753 & rColl = ::GetAppCollator();
754 const CharClass& rCC = GetAppCharClass();
756 //#59900# Sorting should sort number correctly (e.g. "10" after "9" not after "1")
757 const OUString rTmp2 = rNew.sDlgEntry;
758 sal_Int32 nFndPos2 = 0;
759 const OUString sNum2( rTmp2.getToken( 0, ' ', nFndPos2 ));
760 bool bIsNum2IsNumeric = CharClass::isAsciiNumeric( sNum2 );
761 sal_Int32 nNum2 = bIsNum2IsNumeric ? sNum2.toInt32() : 0;
763 nO--;
764 while( nU <= nO )
766 const size_t nM = nU + ( nO - nU ) / 2;
768 //#59900# Sorting should sort number correctly (e.g. "10" after "9" not after "1")
769 const OUString rTmp1 = maData[nM].sDlgEntry;
770 sal_Int32 nFndPos1 = 0;
771 const OUString sNum1( rTmp1.getToken( 0, ' ', nFndPos1 ));
772 sal_Int32 nCmp;
774 if( bIsNum2IsNumeric && rCC.isNumeric( sNum1 ) )
776 sal_Int32 nNum1 = sNum1.toInt32();
777 nCmp = nNum2 - nNum1;
778 if( 0 == nCmp )
780 OUString aTmp1 = nFndPos1 != -1 ? rTmp1.copy(nFndPos1) : OUString();
781 OUString aTmp2 = nFndPos2 != -1 ? rTmp2.copy(nFndPos2) : OUString();
782 nCmp = rCaseColl.compareString(aTmp2, aTmp1);
785 else
786 nCmp = rColl.compareString( rTmp2, rTmp1 );
788 if( 0 == nCmp )
790 if( pP ) *pP = nM;
791 return true;
793 else if( 0 < nCmp )
794 nU = nM + 1;
795 else if( nM == 0 )
796 break;
797 else
798 nO = nM - 1;
801 if( pP ) *pP = nU;
802 return false;
805 SwSetExpField::SwSetExpField(SwSetExpFieldType* pTyp, const OUString& rFormel,
806 sal_uLong nFormat)
807 : SwFormulaField( pTyp, nFormat, 0.0 )
808 , m_fValueRLHidden(0.0)
809 , mnSeqNo( USHRT_MAX )
810 , mnSubType(0)
811 , mpFormatField(nullptr)
813 SetFormula(rFormel);
814 // ignore SubType
815 mbInput = false;
816 if( IsSequenceField() )
818 SwValueField::SetValue(1.0);
819 m_fValueRLHidden = 1.0;
820 if( rFormel.isEmpty() )
822 SetFormula(pTyp->GetName() + "+1");
827 void SwSetExpField::SetFormatField(SwFormatField & rFormatField)
829 mpFormatField = &rFormatField;
832 OUString SwSetExpField::ExpandImpl(SwRootFrame const*const pLayout) const
834 if (mnSubType & nsSwExtendedSubType::SUB_CMD)
835 { // we need the CommandString
836 return GetTyp()->GetName() + " = " + GetFormula();
838 if(!(mnSubType & nsSwExtendedSubType::SUB_INVISIBLE))
839 { // value is visible
840 return (pLayout && pLayout->IsHideRedlines()) ? msExpandRLHidden : msExpand;
842 return OUString();
845 /// @return the field name
846 OUString SwSetExpField::GetFieldName() const
848 SwFieldTypesEnum const nStrType( (IsSequenceField())
849 ? SwFieldTypesEnum::Sequence
850 : mbInput
851 ? SwFieldTypesEnum::SetInput
852 : SwFieldTypesEnum::Set );
854 OUString aStr(
855 SwFieldType::GetTypeStr( nStrType )
856 + " "
857 + GetTyp()->GetName() );
859 // Sequence: without formula
860 if (SwFieldTypesEnum::Sequence != nStrType)
862 aStr += " = " + GetFormula();
864 return aStr;
867 std::unique_ptr<SwField> SwSetExpField::Copy() const
869 std::unique_ptr<SwSetExpField> pTmp(new SwSetExpField(static_cast<SwSetExpFieldType*>(GetTyp()),
870 GetFormula(), GetFormat()));
871 pTmp->SwValueField::SetValue(GetValue());
872 pTmp->m_fValueRLHidden = m_fValueRLHidden;
873 pTmp->msExpand = msExpand;
874 pTmp->msExpandRLHidden = msExpandRLHidden;
875 pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
876 pTmp->SetLanguage(GetLanguage());
877 pTmp->maPText = maPText;
878 pTmp->mbInput = mbInput;
879 pTmp->mnSeqNo = mnSeqNo;
880 pTmp->SetSubType(GetSubType());
882 return std::unique_ptr<SwField>(pTmp.release());
885 void SwSetExpField::SetSubType(sal_uInt16 nSub)
887 static_cast<SwSetExpFieldType*>(GetTyp())->SetType(nSub & 0xff);
888 mnSubType = nSub & 0xff00;
890 OSL_ENSURE( (nSub & 0xff) != 3, "SubType is illegal!" );
893 sal_uInt16 SwSetExpField::GetSubType() const
895 return static_cast<SwSetExpFieldType*>(GetTyp())->GetType() | mnSubType;
898 void SwSetExpField::SetValue( const double& rAny )
900 SwValueField::SetValue(rAny);
902 if( IsSequenceField() )
903 msExpand = FormatNumber( GetValue(), static_cast<SvxNumType>(GetFormat()), GetLanguage() );
904 else
905 msExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue( rAny,
906 GetFormat(), GetLanguage());
909 void SwSetExpField::SetValue(const double& rValue, SwRootFrame const*const pLayout)
911 if (!pLayout || !pLayout->IsHideRedlines())
913 SetValue(rValue);
915 if (pLayout && !pLayout->IsHideRedlines())
916 return;
918 m_fValueRLHidden = rValue;
919 if (IsSequenceField())
921 msExpandRLHidden = FormatNumber(rValue, static_cast<SvxNumType>(GetFormat()), GetLanguage());
923 else
925 msExpandRLHidden = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
926 rValue, GetFormat(), GetLanguage());
930 double SwSetExpField::GetValue(SwRootFrame const* pLayout) const
932 return (pLayout && pLayout->IsHideRedlines()) ? m_fValueRLHidden : GetValue();
935 void SwGetExpField::SetValue( const double& rAny )
937 SwValueField::SetValue(rAny);
938 m_sExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue( rAny, GetFormat(),
939 GetLanguage());
942 void SwGetExpField::SetValue(const double& rValue, SwRootFrame const*const pLayout)
944 if (!pLayout || !pLayout->IsHideRedlines())
946 SetValue(rValue);
948 if (!pLayout || pLayout->IsHideRedlines())
950 m_fValueRLHidden = rValue;
951 m_sExpandRLHidden = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
952 rValue, GetFormat(), GetLanguage());
956 double SwGetExpField::GetValue(SwRootFrame const* pLayout) const
958 return (pLayout && pLayout->IsHideRedlines()) ? m_fValueRLHidden : GetValue();
961 /** Find the index of the reference text following the current field
963 * @param rFormat
964 * @param rDoc
965 * @param nHint search starting position after the current field (or 0 if default)
966 * @return
968 sal_Int32 SwGetExpField::GetReferenceTextPos( const SwFormatField& rFormat, SwDoc& rDoc, sal_Int32 nHint)
971 const SwTextField* pTextField = rFormat.GetTextField();
972 const SwTextNode& rTextNode = pTextField->GetTextNode();
974 sal_Int32 nRet = nHint ? nHint : pTextField->GetStart() + 1;
975 OUString sNodeText = rTextNode.GetText();
977 if(nRet<sNodeText.getLength())
979 sNodeText = sNodeText.copy(nRet);
981 // now check if sNodeText starts with a non-alphanumeric character plus blanks
982 sal_uInt16 nSrcpt = g_pBreakIt->GetRealScriptOfText( sNodeText, 0 );
984 static const sal_uInt16 nIds[] =
986 RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
987 RES_CHRATR_FONT, RES_CHRATR_FONT,
988 RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
989 RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONT,
990 RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
991 RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONT,
992 0, 0
994 SwAttrSet aSet(rDoc.GetAttrPool(), nIds);
995 rTextNode.GetParaAttr(aSet, nRet, nRet+1);
997 if( RTL_TEXTENCODING_SYMBOL != static_cast<const SvxFontItem&>(aSet.Get(
998 GetWhichOfScript( RES_CHRATR_FONT, nSrcpt )) ).GetCharSet() )
1000 LanguageType eLang = static_cast<const SvxLanguageItem&>(aSet.Get(
1001 GetWhichOfScript( RES_CHRATR_LANGUAGE, nSrcpt )) ).GetLanguage();
1002 LanguageTag aLanguageTag( eLang);
1003 CharClass aCC( aLanguageTag);
1004 sal_Unicode c0 = sNodeText[0];
1005 bool bIsAlphaNum = aCC.isAlphaNumeric( sNodeText, 0 );
1006 if( !bIsAlphaNum ||
1007 (c0 == ' ' || c0 == '\t'))
1009 // ignoring blanks
1010 nRet++;
1011 const sal_Int32 nLen = sNodeText.getLength();
1012 for (sal_Int32 i = 1;
1013 i<nLen && (sNodeText[i]==' ' || sNodeText[i]=='\t');
1016 ++nRet;
1020 return nRet;
1023 OUString SwSetExpField::GetPar1() const
1025 return static_cast<const SwSetExpFieldType*>(GetTyp())->GetName();
1028 OUString SwSetExpField::GetPar2() const
1030 sal_uInt16 nType = static_cast<SwSetExpFieldType*>(GetTyp())->GetType();
1032 if (nType & nsSwGetSetExpType::GSE_STRING)
1033 return GetFormula();
1034 return GetExpandedFormula();
1037 void SwSetExpField::SetPar2(const OUString& rStr)
1039 sal_uInt16 nType = static_cast<SwSetExpFieldType*>(GetTyp())->GetType();
1041 if( !(nType & nsSwGetSetExpType::GSE_SEQ) || !rStr.isEmpty() )
1043 if (nType & nsSwGetSetExpType::GSE_STRING)
1044 SetFormula(rStr);
1045 else
1046 SetExpandedFormula(rStr);
1050 bool SwSetExpField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
1052 sal_Int32 nTmp32 = 0;
1053 sal_Int16 nTmp16 = 0;
1054 switch( nWhichId )
1056 case FIELD_PROP_BOOL2:
1057 if(*o3tl::doAccess<bool>(rAny))
1058 mnSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE;
1059 else
1060 mnSubType |= nsSwExtendedSubType::SUB_INVISIBLE;
1061 break;
1062 case FIELD_PROP_FORMAT:
1063 rAny >>= nTmp32;
1064 SetFormat(nTmp32);
1065 break;
1066 case FIELD_PROP_USHORT2:
1068 rAny >>= nTmp16;
1069 if(nTmp16 <= css::style::NumberingType::NUMBER_NONE )
1070 SetFormat(nTmp16);
1071 else {
1072 //exception(wrong_value)
1076 break;
1077 case FIELD_PROP_USHORT1:
1078 rAny >>= nTmp16;
1079 mnSeqNo = nTmp16;
1080 break;
1081 case FIELD_PROP_PAR1:
1083 OUString sTmp;
1084 rAny >>= sTmp;
1085 SetPar1( SwStyleNameMapper::GetUIName( sTmp, SwGetPoolIdFromName::TxtColl ) );
1087 break;
1088 case FIELD_PROP_PAR2:
1090 OUString uTmp;
1091 rAny >>= uTmp;
1092 //I18N - if the formula contains only "TypeName+1"
1093 //and it's one of the initially created sequence fields
1094 //then the localized names has to be replaced by a programmatic name
1095 OUString sMyFormula = SwXFieldMaster::LocalizeFormula(*this, uTmp, false);
1096 SetFormula( sMyFormula );
1098 break;
1099 case FIELD_PROP_DOUBLE:
1101 double fVal = 0.0;
1102 rAny >>= fVal;
1103 SetValue(fVal);
1104 m_fValueRLHidden = fVal;
1106 break;
1107 case FIELD_PROP_SUBTYPE:
1108 nTmp32 = lcl_APIToSubType(rAny);
1109 if(nTmp32 >= 0)
1110 SetSubType(static_cast<sal_uInt16>((GetSubType() & 0xff00) | nTmp32));
1111 break;
1112 case FIELD_PROP_PAR3:
1113 rAny >>= maPText;
1114 break;
1115 case FIELD_PROP_BOOL3:
1116 if(*o3tl::doAccess<bool>(rAny))
1117 mnSubType |= nsSwExtendedSubType::SUB_CMD;
1118 else
1119 mnSubType &= (~nsSwExtendedSubType::SUB_CMD);
1120 break;
1121 case FIELD_PROP_BOOL1:
1123 bool newInput(*o3tl::doAccess<bool>(rAny));
1124 if (newInput != GetInputFlag())
1126 if (static_cast<SwSetExpFieldType*>(GetTyp())->GetType()
1127 & nsSwGetSetExpType::GSE_STRING)
1129 SwXTextField::TransmuteLeadToInputField(*this);
1131 else
1133 SetInputFlag(newInput);
1137 break;
1138 case FIELD_PROP_PAR4:
1140 OUString sTmp;
1141 rAny >>= sTmp;
1142 ChgExpStr(sTmp, nullptr);
1144 break;
1145 default:
1146 return SwField::PutValue(rAny, nWhichId);
1148 return true;
1151 bool SwSetExpField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
1153 switch( nWhichId )
1155 case FIELD_PROP_BOOL2:
1156 rAny <<= 0 == (mnSubType & nsSwExtendedSubType::SUB_INVISIBLE);
1157 break;
1158 case FIELD_PROP_FORMAT:
1159 rAny <<= static_cast<sal_Int32>(GetFormat());
1160 break;
1161 case FIELD_PROP_USHORT2:
1162 rAny <<= static_cast<sal_Int16>(GetFormat());
1163 break;
1164 case FIELD_PROP_USHORT1:
1165 rAny <<= static_cast<sal_Int16>(mnSeqNo);
1166 break;
1167 case FIELD_PROP_PAR1:
1168 rAny <<= SwStyleNameMapper::GetProgName(GetPar1(), SwGetPoolIdFromName::TxtColl );
1169 break;
1170 case FIELD_PROP_PAR2:
1172 //I18N - if the formula contains only "TypeName+1"
1173 //and it's one of the initially created sequence fields
1174 //then the localized names has to be replaced by a programmatic name
1175 OUString sMyFormula = SwXFieldMaster::LocalizeFormula(*this, GetFormula(), true);
1176 rAny <<= sMyFormula;
1178 break;
1179 case FIELD_PROP_DOUBLE:
1180 rAny <<= GetValue();
1181 break;
1182 case FIELD_PROP_SUBTYPE:
1184 sal_Int16 nRet = lcl_SubTypeToAPI(GetSubType() & 0xff);
1185 rAny <<= nRet;
1187 break;
1188 case FIELD_PROP_PAR3:
1189 rAny <<= maPText;
1190 break;
1191 case FIELD_PROP_BOOL3:
1192 rAny <<= 0 != (mnSubType & nsSwExtendedSubType::SUB_CMD);
1193 break;
1194 case FIELD_PROP_BOOL1:
1195 rAny <<= GetInputFlag();
1196 break;
1197 case FIELD_PROP_PAR4:
1198 rAny <<= GetExpStr(nullptr);
1199 break;
1200 default:
1201 return SwField::QueryValue(rAny, nWhichId);
1203 return true;
1206 SwInputFieldType::SwInputFieldType( SwDoc* pD )
1207 : SwFieldType( SwFieldIds::Input )
1208 , mpDoc( pD )
1212 std::unique_ptr<SwFieldType> SwInputFieldType::Copy() const
1214 return std::make_unique<SwInputFieldType>( mpDoc );
1217 SwInputField::SwInputField( SwInputFieldType* pFieldType,
1218 const OUString& rContent,
1219 const OUString& rPrompt,
1220 sal_uInt16 nSub,
1221 sal_uLong nFormat,
1222 bool bIsFormField )
1223 : SwField( pFieldType, nFormat, LANGUAGE_SYSTEM, false )
1224 , maContent(rContent)
1225 , maPText(rPrompt)
1226 , mnSubType(nSub)
1227 , mbIsFormField( bIsFormField )
1228 , mpFormatField( nullptr )
1232 SwInputField::~SwInputField()
1236 void SwInputField::SetFormatField( SwFormatField& rFormatField )
1238 mpFormatField = &rFormatField;
1242 void SwInputField::applyFieldContent( const OUString& rNewFieldContent )
1244 if ( (mnSubType & 0x00ff) == INP_TXT )
1246 maContent = rNewFieldContent;
1248 else if( (mnSubType & 0x00ff) == INP_USR )
1250 SwUserFieldType* pUserTyp = static_cast<SwUserFieldType*>(
1251 static_cast<SwInputFieldType*>(GetTyp())->GetDoc()->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::User, getContent(), false ) );
1252 if( pUserTyp )
1254 pUserTyp->SetContent( rNewFieldContent );
1255 if (!pUserTyp->IsModifyLocked())
1257 // trigger update of the corresponding User Fields and other
1258 // related Input Fields
1259 bool bUnlock(false);
1260 if (GetFormatField() != nullptr)
1262 SwTextInputField *const pTextInputField =
1263 dynamic_cast<SwTextInputField*>(GetFormatField()->GetTextField());
1264 if (pTextInputField != nullptr)
1266 bUnlock = pTextInputField->LockNotifyContentChange();
1269 pUserTyp->UpdateFields();
1270 if (bUnlock)
1272 SwTextInputField *const pTextInputField =
1273 dynamic_cast<SwTextInputField*>(GetFormatField()->GetTextField());
1274 if (pTextInputField != nullptr)
1276 pTextInputField->UnlockNotifyContentChange();
1284 OUString SwInputField::GetFieldName() const
1286 OUString aStr(SwField::GetFieldName());
1287 if ((mnSubType & 0x00ff) == INP_USR)
1289 aStr += GetTyp()->GetName() + " " + getContent();
1291 return aStr;
1294 std::unique_ptr<SwField> SwInputField::Copy() const
1296 std::unique_ptr<SwInputField> pField(
1297 new SwInputField(
1298 static_cast<SwInputFieldType*>(GetTyp()),
1299 getContent(),
1300 maPText,
1301 GetSubType(),
1302 GetFormat(),
1303 mbIsFormField ));
1305 pField->SetHelp( maHelp );
1306 pField->SetToolTip( maToolTip );
1308 pField->SetAutomaticLanguage(IsAutomaticLanguage());
1309 return std::unique_ptr<SwField>(pField.release());
1312 OUString SwInputField::ExpandImpl(SwRootFrame const*const) const
1314 if((mnSubType & 0x00ff) == INP_TXT)
1316 return getContent();
1319 if( (mnSubType & 0x00ff) == INP_USR )
1321 SwUserFieldType* pUserTyp = static_cast<SwUserFieldType*>(
1322 static_cast<SwInputFieldType*>(GetTyp())->GetDoc()->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::User, getContent(), false ) );
1323 if( pUserTyp )
1324 return pUserTyp->GetContent();
1327 return OUString();
1330 bool SwInputField::isFormField() const
1332 return mbIsFormField
1333 || !maHelp.isEmpty()
1334 || !maToolTip.isEmpty();
1337 bool SwInputField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
1339 switch( nWhichId )
1341 case FIELD_PROP_PAR1:
1342 rAny <<= getContent();
1343 break;
1344 case FIELD_PROP_PAR2:
1345 rAny <<= maPText;
1346 break;
1347 case FIELD_PROP_PAR3:
1348 rAny <<= maHelp;
1349 break;
1350 case FIELD_PROP_PAR4:
1351 rAny <<= maToolTip;
1352 break;
1353 default:
1354 assert(false);
1356 return true;
1359 bool SwInputField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
1361 switch( nWhichId )
1363 case FIELD_PROP_PAR1:
1364 rAny >>= maContent;
1365 break;
1366 case FIELD_PROP_PAR2:
1367 rAny >>= maPText;
1368 break;
1369 case FIELD_PROP_PAR3:
1370 rAny >>= maHelp;
1371 break;
1372 case FIELD_PROP_PAR4:
1373 rAny >>= maToolTip;
1374 break;
1375 default:
1376 assert(false);
1378 return true;
1381 /// set condition
1382 void SwInputField::SetPar1(const OUString& rStr)
1384 maContent = rStr;
1387 OUString SwInputField::GetPar1() const
1389 return getContent();
1392 void SwInputField::SetPar2(const OUString& rStr)
1394 maPText = rStr;
1397 OUString SwInputField::GetPar2() const
1399 return maPText;
1402 void SwInputField::SetHelp(const OUString & rStr)
1404 maHelp = rStr;
1407 const OUString& SwInputField::GetHelp() const
1409 return maHelp;
1412 void SwInputField::SetToolTip(const OUString & rStr)
1414 maToolTip = rStr;
1417 const OUString& SwInputField::GetToolTip() const
1419 return maToolTip;
1422 sal_uInt16 SwInputField::GetSubType() const
1424 return mnSubType;
1427 void SwInputField::SetSubType(sal_uInt16 nSub)
1429 mnSubType = nSub;
1432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */