sw/inc/formatcontentcontrol.hxx | 2 + sw/inc/textcontentcontrol.hxx | 1 sw/source/core/crsr/crstrvl.cxx | 3 -- sw/source/core/txtnode/attrcontentcontrol.cxx | 25 +++++++++++++++++++++++- sw/source/ui/vba/vbacontentcontrol.cxx | 21 ++++++++------------ sw/source/ui/vba/vbacontentcontrollistentry.cxx | 16 +++++++++++++-- sw/source/uibase/inc/wrtsh.hxx | 7 +++++- sw/source/uibase/wrtsh/wrtsh3.cxx | 25 +++++++++++++----------- 8 files changed, 70 insertions(+), 30 deletions(-)
New commits: commit f281cdd13347b86db4a9eb8b36162ffe30f2c52b Author: Justin Luth <[email protected]> AuthorDate: Wed Nov 23 08:15:15 2022 -0500 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Dec 13 08:27:02 2022 +0000 tdf#151548 ContentControls: Add Invalidate() Squashed commit. Up until now, all changes made to a content control have been triggered by the UI. However, VBA makes changes by code, and those property changes were just being ignored until the control received the focus. Change-Id: Ife865dd493f7eae4d4e95096071f05b8c27d51db Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143194 Reviewed-by: Justin Luth <[email protected]> Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> tdf#151548 ContentControls: improve Invalidation This addresses some hack concerns that Miklos raised in his review. Change-Id: Ic6d906e9eb1d23700fb743e179ba87899ce2f4a1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143412 Tested-by: Jenkins Reviewed-by: Justin Luth <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144011 Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index 8546e78dabc4..a782112fb917 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -179,9 +179,11 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify sal_Int32 m_nId = 0; /// Stores a list item index, in case the doc model is not yet updated. + // i.e. temporarily store the selected item until the text is inserted by GotoContentControl. std::optional<size_t> m_oSelectedListItem; /// Stores a date timestamp, in case the doc model is not yet updated. + // i.e. temporarily store the date until the text is inserted by GotoContentControl. std::optional<double> m_oSelectedDate; /** diff --git a/sw/inc/textcontentcontrol.hxx b/sw/inc/textcontentcontrol.hxx index 78a4d5120b1b..8c8a3b3ee044 100644 --- a/sw/inc/textcontentcontrol.hxx +++ b/sw/inc/textcontentcontrol.hxx @@ -42,6 +42,7 @@ public: void ChgTextNode(SwTextNode* pNode); SwTextNode* GetTextNode() const; + void Invalidate(); void dumpAsXml(xmlTextWriterPtr pWriter) const override; }; diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index 463a1d05dada..42f80e9bd013 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -883,9 +883,6 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont sal_Int32 nEnd = *pTextContentControl->End() - 1; pCursor->GetMark()->nContent.Assign(pTextNode, nEnd); - // Assume that once the placeholder is selected, the content is no longer the placeholder. - pContentControl->SetShowingPlaceHolder(false); - bRet = !pCursor->IsSelOvr(); if (bRet) { diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx index 3a7d0155c23e..8963d256939c 100644 --- a/sw/source/core/txtnode/attrcontentcontrol.cxx +++ b/sw/source/core/txtnode/attrcontentcontrol.cxx @@ -30,6 +30,7 @@ #include <ndtxt.hxx> #include <textcontentcontrol.hxx> #include <doc.hxx> +#include <wrtsh.hxx> using namespace com::sun::star; @@ -273,7 +274,8 @@ void SwContentControl::DeleteListItem(size_t nZIndex) if (*oSelected == nZIndex) { SetSelectedListItem(std::nullopt); - //Invalidate(); + if (m_bDropDown && GetTextAttr()) + GetTextAttr()->Invalidate(); } else if (*oSelected < nZIndex) SetSelectedListItem(*oSelected - 1); @@ -289,6 +291,8 @@ void SwContentControl::ClearListItems() { SetSelectedListItem(std::nullopt); SetListItems(std::vector<SwContentControlListItem>()); + if (m_bDropDown && GetTextAttr()) + GetTextAttr()->Invalidate(); } OUString SwContentControl::GetDateString() const @@ -652,6 +656,25 @@ SwTextNode* SwTextContentControl::GetTextNode() const return rFormatContentControl.GetTextNode(); } +void SwTextContentControl::Invalidate() +{ + SwDocShell* pDocShell = GetTextNode() ? GetTextNode()->GetDoc().GetDocShell() : nullptr; + if (!pDocShell || !pDocShell->GetWrtShell()) + return; + + // save the cursor + // NOTE: needs further testing to see if this is adequate (i.e. in auto-run macros...) + pDocShell->GetWrtShell()->Push(); + + // visit the control in the text (which makes any necessary visual changes) + // NOTE: simply going to a control indicates cancelling ShowingPlaceHolder, unless bOnlyRefresh + // NOTE: simply going to a checkbox causes a toggle, unless bOnlyRefresh + auto& rFormatContentControl = static_cast<SwFormatContentControl&>(GetAttr()); + pDocShell->GetWrtShell()->GotoContentControl(rFormatContentControl, /*bOnlyRefresh=*/true); + + pDocShell->GetWrtShell()->Pop(SwCursorShell::PopMode::DeleteCurrent); +} + void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const { (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextContentControl")); diff --git a/sw/source/ui/vba/vbacontentcontrol.cxx b/sw/source/ui/vba/vbacontentcontrol.cxx index 62ee4a4f7be6..d75ce84d7f4a 100644 --- a/sw/source/ui/vba/vbacontentcontrol.cxx +++ b/sw/source/ui/vba/vbacontentcontrol.cxx @@ -99,7 +99,8 @@ void SwVbaContentControl::setChecked(sal_Bool bSet) if (pCC->GetCheckbox() && pCC->GetChecked() != static_cast<bool>(bSet)) { pCC->SetChecked(bSet); - //pCC->Invalidate(); + pCC->SetShowingPlaceHolder(false); + m_rCC.Invalidate(); } } @@ -694,8 +695,9 @@ void SwVbaContentControl::SetCheckedSymbol(sal_Int32 Character, const uno::Any& std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl(); pCC->SetCheckedState(OUString(static_cast<sal_Unicode>(Character))); - //if (getChecked()) - // pCC->Invalidate(); + + if (pCC->GetCheckbox() && pCC->GetChecked()) + m_rCC.Invalidate(); } void SwVbaContentControl::SetUnCheckedSymbol(sal_Int32 Character, const uno::Any& Font) @@ -706,8 +708,9 @@ void SwVbaContentControl::SetUnCheckedSymbol(sal_Int32 Character, const uno::Any std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl(); pCC->SetUncheckedState(OUString(static_cast<sal_Unicode>(Character))); - //if (!getChecked()) - // pCC->Invalidate(); + + if (pCC->GetCheckbox() && !pCC->GetChecked()) + m_rCC.Invalidate(); } void SwVbaContentControl::SetPlaceholderText(const uno::Any& BuildingBlock, const uno::Any& Range, @@ -732,13 +735,7 @@ void SwVbaContentControl::SetPlaceholderText(const uno::Any& BuildingBlock, cons // Remove placeholder text. pCC->SetPlaceholderDocPart(""); } - //if (getShowingPlaceholderText()) - //{ - // if (!pCC->GetCheckbox()) - // pCC->Invalidate(); - // // Ensure that invalidation doesn't turn off showing placeholder as true - // pCC->SetShowingPlaceHolder(true); - //} + m_rCC.Invalidate(); } void SwVbaContentControl::Ungroup() { SAL_INFO("sw.vba", "SwVbaContentControl::UnGroup stub"); } diff --git a/sw/source/ui/vba/vbacontentcontrollistentry.cxx b/sw/source/ui/vba/vbacontentcontrollistentry.cxx index 1f758c4ba30a..61d2a1faf6a8 100644 --- a/sw/source/ui/vba/vbacontentcontrollistentry.cxx +++ b/sw/source/ui/vba/vbacontentcontrollistentry.cxx @@ -62,9 +62,20 @@ void SwVbaContentControlListEntry::setText(const OUString& rSet) if (vListItems[i].ToString() == rSet) return; } + + bool bNeedsInvalidation = false; + if (!pCC->GetShowingPlaceHolder()) + { + // TODO: implement bCheckDocModel + std::optional<size_t> oSel(pCC->GetSelectedListItem(/*bCheckDocModel=true*/)); + bNeedsInvalidation = oSel && *oSel == m_nZIndex; + } + vListItems[m_nZIndex].m_aDisplayText = rSet; pCC->SetListItems(vListItems); - //pCC->Invalidate(); + + if (bNeedsInvalidation) + m_rCC.Invalidate(); } OUString SwVbaContentControlListEntry::getValue() @@ -143,7 +154,8 @@ void SwVbaContentControlListEntry::Select() std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl(); assert(m_nZIndex < pCC->GetListItems().size()); pCC->SetSelectedListItem(m_nZIndex); - //pCC->Invalidate(); + pCC->SetShowingPlaceHolder(false); + m_rCC.Invalidate(); } // XHelperInterface diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx index 664af50018d7..bd46da908876 100644 --- a/sw/source/uibase/inc/wrtsh.hxx +++ b/sw/source/uibase/inc/wrtsh.hxx @@ -428,7 +428,12 @@ typedef bool (SwWrtShell::*FNSimpleMove)(); bool GotoField( const SwFormatField& rField ); - bool GotoContentControl(const SwFormatContentControl& rContentControl); + /** @param bOnlyRefresh: + * false: run default actions (e.g. toggle checkbox, remove placeholder content) + * true: do not alter the content control, just refresh the doc model + */ + bool GotoContentControl(const SwFormatContentControl& rContentControl, + bool bOnlyRefresh = false); // jump to the next / previous hyperlink - inside text and also // on graphics diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx index 58204886933e..aa170d1374a4 100644 --- a/sw/source/uibase/wrtsh/wrtsh3.cxx +++ b/sw/source/uibase/wrtsh/wrtsh3.cxx @@ -93,7 +93,8 @@ bool SwWrtShell::GotoField( const SwFormatField& rField ) return bRet; } -bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl) +bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl, + bool bOnlyRefresh) { std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl(); if (IsFrameSelected() && pContentControl && pContentControl->GetPicture()) @@ -124,23 +125,24 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro (this->*m_fnKillSel)(nullptr, false); bool bRet = SwCursorShell::GotoFormatContentControl(rContentControl); + // Assume that once the placeholder is selected, the content is no longer the placeholder. + if (!bOnlyRefresh && pContentControl) + pContentControl->SetShowingPlaceHolder(false); + if (bRet && pContentControl && pContentControl->GetCheckbox()) { // Checkbox: GotoFormatContentControl() selected the old state. LockView(/*bViewLocked=*/true); - OUString aOldState; + OUString aOldState = GetCursorDescr(); OUString aNewState; if (pContentControl->GetChecked()) - { - aOldState = pContentControl->GetCheckedState(); - aNewState = pContentControl->GetUncheckedState(); - } + aNewState = bOnlyRefresh ? pContentControl->GetCheckedState() + : pContentControl->GetUncheckedState(); else - { - aOldState = pContentControl->GetUncheckedState(); - aNewState = pContentControl->GetCheckedState(); - } + aNewState = bOnlyRefresh ? pContentControl->GetUncheckedState() + : pContentControl->GetCheckedState(); + SwRewriter aRewriter; aRewriter.AddRule(UndoArg1, aOldState); aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS)); @@ -150,7 +152,8 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro // Toggle the state. pContentControl->SetReadWrite(true); DelLeft(); - pContentControl->SetChecked(!pContentControl->GetChecked()); + if (!bOnlyRefresh) + pContentControl->SetChecked(!pContentControl->GetChecked()); Insert(aNewState); pContentControl->SetReadWrite(false);
