1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <formatcontentcontrol.hxx>
22 #include <libxml/xmlwriter.h>
24 #include <sal/log.hxx>
25 #include <comphelper/propertyvalue.hxx>
26 #include <comphelper/sequenceashashmap.hxx>
27 #include <svl/numformat.hxx>
28 #include <vcl/keycod.hxx>
31 #include <textcontentcontrol.hxx>
33 #include <unocontentcontrol.hxx>
36 using namespace com::sun::star
;
40 inline constexpr OUStringLiteral CURRENT_DATE_FORMAT
= u
"YYYY-MM-DD";
43 SwFormatContentControl
* SwFormatContentControl::CreatePoolDefault(sal_uInt16 nWhich
)
45 return new SwFormatContentControl(nWhich
);
48 SwFormatContentControl::SwFormatContentControl(sal_uInt16 nWhich
)
50 , m_pTextAttr(nullptr)
54 SwFormatContentControl::SwFormatContentControl(
55 const std::shared_ptr
<SwContentControl
>& pContentControl
, sal_uInt16 nWhich
)
57 , m_pContentControl(pContentControl
)
58 , m_pTextAttr(nullptr)
62 SAL_WARN("sw.core", "SwFormatContentControl ctor: no pContentControl?");
64 // Not calling m_pContentControl->SetFormatContentControl(this) here; only from SetTextAttr.
67 SwFormatContentControl::~SwFormatContentControl()
69 if (m_pContentControl
&& (m_pContentControl
->GetFormatContentControl() == this))
71 NotifyChangeTextNode(nullptr);
72 m_pContentControl
->SetFormatContentControl(nullptr);
76 bool SwFormatContentControl::operator==(const SfxPoolItem
& rOther
) const
78 return SfxPoolItem::operator==(rOther
)
80 == static_cast<const SwFormatContentControl
&>(rOther
).m_pContentControl
;
83 SwFormatContentControl
* SwFormatContentControl::Clone(SfxItemPool
* /*pPool*/) const
85 // If this is indeed a copy, then DoCopy will be called later.
86 if (m_pContentControl
)
88 return new SwFormatContentControl(m_pContentControl
, Which());
92 return new SwFormatContentControl(Which());
96 void SwFormatContentControl::SetTextAttr(SwTextContentControl
* pTextAttr
)
98 if (m_pTextAttr
&& pTextAttr
)
100 SAL_WARN("sw.core", "SwFormatContentControl::SetTextAttr: already has a text attribute");
102 if (!m_pTextAttr
&& !pTextAttr
)
104 SAL_WARN("sw.core", "SwFormatContentControl::SetTextAttr: no attribute to remove");
106 m_pTextAttr
= pTextAttr
;
107 if (!m_pContentControl
)
109 SAL_WARN("sw.core", "inserted SwFormatContentControl has no SwContentControl");
111 // The SwContentControl should be able to find the current text attribute.
112 if (m_pContentControl
)
116 m_pContentControl
->SetFormatContentControl(this);
118 else if (m_pContentControl
->GetFormatContentControl() == this)
120 // The text attribute is gone, so de-register from text node.
121 NotifyChangeTextNode(nullptr);
122 m_pContentControl
->SetFormatContentControl(nullptr);
127 void SwFormatContentControl::NotifyChangeTextNode(SwTextNode
* pTextNode
)
129 // Not deleting m_pTextAttr here, SwNodes::ChgNode() doesn't do that, either.
130 if (!m_pContentControl
)
132 SAL_WARN("sw.core", "SwFormatContentControl::NotifyChangeTextNode: no content control?");
134 if (m_pContentControl
&& (m_pContentControl
->GetFormatContentControl() == this))
136 // Not calling Modify, that would call SwXContentControl::SwClientNotify.
137 m_pContentControl
->NotifyChangeTextNode(pTextNode
);
141 SwTextNode
* SwFormatContentControl::GetTextNode() const
143 if (!m_pContentControl
)
148 return m_pContentControl
->GetTextNode();
151 // This SwFormatContentControl has been cloned and points at the same SwContentControl as the
152 // source: this function copies the SwContentControl.
153 void SwFormatContentControl::DoCopy(SwTextNode
& rTargetTextNode
)
155 if (!m_pContentControl
)
157 SAL_WARN("sw.core", "SwFormatContentControl::DoCopy: called for SwFormatContentControl "
158 "with no SwContentControl.");
162 m_pContentControl
= std::make_shared
<SwContentControl
>(this);
163 m_pContentControl
->NotifyChangeTextNode(&rTargetTextNode
);
166 void SwFormatContentControl::dumpAsXml(xmlTextWriterPtr pWriter
) const
168 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwFormatContentControl"));
169 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
170 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("m_pTextAttr"), "%p", m_pTextAttr
);
171 SfxPoolItem::dumpAsXml(pWriter
);
173 if (m_pContentControl
)
175 m_pContentControl
->dumpAsXml(pWriter
);
178 (void)xmlTextWriterEndElement(pWriter
);
181 SwContentControl::SwContentControl(SwFormatContentControl
* pFormat
)
182 : sw::BroadcastingModify()
184 , m_pTextNode(nullptr)
191 const std::shared_ptr
<SwContentControl
>& pOther
= pFormat
->GetContentControl();
197 SetShowingPlaceHolder(pOther
->m_bShowingPlaceHolder
);
198 SetCheckbox(pOther
->m_bCheckbox
);
199 SetChecked(pOther
->m_bChecked
);
200 SetCheckedState(pOther
->m_aCheckedState
);
201 SetUncheckedState(pOther
->m_aUncheckedState
);
202 SetListItems(pOther
->m_aListItems
);
203 SetPicture(pOther
->m_bPicture
);
204 SetDate(pOther
->m_bDate
);
205 SetDateFormat(pOther
->m_aDateFormat
);
206 SetDateLanguage(pOther
->m_aDateLanguage
);
207 SetCurrentDate(pOther
->m_aCurrentDate
);
208 SetPlainText(pOther
->m_bPlainText
);
209 SetComboBox(pOther
->m_bComboBox
);
210 SetDropDown(pOther
->m_bDropDown
);
211 SetPlaceholderDocPart(pOther
->m_aPlaceholderDocPart
);
212 SetDataBindingPrefixMappings(pOther
->m_aDataBindingPrefixMappings
);
213 SetDataBindingXpath(pOther
->m_aDataBindingXpath
);
214 SetDataBindingStoreItemID(pOther
->m_aDataBindingStoreItemID
);
215 SetColor(pOther
->m_aColor
);
216 SetAppearance(pOther
->m_aAppearance
);
217 SetAlias(pOther
->m_aAlias
);
218 SetTag(pOther
->m_aTag
);
219 SetId(pOther
->m_nId
);
220 SetTabIndex(pOther
->m_nTabIndex
);
221 SetLock(pOther
->m_aLock
);
224 SwContentControl::~SwContentControl() {}
226 void SwContentControl::SetXContentControl(const rtl::Reference
<SwXContentControl
>& xContentControl
)
228 m_wXContentControl
= xContentControl
.get();
231 SwTextContentControl
* SwContentControl::GetTextAttr() const
233 return m_pFormat
? m_pFormat
->GetTextAttr() : nullptr;
236 void SwContentControl::NotifyChangeTextNode(SwTextNode
* pTextNode
)
238 m_pTextNode
= pTextNode
;
239 if (m_pTextNode
&& (GetRegisteredIn() != m_pTextNode
))
241 m_pTextNode
->Add(this);
243 else if (!m_pTextNode
)
249 // If the text node is gone, then invalidate clients (e.g. UNO object).
250 GetNotifier().Broadcast(SfxHint(SfxHintId::Deinitializing
));
254 void SwContentControl::SwClientNotify(const SwModify
&, const SfxHint
& rHint
)
256 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
259 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
260 CallSwClientNotify(rHint
);
261 GetNotifier().Broadcast(SfxHint(SfxHintId::DataChanged
));
263 if (pLegacy
->GetWhich() == RES_REMOVE_UNO_OBJECT
)
265 // Invalidate cached uno object.
266 SetXContentControl(nullptr);
267 GetNotifier().Broadcast(SfxHint(SfxHintId::Deinitializing
));
271 std::optional
<size_t> SwContentControl::GetSelectedListItem(bool bCheckDocModel
) const
273 if (!bCheckDocModel
|| m_oSelectedListItem
)
274 return m_oSelectedListItem
;
276 const size_t nLen
= GetListItems().size();
277 if (GetShowingPlaceHolder() || !nLen
|| !GetTextAttr())
280 const OUString
& rText
= GetTextAttr()->ToString();
281 for (size_t i
= 0; i
< nLen
; ++i
)
283 if (GetTextAttr()[i
].ToString() == rText
)
286 assert(!GetDropDown() && "DropDowns must always have an associated list item");
290 bool SwContentControl::AddListItem(size_t nZIndex
, const OUString
& rDisplayText
,
291 const OUString
& rValue
)
293 SwContentControlListItem aListItem
;
294 if (rValue
.isEmpty())
296 if (rDisplayText
.isEmpty())
298 aListItem
.m_aValue
= rDisplayText
;
302 aListItem
.m_aValue
= rValue
;
303 aListItem
.m_aDisplayText
= rDisplayText
;
306 // Avoid adding duplicates
307 for (auto& rListItem
: GetListItems())
309 if (rListItem
== aListItem
)
313 const size_t nLen
= GetListItems().size();
314 nZIndex
= std::min(nZIndex
, nLen
);
315 const std::optional
<size_t> oSelected
= GetSelectedListItem();
316 if (oSelected
&& *oSelected
>= nZIndex
)
318 if (*oSelected
< nLen
)
319 SetSelectedListItem(*oSelected
+ 1);
321 std::vector
<SwContentControlListItem
> vListItems
= GetListItems();
322 vListItems
.insert(vListItems
.begin() + nZIndex
, aListItem
);
323 SetListItems(vListItems
);
327 void SwContentControl::DeleteListItem(size_t nZIndex
)
329 if (nZIndex
>= GetListItems().size())
332 const std::optional
<size_t> oSelected
= GetSelectedListItem();
335 if (*oSelected
== nZIndex
)
337 SetSelectedListItem(std::nullopt
);
338 if (m_bDropDown
&& GetTextAttr())
339 GetTextAttr()->Invalidate();
341 else if (*oSelected
< nZIndex
)
342 SetSelectedListItem(*oSelected
- 1);
345 std::vector
<SwContentControlListItem
> vListItems
= GetListItems();
346 vListItems
.erase(vListItems
.begin() + nZIndex
);
347 SetListItems(vListItems
);
351 void SwContentControl::ClearListItems()
353 SetSelectedListItem(std::nullopt
);
354 SetListItems(std::vector
<SwContentControlListItem
>());
355 if (m_bDropDown
&& GetTextAttr())
356 GetTextAttr()->Invalidate();
359 OUString
SwContentControl::GetDateString() const
361 SwDoc
& rDoc
= m_pTextNode
->GetDoc();
362 SvNumberFormatter
* pNumberFormatter
= rDoc
.GetNumberFormatter();
363 sal_uInt32 nFormat
= pNumberFormatter
->GetEntryKey(
364 m_aDateFormat
, LanguageTag(m_aDateLanguage
).getLanguageType());
366 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
368 // If not found, then create it.
369 sal_Int32 nCheckPos
= 0;
370 SvNumFormatType nType
;
371 OUString aFormat
= m_aDateFormat
;
372 pNumberFormatter
->PutEntry(aFormat
, nCheckPos
, nType
, nFormat
,
373 LanguageTag(m_aDateLanguage
).getLanguageType());
376 const Color
* pColor
= nullptr;
378 double fSelectedDate
= 0;
381 fSelectedDate
= *m_oSelectedDate
;
385 fSelectedDate
= GetCurrentDateValue();
388 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
393 pNumberFormatter
->GetOutputString(fSelectedDate
, nFormat
, aFormatted
, &pColor
, false);
397 void SwContentControl::SetCurrentDateValue(double fCurrentDate
)
399 SwDoc
& rDoc
= m_pTextNode
->GetDoc();
400 SvNumberFormatter
* pNumberFormatter
= rDoc
.GetNumberFormatter();
402 sal_uInt32 nFormat
= pNumberFormatter
->GetEntryKey(CURRENT_DATE_FORMAT
, LANGUAGE_ENGLISH_US
);
403 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
405 // If not found, then create it.
406 sal_Int32 nCheckPos
= 0;
407 SvNumFormatType nType
;
408 OUString sFormat
= CURRENT_DATE_FORMAT
;
409 pNumberFormatter
->PutEntry(sFormat
, nCheckPos
, nType
, nFormat
, LANGUAGE_ENGLISH_US
);
412 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
417 const Color
* pColor
= nullptr;
418 pNumberFormatter
->GetOutputString(fCurrentDate
, nFormat
, aFormatted
, &pColor
, false);
419 m_aCurrentDate
= aFormatted
+ "T00:00:00Z";
422 double SwContentControl::GetCurrentDateValue() const
424 if (m_aCurrentDate
.isEmpty())
429 SwDoc
& rDoc
= m_pTextNode
->GetDoc();
430 SvNumberFormatter
* pNumberFormatter
= rDoc
.GetNumberFormatter();
431 sal_uInt32 nFormat
= pNumberFormatter
->GetEntryKey(CURRENT_DATE_FORMAT
, LANGUAGE_ENGLISH_US
);
432 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
434 sal_Int32 nCheckPos
= 0;
435 SvNumFormatType nType
;
436 OUString sFormat
= CURRENT_DATE_FORMAT
;
437 pNumberFormatter
->PutEntry(sFormat
, nCheckPos
, nType
, nFormat
, LANGUAGE_ENGLISH_US
);
440 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
445 double dCurrentDate
= 0;
446 OUString aCurrentDate
= m_aCurrentDate
.replaceAll("T00:00:00Z", "");
447 (void)pNumberFormatter
->IsNumberFormat(aCurrentDate
, nFormat
, dCurrentDate
);
451 bool SwContentControl::IsInteractingCharacter(sal_Unicode cCh
)
466 bool SwContentControl::ShouldOpenPopup(const vcl::KeyCode
& rKeyCode
)
470 case SwContentControlType::DROP_DOWN_LIST
:
471 case SwContentControlType::COMBO_BOX
:
472 case SwContentControlType::DATE
:
474 // Alt-down opens the popup.
475 return rKeyCode
.IsMod2() && rKeyCode
.GetCode() == KEY_DOWN
;
484 // NOTE: call SetReadWrite separately to implement true (un)locking.
485 // This is mostly a theoretical function; the lock state is mainly kept for round-tripping purposes.
486 // It is implemented here primarily for pointless VBA control, but with the intention that it
487 // could be made functionally useful as well for checkboxes/dropdowns/pictures.
488 // Returns whether the content (bControl=false) cannot be modified,
489 // or if the control cannot be deleted.
490 std::optional
<bool> SwContentControl::GetLock(bool bControl
) const
492 std::optional
<bool> oLock
;
493 if (m_aLock
.isEmpty())
495 else if (m_aLock
.equalsIgnoreAsciiCase("sdtContentLocked"))
497 else if (m_aLock
.equalsIgnoreAsciiCase("unlocked"))
499 else if (m_aLock
.equalsIgnoreAsciiCase("sdtLocked"))
501 else if (m_aLock
.equalsIgnoreAsciiCase("contentLocked"))
504 assert(oLock
&& "invalid or unknown lock state");
508 void SwContentControl::SetLock(bool bLockContent
, bool bLockControl
)
510 if (!bLockContent
&& !bLockControl
)
511 m_aLock
= "unlocked";
512 else if (bLockContent
&& bLockControl
)
513 m_aLock
= "sdtContentLocked";
514 else if (bLockContent
)
515 m_aLock
= "contentLocked";
517 m_aLock
= "sdtLocked";
520 SwContentControlType
SwContentControl::GetType() const
524 return SwContentControlType::CHECKBOX
;
529 return SwContentControlType::COMBO_BOX
;
534 return SwContentControlType::DROP_DOWN_LIST
;
539 return SwContentControlType::PICTURE
;
544 return SwContentControlType::DATE
;
549 return SwContentControlType::PLAIN_TEXT
;
552 return SwContentControlType::RICH_TEXT
;
555 void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter
) const
557 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwContentControl"));
558 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
559 (void)xmlTextWriterWriteFormatAttribute(
560 pWriter
, BAD_CAST("showing-place-holder"), "%s",
561 BAD_CAST(OString::boolean(m_bShowingPlaceHolder
).getStr()));
562 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("checkbox"), "%s",
563 BAD_CAST(OString::boolean(m_bCheckbox
).getStr()));
564 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("checked"), "%s",
565 BAD_CAST(OString::boolean(m_bChecked
).getStr()));
566 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("checked-state"), "%s",
567 BAD_CAST(m_aCheckedState
.toUtf8().getStr()));
568 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("unchecked-state"), "%s",
569 BAD_CAST(m_aUncheckedState
.toUtf8().getStr()));
570 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("picture"),
571 BAD_CAST(OString::boolean(m_bPicture
).getStr()));
572 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("date"),
573 BAD_CAST(OString::boolean(m_bDate
).getStr()));
574 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("date-format"),
575 BAD_CAST(m_aDateFormat
.toUtf8().getStr()));
576 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("date-language"),
577 BAD_CAST(m_aDateLanguage
.toUtf8().getStr()));
578 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("current-date"),
579 BAD_CAST(m_aCurrentDate
.toUtf8().getStr()));
580 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("plain-text"),
581 BAD_CAST(OString::boolean(m_bPlainText
).getStr()));
582 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("combo-box"),
583 BAD_CAST(OString::boolean(m_bComboBox
).getStr()));
584 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("drop-down"),
585 BAD_CAST(OString::boolean(m_bDropDown
).getStr()));
586 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("placeholder-doc-part"),
587 BAD_CAST(m_aPlaceholderDocPart
.toUtf8().getStr()));
588 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("data-binding-prefix-mappings"),
589 BAD_CAST(m_aDataBindingPrefixMappings
.toUtf8().getStr()));
590 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("data-binding-xpath"),
591 BAD_CAST(m_aDataBindingXpath
.toUtf8().getStr()));
592 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("data-binding-store-item-id"),
593 BAD_CAST(m_aDataBindingStoreItemID
.toUtf8().getStr()));
594 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("color"),
595 BAD_CAST(m_aColor
.toUtf8().getStr()));
596 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("appearance"),
597 BAD_CAST(m_aAppearance
.toUtf8().getStr()));
598 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("alias"),
599 BAD_CAST(m_aAlias
.toUtf8().getStr()));
600 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("tag"), BAD_CAST(m_aTag
.toUtf8().getStr()));
601 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("id"),
602 BAD_CAST(OString::number(m_nId
).getStr()));
603 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("tab-index"),
604 BAD_CAST(OString::number(m_nTabIndex
).getStr()));
605 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("lock"),
606 BAD_CAST(m_aLock
.toUtf8().getStr()));
608 if (!m_aListItems
.empty())
610 for (const auto& rListItem
: m_aListItems
)
612 rListItem
.dumpAsXml(pWriter
);
616 (void)xmlTextWriterEndElement(pWriter
);
619 void SwContentControlListItem::dumpAsXml(xmlTextWriterPtr pWriter
) const
621 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwContentControlListItem"));
622 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
623 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("display-text"),
624 BAD_CAST(m_aDisplayText
.toUtf8().getStr()));
625 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("value"),
626 BAD_CAST(m_aValue
.toUtf8().getStr()));
628 (void)xmlTextWriterEndElement(pWriter
);
631 const OUString
& SwContentControlListItem::ToString() const
633 if (!m_aDisplayText
.isEmpty())
635 return m_aDisplayText
;
641 bool SwContentControlListItem::operator==(const SwContentControlListItem
& rOther
) const
643 return m_aDisplayText
== rOther
.m_aDisplayText
&& m_aValue
== rOther
.m_aValue
;
646 void SwContentControlListItem::ItemsToAny(const std::vector
<SwContentControlListItem
>& rItems
,
649 uno::Sequence
<uno::Sequence
<beans::PropertyValue
>> aRet(rItems
.size());
651 uno::Sequence
<beans::PropertyValue
>* pRet
= aRet
.getArray();
652 for (size_t i
= 0; i
< rItems
.size(); ++i
)
654 const SwContentControlListItem
& rItem
= rItems
[i
];
655 uno::Sequence
<beans::PropertyValue
> aItem
= {
656 comphelper::makePropertyValue("DisplayText", rItem
.m_aDisplayText
),
657 comphelper::makePropertyValue("Value", rItem
.m_aValue
),
665 std::vector
<SwContentControlListItem
>
666 SwContentControlListItem::ItemsFromAny(const css::uno::Any
& rVal
)
668 std::vector
<SwContentControlListItem
> aRet
;
670 uno::Sequence
<uno::Sequence
<beans::PropertyValue
>> aSequence
;
672 for (const auto& rItem
: aSequence
)
674 comphelper::SequenceAsHashMap
aMap(rItem
);
675 SwContentControlListItem aItem
;
676 auto it
= aMap
.find("DisplayText");
677 if (it
!= aMap
.end())
679 it
->second
>>= aItem
.m_aDisplayText
;
681 it
= aMap
.find("Value");
682 if (it
!= aMap
.end())
684 it
->second
>>= aItem
.m_aValue
;
686 aRet
.push_back(aItem
);
692 SwTextContentControl
* SwTextContentControl::CreateTextContentControl(SwDoc
& rDoc
,
693 SwTextNode
* pTargetTextNode
,
694 SwFormatContentControl
& rAttr
,
696 sal_Int32 nEnd
, bool bIsCopy
)
700 // rAttr is already cloned, now call DoCopy to copy the SwContentControl
701 if (!pTargetTextNode
)
704 "SwTextContentControl ctor: cannot copy content control without target node");
706 rAttr
.DoCopy(*pTargetTextNode
);
708 SwContentControlManager
* pManager
= &rDoc
.GetContentControlManager();
709 auto pTextContentControl(new SwTextContentControl(pManager
, rAttr
, nStart
, nEnd
));
710 return pTextContentControl
;
713 SwTextContentControl::SwTextContentControl(SwContentControlManager
* pManager
,
714 SwFormatContentControl
& rAttr
, sal_Int32 nStart
,
716 : SwTextAttr(rAttr
, nStart
)
717 , SwTextAttrNesting(rAttr
, nStart
, nEnd
)
718 , m_pManager(pManager
)
720 rAttr
.SetTextAttr(this);
721 SetHasDummyChar(true);
722 m_pManager
->Insert(this);
725 SwTextContentControl::~SwTextContentControl()
727 auto& rFormatContentControl
= static_cast<SwFormatContentControl
&>(GetAttr());
728 if (rFormatContentControl
.GetTextAttr() == this)
730 rFormatContentControl
.SetTextAttr(nullptr);
734 void SwTextContentControl::ChgTextNode(SwTextNode
* pNode
)
736 auto& rFormatContentControl
= static_cast<SwFormatContentControl
&>(GetAttr());
737 if (rFormatContentControl
.GetTextAttr() == this)
739 rFormatContentControl
.NotifyChangeTextNode(pNode
);
743 m_pManager
= &pNode
->GetDoc().GetContentControlManager();
749 m_pManager
->Erase(this);
751 m_pManager
= nullptr;
756 void SwTextContentControl::Delete(bool bSaveContents
)
761 SwPaM
aPaM(*GetTextNode(), GetStart(), *GetTextNode(), *End());
763 GetTextNode()->GetDoc().ResetAttrs(aPaM
, /*bTextAttr=*/true, { RES_TXTATR_CONTENTCONTROL
});
765 GetTextNode()->GetDoc().getIDocumentContentOperations().DeleteAndJoin(aPaM
);
768 SwTextNode
* SwTextContentControl::GetTextNode() const
770 auto& rFormatContentControl
= static_cast<const SwFormatContentControl
&>(GetAttr());
771 return rFormatContentControl
.GetTextNode();
774 OUString
SwTextContentControl::ToString() const
779 // Don't select the text attribute itself at the start.
780 sal_Int32 nStart
= GetStart() + 1;
781 // Don't select the CH_TXTATR_BREAKWORD itself at the end.
782 sal_Int32 nEnd
= *End() - 1;
784 SwPaM
aPaM(*GetTextNode(), nStart
, *GetTextNode(), nEnd
);
785 return aPaM
.GetText();
788 void SwTextContentControl::Invalidate()
790 SwDocShell
* pDocShell
= GetTextNode() ? GetTextNode()->GetDoc().GetDocShell() : nullptr;
791 if (!pDocShell
|| !pDocShell
->GetWrtShell())
795 // NOTE: needs further testing to see if this is adequate (i.e. in auto-run macros...)
796 pDocShell
->GetWrtShell()->Push();
798 // visit the control in the text (which makes any necessary visual changes)
799 // NOTE: simply going to a checkbox causes a toggle, unless bOnlyRefresh
800 auto& rFormatContentControl
= static_cast<SwFormatContentControl
&>(GetAttr());
801 pDocShell
->GetWrtShell()->GotoContentControl(rFormatContentControl
, /*bOnlyRefresh=*/true);
803 pDocShell
->GetWrtShell()->Pop(SwCursorShell::PopMode::DeleteCurrent
);
806 void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter
) const
808 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwTextContentControl"));
809 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
810 SwTextAttr::dumpAsXml(pWriter
);
812 (void)xmlTextWriterEndElement(pWriter
);
815 SwContentControlManager::SwContentControlManager() {}
817 void SwContentControlManager::Insert(SwTextContentControl
* pTextContentControl
)
819 m_aContentControls
.push_back(pTextContentControl
);
822 void SwContentControlManager::Erase(SwTextContentControl
* pTextContentControl
)
824 m_aContentControls
.erase(
825 std::remove(m_aContentControls
.begin(), m_aContentControls
.end(), pTextContentControl
),
826 m_aContentControls
.end());
829 SwTextContentControl
* SwContentControlManager::Get(size_t nIndex
)
831 // Only sort now: the items may not have an associated text node by the time they are inserted
832 // into the container.
833 std::sort(m_aContentControls
.begin(), m_aContentControls
.end(),
834 [](SwTextContentControl
*& pLhs
, SwTextContentControl
*& pRhs
) -> bool {
835 SwNodeOffset nIdxLHS
= pLhs
->GetTextNode()->GetIndex();
836 SwNodeOffset nIdxRHS
= pRhs
->GetTextNode()->GetIndex();
837 if (nIdxLHS
== nIdxRHS
)
839 return pLhs
->GetStart() < pRhs
->GetStart();
842 return nIdxLHS
< nIdxRHS
;
845 return m_aContentControls
[nIndex
];
848 SwTextContentControl
* SwContentControlManager::UnsortedGet(size_t nIndex
)
850 assert(nIndex
< m_aContentControls
.size());
851 return m_aContentControls
[nIndex
];
854 void SwContentControlManager::dumpAsXml(xmlTextWriterPtr pWriter
) const
856 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwContentControlManager"));
857 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
858 for (const auto& pContentControl
: m_aContentControls
)
860 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwTextContentControl"));
861 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", pContentControl
);
862 (void)xmlTextWriterEndElement(pWriter
);
865 (void)xmlTextWriterEndElement(pWriter
);
868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */