android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / txtnode / atrfld.cxx
bloba9b98554f74ba55f57adc03c3d46d118fed31985
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 <fmtfld.hxx>
22 #include <libxml/xmlwriter.h>
24 #include <fldbas.hxx>
25 #include <txtfld.hxx>
26 #include <txtannotationfld.hxx>
27 #include <docfld.hxx>
28 #include <docufld.hxx>
29 #include <doc.hxx>
30 #include <unofield.hxx>
32 #include <pam.hxx>
33 #include <reffld.hxx>
34 #include <ddefld.hxx>
35 #include <usrfld.hxx>
36 #include <expfld.hxx>
37 #include <ndtxt.hxx>
38 #include <hints.hxx>
39 #include <IDocumentFieldsAccess.hxx>
40 #include <IDocumentMarkAccess.hxx>
41 #include <IDocumentLayoutAccess.hxx>
42 #include <fieldhint.hxx>
43 #include <sal/log.hxx>
44 #include <osl/diagnose.h>
47 // constructor for default item in attribute-pool
48 SwFormatField::SwFormatField( sal_uInt16 nWhich )
49 : SfxPoolItem( nWhich )
50 , SfxBroadcaster()
51 , mpTextField( nullptr )
55 SwFormatField::SwFormatField( const SwField &rField )
56 : SfxPoolItem( RES_TXTATR_FIELD )
57 , SfxBroadcaster()
58 , mpField( rField.CopyField() )
59 , mpTextField( nullptr )
61 rField.GetTyp()->Add(this);
62 if ( mpField->GetTyp()->Which() == SwFieldIds::Input )
64 // input field in-place editing
65 SetWhich( RES_TXTATR_INPUTFIELD );
66 static_cast<SwInputField*>(mpField.get())->SetFormatField( *this );
68 else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp)
70 // see SwWrtShell::StartInputFieldDlg
71 SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField.get()));
72 if (pSetField->GetInputFlag()
73 // only for string fields for now - inline editing of number fields
74 // tends to produce error messages...
75 && (static_cast<SwSetExpFieldType*>(pSetField->GetTyp())->GetType()
76 & nsSwGetSetExpType::GSE_STRING))
78 SetWhich( RES_TXTATR_INPUTFIELD );
80 pSetField->SetFormatField(*this);
82 else if ( mpField->GetTyp()->Which() == SwFieldIds::Postit )
84 // text annotation field
85 SetWhich( RES_TXTATR_ANNOTATION );
89 // #i24434#
90 // Since Items are used in ItemPool and in default constructed ItemSets with
91 // full pool range, all items need to be clonable. Thus, this one needed to be
92 // corrected
93 SwFormatField::SwFormatField( const SwFormatField& rAttr )
94 : SfxPoolItem( rAttr )
95 , SfxBroadcaster()
96 , mpTextField( nullptr )
98 if ( !rAttr.mpField )
99 return;
101 rAttr.mpField->GetTyp()->Add(this);
102 mpField = rAttr.mpField->CopyField();
103 if ( mpField->GetTyp()->Which() == SwFieldIds::Input )
105 // input field in-place editing
106 SetWhich( RES_TXTATR_INPUTFIELD );
107 SwInputField *pField = dynamic_cast<SwInputField*>(mpField.get());
108 assert(pField);
109 if (pField)
110 pField->SetFormatField( *this );
112 else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp)
114 SwSetExpField *const pSetField(static_cast<SwSetExpField *>(mpField.get()));
115 if (pSetField->GetInputFlag()
116 && (static_cast<SwSetExpFieldType*>(pSetField->GetTyp())->GetType()
117 & nsSwGetSetExpType::GSE_STRING))
119 SetWhich( RES_TXTATR_INPUTFIELD );
121 // see SwWrtShell::StartInputFieldDlg
122 pSetField->SetFormatField(*this);
124 else if ( mpField->GetTyp()->Which() == SwFieldIds::Postit )
126 // text annotation field
127 SetWhich( RES_TXTATR_ANNOTATION );
131 SwFormatField::~SwFormatField()
133 SwFieldType* pType = mpField ? mpField->GetTyp() : nullptr;
135 if (pType && pType->Which() == SwFieldIds::Database)
136 pType = nullptr; // DB field types destroy themselves
138 Broadcast( SwFormatFieldHint( this, SwFormatFieldHintWhich::REMOVED ) );
139 mpField.reset();
141 // some fields need to delete their field type
142 if( !(pType && pType->HasOnlyOneListener()) )
143 return;
145 bool bDel = false;
146 switch( pType->Which() )
148 case SwFieldIds::User:
149 bDel = static_cast<SwUserFieldType*>(pType)->IsDeleted();
150 break;
152 case SwFieldIds::SetExp:
153 bDel = static_cast<SwSetExpFieldType*>(pType)->IsDeleted();
154 break;
156 case SwFieldIds::Dde:
157 bDel = static_cast<SwDDEFieldType*>(pType)->IsDeleted();
158 break;
159 default: break;
162 if( bDel )
164 // unregister before deleting
165 pType->Remove( this );
166 delete pType;
170 void SwFormatField::RegisterToFieldType( SwFieldType& rType )
172 rType.Add(this);
175 void SwFormatField::SetField(std::unique_ptr<SwField> _pField)
177 mpField = std::move(_pField);
178 if ( mpField->GetTyp()->Which() == SwFieldIds::Input )
180 static_cast<SwInputField* >(mpField.get())->SetFormatField( *this );
182 else if (mpField->GetTyp()->Which() == SwFieldIds::SetExp)
184 // see SwWrtShell::StartInputFieldDlg
185 static_cast<SwSetExpField *>(mpField.get())->SetFormatField(*this);
187 Broadcast( SwFormatFieldHint( this, SwFormatFieldHintWhich::CHANGED ) );
190 void SwFormatField::SetTextField( SwTextField& rTextField )
192 mpTextField = &rTextField;
195 void SwFormatField::ClearTextField()
197 mpTextField = nullptr;
200 bool SwFormatField::operator==( const SfxPoolItem& rAttr ) const
202 assert(SfxPoolItem::operator==(rAttr));
203 return ( mpField
204 && static_cast<const SwFormatField&>(rAttr).mpField
205 && mpField->GetTyp() == static_cast<const SwFormatField&>(rAttr).mpField->GetTyp()
206 && mpField->GetFormat() == static_cast<const SwFormatField&>(rAttr).mpField->GetFormat() )
208 ( !mpField && !static_cast<const SwFormatField&>(rAttr).mpField );
211 SwFormatField* SwFormatField::Clone( SfxItemPool* ) const
213 return new SwFormatField( *this );
216 void SwFormatField::InvalidateField()
218 const SwPtrMsgPoolItem aItem(RES_REMOVE_UNO_OBJECT, &static_cast<sw::BroadcastingModify&>(*this));
219 CallSwClientNotify(sw::LegacyModifyHint{ &aItem, &aItem });
222 void SwFormatField::SwClientNotify( const SwModify& rModify, const SfxHint& rHint )
224 SwClient::SwClientNotify(rModify, rHint);
225 if (rHint.GetId() == SfxHintId::SwField)
227 const auto pFieldHint = static_cast<const SwFieldHint*>( &rHint );
228 // replace field content by text
229 SwPaM* pPaM = pFieldHint->m_pPaM;
230 pPaM->DeleteMark(); // TODO: this is really hackish
232 if( !mpTextField )
233 return;
235 SwDoc& rDoc = pPaM->GetDoc();
236 const SwTextNode& rTextNode = mpTextField->GetTextNode();
237 pPaM->GetPoint()->Assign(rTextNode, mpTextField->GetStart());
239 OUString const aEntry(mpField->ExpandField(rDoc.IsClipBoard(), pFieldHint->m_pLayout));
240 pPaM->SetMark();
241 pPaM->Move( fnMoveForward );
242 rDoc.getIDocumentContentOperations().DeleteRange( *pPaM );
243 rDoc.getIDocumentContentOperations().InsertString( *pPaM, aEntry );
245 else if (rHint.GetId() == SfxHintId::SwLegacyModify)
247 if(!mpTextField)
248 return;
249 UpdateTextNode(rHint);
251 else if (rHint.GetId() == SfxHintId::SwFindFormatForField)
253 const auto pFindForFieldHint = static_cast<const sw::FindFormatForFieldHint*>( &rHint );
254 if(pFindForFieldHint->m_rpFormat == nullptr && pFindForFieldHint->m_pField == GetField())
255 pFindForFieldHint->m_rpFormat = this;
257 else if (rHint.GetId() == SfxHintId::SwFindFormatForPostItId)
259 const auto pFindForPostItIdHint = static_cast<const sw::FindFormatForPostItIdHint*>( &rHint );
260 auto pPostItField = dynamic_cast<SwPostItField*>(mpField.get());
261 if(pPostItField && pFindForPostItIdHint->m_rpFormat == nullptr && pFindForPostItIdHint->m_nPostItId == pPostItField->GetPostItId())
262 pFindForPostItIdHint->m_rpFormat = this;
264 else if (rHint.GetId() == SfxHintId::SwCollectPostIts)
266 const auto pCollectPostItsHint = static_cast<const sw::CollectPostItsHint*>( &rHint );
267 if(GetTextField() && IsFieldInDoc() && (!pCollectPostItsHint->m_bHideRedlines || !sw::IsFieldDeletedInModel(pCollectPostItsHint->m_rIDRA, *GetTextField())))
268 pCollectPostItsHint->m_rvFormatFields.push_back(this);
270 else if (rHint.GetId() == SfxHintId::SwHasHiddenInformationNotes)
272 const auto pHasHiddenInfoHint = static_cast<const sw::HasHiddenInformationNotesHint*>( &rHint );
273 if(!pHasHiddenInfoHint->m_rbHasHiddenInformationNotes && GetTextField() && IsFieldInDoc())
274 pHasHiddenInfoHint->m_rbHasHiddenInformationNotes = true;
276 else if (rHint.GetId() == SfxHintId::SwGatherNodeIndex)
278 const auto pGatherNodeIndexHint = static_cast<const sw::GatherNodeIndexHint*>( &rHint );
279 if(auto pTextField = GetTextField())
280 pGatherNodeIndexHint->m_rvNodeIndex.push_back(pTextField->GetTextNode().GetIndex());
282 else if (rHint.GetId() == SfxHintId::SwGatherRefFields)
284 const auto pGatherRefFieldsHint = static_cast<const sw::GatherRefFieldsHint*>( &rHint );
285 if(!GetTextField() || pGatherRefFieldsHint->m_nType != GetField()->GetSubType())
286 return;
287 SwTextNode* pNd = GetTextField()->GetpTextNode();
288 if(pNd && pNd->GetNodes().IsDocNodes())
289 pGatherRefFieldsHint->m_rvRFields.push_back(static_cast<SwGetRefField*>(GetField()));
291 else if (rHint.GetId() == SfxHintId::SwGatherFields)
293 const auto pGatherFieldsHint = static_cast<const sw::GatherFieldsHint*>( &rHint );
294 if(pGatherFieldsHint->m_bCollectOnlyInDocNodes)
296 if(!GetTextField())
297 return;
298 SwTextNode* pNd = GetTextField()->GetpTextNode();
299 if(!pNd || !pNd->GetNodes().IsDocNodes())
300 return;
302 pGatherFieldsHint->m_rvFields.push_back(this);
304 else if (rHint.GetId() == SfxHintId::SwDocPosUpdate)
306 UpdateDocPos(static_cast<const sw::DocPosUpdate*>(&rHint)->m_nDocPos);
310 namespace
312 bool lcl_ExpandField(const SwFieldIds eId, const bool bHiddenParaPrint)
314 switch(eId)
316 case SwFieldIds::HiddenPara:
317 return !bHiddenParaPrint;
318 case SwFieldIds::DbSetNumber:
319 case SwFieldIds::DbNumSet:
320 case SwFieldIds::DbNextSet:
321 case SwFieldIds::DatabaseName:
322 return false;
323 default:
324 return true;
328 bool lcl_TriggerNode(const SwFieldIds eId)
330 switch(eId)
332 case SwFieldIds::HiddenPara:
333 case SwFieldIds::DbSetNumber:
334 case SwFieldIds::DbNumSet:
335 case SwFieldIds::DbNextSet:
336 case SwFieldIds::DatabaseName:
337 return true;
338 default:
339 return false;
342 void lcl_EnsureUserFieldValid(SwFieldType& rType)
344 if(rType.Which() != SwFieldIds::User)
345 return;
346 static_cast<SwUserFieldType*>(&rType)->EnsureValid();
348 bool lcl_NeedsForcedUpdate(const SwField& rField)
350 if (rField.GetTyp()->Which() == SwFieldIds::DocInfo)
352 auto pDocInfoField = static_cast<const SwDocInfoField*>(&rField);
353 sal_uInt16 nSubType = pDocInfoField->GetSubType();
354 // Do not consider extended SubTypes.
355 nSubType &= 0xff;
356 switch (nSubType)
358 case nsSwDocInfoSubType::DI_TITLE:
359 case nsSwDocInfoSubType::DI_SUBJECT:
360 case nsSwDocInfoSubType::DI_CHANGE:
361 case nsSwDocInfoSubType::DI_CUSTOM:
362 return false;
365 return true;
369 void SwFormatField::ForceUpdateTextNode()
371 if (!IsFieldInDoc())
372 return;
374 SwTextNode* pTextNd = &mpTextField->GetTextNode();
375 OSL_ENSURE(pTextNd, "Where is my Node?");
377 auto pType = mpField->GetTyp();
378 lcl_EnsureUserFieldValid(*pType);
379 if(lcl_TriggerNode(pType->Which()))
380 pTextNd->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, nullptr));
381 if(!lcl_ExpandField(pType->Which(), false))
382 return;
384 // Force notify was added for conditional text fields,
385 // at least the below fields need no forced notify.
386 bool bNeedForced = lcl_NeedsForcedUpdate(*mpTextField->GetFormatField().GetField());
387 mpTextField->ExpandTextField(bNeedForced);
389 void SwFormatField::UpdateDocPos(const SwTwips nDocPos)
391 if (!IsFieldInDoc())
392 return;
393 auto pTextNd = &mpTextField->GetTextNode();
395 pTextNd->UpdateDocPos(nDocPos, mpTextField->GetStart());
397 void SwFormatField::UpdateTextNode(const SfxHint& rHint)
399 if(SfxHintId::SwLegacyModify != rHint.GetId())
400 return;
401 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
402 auto pOld = pLegacy->m_pOld;
403 auto pNew = pLegacy->m_pNew;
404 if (pOld == nullptr && pNew == nullptr)
406 ForceUpdateTextNode();
407 return;
409 else if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
410 { // invalidate cached UNO object
411 m_wXTextField.clear();
412 // ??? why does this Modify method not already do this?
413 CallSwClientNotify(sw::LegacyModifyHint(pOld, pNew));
414 return;
417 if (!IsFieldInDoc())
418 return;
420 // don't do anything, especially not expand!
421 if( pNew && pNew->Which() == RES_OBJECTDYING )
422 return;
424 SwTextNode* pTextNd = &mpTextField->GetTextNode();
425 OSL_ENSURE(pTextNd, "Where is my Node?");
427 bool bTriggerNode = pNew != nullptr;
428 bool bExpand = false;
429 if(pNew)
431 switch(pNew->Which())
433 case RES_ATTRSET_CHG:
434 case RES_FMT_CHG:
435 break;
436 default:
438 auto pType = mpField->GetTyp();
439 lcl_EnsureUserFieldValid(*pType);
440 bTriggerNode = lcl_TriggerNode(pType->Which());
441 bExpand = lcl_ExpandField(pType->Which(), pOld && pOld->Which() == RES_HIDDENPARA_PRINT);
442 pOld = nullptr;
446 if(bTriggerNode)
447 pTextNd->TriggerNodeUpdate(sw::LegacyModifyHint(pOld, pNew));
448 if(bExpand)
449 mpTextField->ExpandTextField(false);
452 bool SwFormatField::GetInfo( SfxPoolItem& rInfo ) const
454 if( RES_AUTOFMT_DOCNODE != rInfo.Which() || !mpTextField )
455 return true;
456 const SwTextNode* pTextNd = mpTextField->GetpTextNode();
457 return nullptr == pTextNd ||
458 &pTextNd->GetNodes() != static_cast<SwAutoFormatGetDocNode&>(rInfo).pNodes;
461 bool SwFormatField::IsFieldInDoc() const
463 return mpTextField != nullptr
464 && mpTextField->IsFieldInDoc();
467 bool SwFormatField::IsProtect() const
469 return mpTextField != nullptr
470 && mpTextField->GetpTextNode() != nullptr
471 && mpTextField->GetpTextNode()->IsProtect();
474 void SwFormatField::dumpAsXml(xmlTextWriterPtr pWriter) const
476 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatField"));
477 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
478 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("mpTextField"), "%p", mpTextField);
480 SfxPoolItem::dumpAsXml(pWriter);
481 if (mpField) // pool default doesn't have one
483 mpField->dumpAsXml(pWriter);
486 (void)xmlTextWriterEndElement(pWriter);
489 // class SwTextField ////////////////////////////////////////////////////
491 SwTextField::SwTextField(
492 SwFormatField & rAttr,
493 sal_Int32 const nStartPos,
494 bool const bInClipboard)
495 : SwTextAttr( rAttr, nStartPos )
496 // fdo#39694 the ExpandField here may not give the correct result in all cases,
497 // but is better than nothing
498 , m_aExpand( rAttr.GetField()->ExpandField(bInClipboard, nullptr) )
499 , m_pTextNode( nullptr )
501 rAttr.SetTextField( *this );
502 SetHasDummyChar(true);
505 SwTextField::~SwTextField( )
507 SwFormatField & rFormatField( static_cast<SwFormatField &>(GetAttr()) );
508 if ( this == rFormatField.GetTextField() )
510 rFormatField.ClearTextField();
514 bool SwTextField::IsFieldInDoc() const
516 return GetpTextNode() != nullptr
517 && GetpTextNode()->GetNodes().IsDocNodes();
520 void SwTextField::ExpandTextField(const bool bForceNotify) const
522 OSL_ENSURE( m_pTextNode, "SwTextField: where is my TextNode?" );
524 const SwField* pField = GetFormatField().GetField();
525 const OUString aNewExpand( pField->ExpandField(m_pTextNode->GetDoc().IsClipBoard(),
526 // can't do any better than this here...
527 m_pTextNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()) );
529 const SwFieldIds nWhich = pField->GetTyp()->Which();
530 const bool bSameExpandSimpleNotification
531 = SwFieldIds::Chapter != nWhich && SwFieldIds::PageNumber != nWhich
532 && SwFieldIds::RefPageGet != nWhich
533 // Page count fields to not use aExpand during formatting,
534 // therefore an invalidation of the text frame has to be triggered even if aNewExpand == aExpand:
535 && (SwFieldIds::DocStat != nWhich
536 || DS_PAGE != static_cast<const SwDocStatField*>(pField)->GetSubType())
537 && (SwFieldIds::GetExp != nWhich
538 || static_cast<const SwGetExpField*>(pField)->IsInBodyText());
540 bool bHiddenParaChanged = false;
541 if (aNewExpand != m_aExpand || bSameExpandSimpleNotification)
542 bHiddenParaChanged = m_pTextNode->CalcHiddenParaField();
544 if (aNewExpand == m_aExpand)
546 if ( bSameExpandSimpleNotification )
548 if( bHiddenParaChanged )
549 m_pTextNode->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, nullptr));
550 if ( !bForceNotify )
552 // done, if no further notification forced.
553 return;
557 else
558 m_aExpand = aNewExpand;
560 const_cast<SwTextField*>(this)->NotifyContentChange( const_cast<SwFormatField&>(GetFormatField()) );
563 void SwTextField::CopyTextField( SwTextField *pDest ) const
565 OSL_ENSURE( m_pTextNode, "SwTextField: where is my TextNode?" );
566 OSL_ENSURE( pDest->m_pTextNode, "SwTextField: where is pDest's TextNode?" );
568 IDocumentFieldsAccess* pIDFA = &m_pTextNode->getIDocumentFieldsAccess();
569 IDocumentFieldsAccess* pDestIDFA = &pDest->m_pTextNode->getIDocumentFieldsAccess();
571 SwFormatField& rDestFormatField = const_cast<SwFormatField&>(pDest->GetFormatField());
572 const SwFieldIds nFieldWhich = rDestFormatField.GetField()->GetTyp()->Which();
574 if( pIDFA != pDestIDFA )
576 // different documents, e.g. clipboard:
577 // register field type in target document
578 SwFieldType* pFieldType;
579 if( nFieldWhich != SwFieldIds::Database
580 && nFieldWhich != SwFieldIds::User
581 && nFieldWhich != SwFieldIds::SetExp
582 && nFieldWhich != SwFieldIds::Dde
583 && SwFieldIds::TableOfAuthorities != nFieldWhich )
585 pFieldType = pDestIDFA->GetSysFieldType( nFieldWhich );
587 else
589 pFieldType = pDestIDFA->InsertFieldType( *rDestFormatField.GetField()->GetTyp() );
592 // DDE fields need special treatment
593 if( SwFieldIds::Dde == nFieldWhich )
595 if( rDestFormatField.GetTextField() )
597 static_cast<SwDDEFieldType*>(rDestFormatField.GetField()->GetTyp())->DecRefCnt();
599 static_cast<SwDDEFieldType*>(pFieldType)->IncRefCnt();
602 OSL_ENSURE( pFieldType, "unknown FieldType" );
603 pFieldType->Add( &rDestFormatField ); // register at the field type
604 rDestFormatField.GetField()->ChgTyp( pFieldType );
607 // update expression fields
608 if( nFieldWhich == SwFieldIds::SetExp
609 || nFieldWhich == SwFieldIds::GetExp
610 || nFieldWhich == SwFieldIds::HiddenText )
612 SwTextField* pField = const_cast<SwTextField*>(this);
613 pDestIDFA->UpdateExpFields( pField, true );
615 // table fields: external display
616 else if( SwFieldIds::Table == nFieldWhich
617 && static_cast<SwTableField*>(rDestFormatField.GetField())->IsIntrnlName() )
619 // convert internal (core) to external (UI) formula
620 const SwTableNode* pTableNd = m_pTextNode->FindTableNode();
621 if( pTableNd ) // in a table?
622 static_cast<SwTableField*>(rDestFormatField.GetField())->PtrToBoxNm( &pTableNd->GetTable() );
626 void SwTextField::NotifyContentChange(SwFormatField& rFormatField)
628 //if not in undo section notify the change
629 if (m_pTextNode && m_pTextNode->GetNodes().IsDocNodes())
630 m_pTextNode->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, &rFormatField));
633 /*static*/
634 void SwTextField::GetPamForTextField(
635 const SwTextField& rTextField,
636 std::shared_ptr< SwPaM >& rPamForTextField )
638 if (rTextField.GetpTextNode() == nullptr)
640 SAL_WARN("sw.core", "<SwTextField::GetPamForField> - missing <SwTextNode>");
641 return;
644 const SwTextNode& rTextNode = rTextField.GetTextNode();
646 rPamForTextField = std::make_shared<SwPaM>( rTextNode,
647 (rTextField.End() != nullptr) ? *(rTextField.End()) : ( rTextField.GetStart() + 1 ),
648 rTextNode,
649 rTextField.GetStart() );
653 /*static*/
654 void SwTextField::DeleteTextField( const SwTextField& rTextField )
656 if (rTextField.GetpTextNode() != nullptr)
658 std::shared_ptr< SwPaM > pPamForTextField;
659 GetPamForTextField(rTextField, pPamForTextField);
660 if (pPamForTextField != nullptr)
662 rTextField.GetTextNode().GetDoc().getIDocumentContentOperations().DeleteAndJoin(*pPamForTextField);
667 // class SwTextInputField ///////////////////////////////////////////////
669 // input field in-place editing
670 SwTextInputField::SwTextInputField(
671 SwFormatField & rAttr,
672 sal_Int32 const nStart,
673 sal_Int32 const nEnd,
674 bool const bInClipboard )
676 : SwTextAttr( rAttr, nStart )
677 , SwTextAttrNesting( rAttr, nStart, nEnd )
678 , SwTextField( rAttr, nStart, bInClipboard )
679 , m_bLockNotifyContentChange( false )
681 SetHasDummyChar( false );
682 SetHasContent( true );
685 SwTextInputField::~SwTextInputField()
689 bool SwTextInputField::LockNotifyContentChange()
691 if (m_bLockNotifyContentChange)
693 return false;
695 m_bLockNotifyContentChange = true;
696 return true;
699 void SwTextInputField::UnlockNotifyContentChange()
701 m_bLockNotifyContentChange = false;
704 void SwTextInputField::NotifyContentChange( SwFormatField& rFormatField )
706 if ( !m_bLockNotifyContentChange )
708 LockNotifyContentChange();
710 SwTextField::NotifyContentChange( rFormatField );
711 UpdateTextNodeContent( GetFieldContent() );
713 UnlockNotifyContentChange();
717 OUString SwTextInputField::GetFieldContent() const
719 return GetFormatField().GetField()->ExpandField(false, nullptr/*ignored anyway*/);
722 void SwTextInputField::UpdateFieldContent()
724 if ( !(IsFieldInDoc()
725 && GetStart() != (*End())) )
726 return;
728 assert( (*End()) - GetStart() >= 2 &&
729 "<SwTextInputField::UpdateFieldContent()> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
730 // skip CH_TXT_ATR_INPUTFIELDSTART character
731 const sal_Int32 nIdx = GetStart() + 1;
732 // skip CH_TXT_ATR_INPUTFIELDEND character
733 const sal_Int32 nLen = static_cast<sal_Int32>(std::max<sal_Int32>( 0, ( (*End()) - 1 - nIdx ) ));
734 const OUString aNewFieldContent = GetTextNode().GetExpandText(nullptr, nIdx, nLen);
736 const SwField* pField = GetFormatField().GetField();
737 const SwInputField* pInputField = dynamic_cast<const SwInputField*>(pField);
738 if (pInputField)
739 const_cast<SwInputField*>(pInputField)->applyFieldContent( aNewFieldContent );
741 const SwSetExpField* pExpField = dynamic_cast<const SwSetExpField*>(pField);
742 if (pExpField)
744 assert(pExpField->GetInputFlag());
745 const_cast<SwSetExpField*>(pExpField)->SetPar2(aNewFieldContent);
747 assert(pInputField || pExpField);
749 // trigger update of fields for scenarios in which the Input Field's content is part of e.g. a table formula
750 GetTextNode().GetDoc().getIDocumentFieldsAccess().GetUpdateFields().SetFieldsDirty(true);
753 void SwTextInputField::UpdateTextNodeContent( const OUString& rNewContent )
755 assert(IsFieldInDoc() &&
756 "<SwTextInputField::UpdateTextNodeContent(..)> - misusage as Input Field is not in document content.");
758 assert( (*End()) - GetStart() >= 2 &&
759 "<SwTextInputField::UpdateTextNodeContent(..)> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
760 // skip CH_TXT_ATR_INPUTFIELDSTART character
761 const sal_Int32 nIdx = GetStart() + 1;
762 // skip CH_TXT_ATR_INPUTFIELDEND character
763 const sal_Int32 nDelLen = std::max<sal_Int32>( 0, ( (*End()) - 1 - nIdx ) );
764 SwContentIndex aIdx( &GetTextNode(), nIdx );
765 GetTextNode().ReplaceText( aIdx, nDelLen, rNewContent );
768 // class SwTextAnnotationField //////////////////////////////////////////
770 // text annotation field
771 SwTextAnnotationField::SwTextAnnotationField(
772 SwFormatField & rAttr,
773 sal_Int32 const nStart,
774 bool const bInClipboard )
775 : SwTextAttr( rAttr, nStart )
776 , SwTextField( rAttr, nStart, bInClipboard )
780 SwTextAnnotationField::~SwTextAnnotationField()
784 ::sw::mark::IMark* SwTextAnnotationField::GetAnnotationMark() const
786 auto pPostItField = dynamic_cast<const SwPostItField*>(GetFormatField().GetField());
787 assert(pPostItField);
789 SwDoc& rDoc = static_cast<const SwPostItFieldType*>(pPostItField->GetTyp())->GetDoc();
791 IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess();
792 IDocumentMarkAccess::const_iterator_t pMark = pMarksAccess->findAnnotationMark( pPostItField->GetName() );
793 return pMark != pMarksAccess->getAnnotationMarksEnd()
794 ? *pMark
795 : nullptr;
798 void SwFormatField::SetXTextField(rtl::Reference<SwXTextField> const& xTextField)
799 { m_wXTextField = xTextField.get(); }
801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */