sw/inc/formatcontentcontrol.hxx | 10 +++ sw/qa/uibase/wrtsh/wrtsh.cxx | 53 +++++++++++++++++++ sw/source/core/crsr/crstrvl.cxx | 3 - sw/source/core/crsr/dropdowncontentcontrolbutton.cxx | 10 ++- sw/source/core/crsr/viscrs.cxx | 13 +++- sw/source/core/inc/contentcontrolbutton.hxx | 2 sw/source/uibase/wrtsh/wrtsh3.cxx | 27 +++++++++ 7 files changed, 111 insertions(+), 7 deletions(-)
New commits: commit 9ca44e925a8e06e0946fa9e7bd80cfdbfbb83c62 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 6 13:48:46 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri May 6 15:17:34 2022 +0200 sw content controls, drop-down: select list item on click - remember the selected list item in SwDropDownContentControlButton::ListBoxHandler() - extend SwWrtShell::GotoContentControl() to update the document text, somewhat similar to how checkboxes are already handled - improve SwSelPaintRects::HighlightContentControl(): - re-create the vcl widget in case a different content control was selected - adjust position/size and re-show the dropdown button after selecting an item + doc text was updated Change-Id: Id3b89b6132697bfec7046caeb1f0c5fe93e99b37 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133915 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index c25036fc5d15..e3debfb77bf4 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -117,6 +117,9 @@ class SAL_DLLPUBLIC_RTTI SwContentControl : public sw::BroadcastingModify std::vector<SwContentControlListItem> m_aListItems; + /// Stores a list item index, in case the doc model is not yet updated. + std::optional<size_t> m_oSelectedListItem; + public: SwTextContentControl* GetTextAttr() const; @@ -176,6 +179,13 @@ public: m_aListItems = rListItems; } + void SetSelectedListItem(std::optional<size_t> oSelectedListItem) + { + m_oSelectedListItem = oSelectedListItem; + } + + std::optional<size_t> GetSelectedListItem() const { return m_oSelectedListItem; } + virtual void dumpAsXml(xmlTextWriterPtr pWriter) const; }; diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx index 78d8c26a0b4a..1bce34fb8a53 100644 --- a/sw/qa/uibase/wrtsh/wrtsh.cxx +++ b/sw/qa/uibase/wrtsh/wrtsh.cxx @@ -17,6 +17,7 @@ #include <rtl/ustring.hxx> #include <sal/types.h> +#include <comphelper/propertyvalue.hxx> #include <doc.hxx> #include <docsh.hxx> @@ -165,6 +166,58 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertCheckboxContentControl) // control wasn't a checkbox one. CPPUNIT_ASSERT(pContentControl->GetCheckbox()); } + +CPPUNIT_TEST_FIXTURE(Test, testSelectDropdownContentControl) +{ + // Given a document with a dropdown content control: + SwDoc* pDoc = createSwDoc(); + uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "choose an item", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference<text::XTextContent> xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + { + uno::Sequence<beans::PropertyValues> aListItems = { + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("R"))), + }, + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("G"))), + }, + { + comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))), + comphelper::makePropertyValue("Value", uno::Any(OUString("B"))), + }, + }; + xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems)); + } + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When clicking on that content control: + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); + SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); + auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + auto& rFormatContentControl + = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr()); + rFormatContentControl.GetContentControl()->SetSelectedListItem(0); + pWrtShell->GotoContentControl(rFormatContentControl); + + // Then make sure that the document text is updated: + // Without the accompanying fix in place, this test would have failed: + // - Expected: red + // - Actual : choose an item + // i.e. the document text was unchanged instead of CH_TXTATR_BREAKWORD + display text of the + // first list item. + CPPUNIT_ASSERT_EQUAL(OUString(u"\x0001red"), pTextNode->GetText()); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index cfc57e901827..14ed1026f4d7 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -857,7 +857,8 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont { bool bRet = false; auto pContentControl = const_cast<SwContentControl*>(rContentControl.GetContentControl()); - if (!pContentControl->GetShowingPlaceHolder() && !pContentControl->GetCheckbox()) + if (!pContentControl->GetShowingPlaceHolder() && !pContentControl->GetCheckbox() + && !pContentControl->GetSelectedListItem()) { return bRet; } diff --git a/sw/source/core/crsr/dropdowncontentcontrolbutton.cxx b/sw/source/core/crsr/dropdowncontentcontrolbutton.cxx index 75517cd972c4..b7113994c0c7 100644 --- a/sw/source/core/crsr/dropdowncontentcontrolbutton.cxx +++ b/sw/source/core/crsr/dropdowncontentcontrolbutton.cxx @@ -17,6 +17,7 @@ #include <docsh.hxx> #include <strings.hrc> #include <formatcontentcontrol.hxx> +#include <wrtsh.hxx> void SwDropDownContentControlButton::InitDropdown() { @@ -52,15 +53,16 @@ IMPL_LINK(SwDropDownContentControlButton, ListBoxHandler, weld::TreeView&, rBox, } sal_Int32 nSelection = rBox.get_selected_index(); + m_xPopup->popdown(); if (nSelection >= 0) { - // TODO update the doc model SwView& rView = static_cast<SwEditWin*>(GetParent())->GetView(); - rView.GetDocShell()->SetModified(); + SwWrtShell& rWrtShell = rView.GetWrtShell(); + auto& rContentControl = const_cast<SwContentControl&>(m_rContentControl); + rContentControl.SetSelectedListItem(nSelection); + rWrtShell.GotoContentControl(*m_rContentControl.GetFormatContentControl()); } - m_xPopup->popdown(); - return true; } diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx index 7ec01eeba708..12dae9ceda13 100644 --- a/sw/source/core/crsr/viscrs.cxx +++ b/sw/source/core/crsr/viscrs.cxx @@ -723,13 +723,22 @@ void SwSelPaintRects::HighlightContentControl() } } - if (!m_pContentControlButton && pContentControl && pContentControl->HasListItems()) + if (pContentControl && pContentControl->HasListItems()) { auto pWrtShell = dynamic_cast<const SwWrtShell*>(GetShell()); if (pWrtShell) { auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin()); - m_pContentControlButton = VclPtr<SwDropDownContentControlButton>::Create(&rEditWin, *pContentControl); + if (m_pContentControlButton + && &m_pContentControlButton->GetContentControl() != pContentControl) + { + m_pContentControlButton.disposeAndClear(); + } + if (!m_pContentControlButton) + { + m_pContentControlButton = VclPtr<SwDropDownContentControlButton>::Create( + &rEditWin, *pContentControl); + } m_pContentControlButton->CalcPosAndSize(aLastPortionPaintArea); m_pContentControlButton->Show(); } diff --git a/sw/source/core/inc/contentcontrolbutton.hxx b/sw/source/core/inc/contentcontrolbutton.hxx index 591b8ce6114c..d840887fb460 100644 --- a/sw/source/core/inc/contentcontrolbutton.hxx +++ b/sw/source/core/inc/contentcontrolbutton.hxx @@ -35,6 +35,8 @@ public: virtual void LaunchPopup(); virtual void DestroyPopup(); + const SwContentControl& GetContentControl() const { return m_rContentControl; } + private: tools::Rectangle m_aFramePixel; diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx index 35d1d3bd45ee..aa0badb54e61 100644 --- a/sw/source/uibase/wrtsh/wrtsh3.cxx +++ b/sw/source/uibase/wrtsh/wrtsh3.cxx @@ -37,6 +37,7 @@ #include <IDocumentUndoRedo.hxx> #include <SwRewriter.hxx> #include <strings.hrc> +#include <textcontentcontrol.hxx> using namespace ::com::sun::star; @@ -125,6 +126,32 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro LockView(/*bViewLocked=*/false); ShowCursor(); } + else if (bRet && pContentControl && pContentControl->GetSelectedListItem()) + { + // Dropdown: GotoFormatContentControl() selected the old content. + size_t nSelectedListItem = *pContentControl->GetSelectedListItem(); + LockView(/*bViewLocked=*/true); + OUString aOldState = GetCursorDescr(); + OUString aNewState = pContentControl->GetListItems()[nSelectedListItem].m_aDisplayText; + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, aOldState); + aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS)); + aRewriter.AddRule(UndoArg3, SwResId(STR_START_QUOTE) + aNewState + SwResId(STR_END_QUOTE)); + GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter); + + // Update the content. + SwTextContentControl* pTextContentControl + = const_cast<SwFormatContentControl&>(rContentControl).GetTextAttr(); + // If the content control is at the end of the line, then expand is false by default. + pTextContentControl->SetDontExpand(false); + DelLeft(); + pContentControl->SetSelectedListItem(std::nullopt); + Insert(aNewState); + + GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter); + LockView(/*bViewLocked=*/false); + ShowCursor(); + } if (bRet && IsSelFrameMode()) {