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())
     {

Reply via email to