sw/qa/core/unocore/unocore.cxx | 7 ++++- sw/qa/uibase/wrtsh/wrtsh.cxx | 46 ++++++++++++++++++++++++++++++++++++++ sw/source/uibase/docvw/edtwin.cxx | 26 +++++++++++++++++++++ sw/source/uibase/uiview/view2.cxx | 2 - sw/source/uibase/wrtsh/wrtsh3.cxx | 18 ++++++++++++++ 5 files changed, 96 insertions(+), 3 deletions(-)
New commits: commit b213abcb77e19fa5d22af45c7ecd17c8a63af554 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Wed May 18 10:51:18 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu May 19 14:38:03 2022 +0200 sw content controls, picture: replace placeholder image on click Previous content control types (rich text, checkbox, dropdown) had the cursor somewhere in the content control and click selected the content control in the placeholder case. The picture case is somewhat different: the content control has a single as-char image, and by the time SwWrtShell::GotoContentControl() is invoked, the picture frame is already selected. All we have to do here is to trigger the file picker to select a replacement and then insert that image to replace the already selected frame's bitmap. Change-Id: Id3ad94ed8f7e13b0ebc2f57327bb8c0b1e374a86 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134511 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx index c9ea6f833c12..3739362fb403 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -553,7 +553,12 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPicture) 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, "test", /*bAbsorb=*/false); + uno::Reference<beans::XPropertySet> xTextGraphic( + xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + xTextGraphic->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); + uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xTextContent, false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference<text::XTextContent> xContentControl( diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx index 6faf642e10e4..297e7a2d1ebd 100644 --- a/sw/qa/uibase/wrtsh/wrtsh.cxx +++ b/sw/qa/uibase/wrtsh/wrtsh.cxx @@ -25,6 +25,7 @@ #include <wrtsh.hxx> #include <ndtxt.hxx> #include <textcontentcontrol.hxx> +#include <fmtanchr.hxx> namespace { @@ -239,6 +240,51 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertDropdownContentControl) // i.e. the inserted content control was a default (rich text) one, not a dropdown. CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pContentControl->GetListItems().size()); } + +CPPUNIT_TEST_FIXTURE(Test, testReplacePictureContentControl) +{ + // Given a document with a picture 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(); + uno::Reference<beans::XPropertySet> xTextGraphic( + xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + xTextGraphic->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); + uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xTextContent, 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); + xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::Any(true)); + xContentControlProps->setPropertyValue("Picture", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When clicking on that content control: + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->GotoObj(/*bNext=*/true, GotoObjFlags::Any); + pWrtShell->EnterSelFrameMode(); + const SwFrameFormat* pFlyFormat = pWrtShell->GetFlyFrameFormat(); + const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor(); + const SwPosition* pAnchorPos = rFormatAnchor.GetContentAnchor(); + SwTextNode* pTextNode = pAnchorPos->nNode.GetNode().GetTextNode(); + SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); + auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + auto& rFormatContentControl + = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr()); + pWrtShell->GotoContentControl(rFormatContentControl); + + // Then make sure that the picture is replaced: + CPPUNIT_ASSERT(!rFormatContentControl.GetContentControl()->GetShowingPlaceHolder()); + // Without the accompanying fix in place, this test would have failed, there was no special + // handling for picture content control (how to interact with them), and the default handler + // killed the image selection. + CPPUNIT_ASSERT(pWrtShell->IsFrameSelected()); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 12ade08df6d6..69dc6f7aa509 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -4684,6 +4684,32 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt) CaptureMouse(); } + + if (pFlyFormat) + { + // See if the fly frame's anchor is in a content control. If so, + // interact with it. + const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor(); + const SwPosition* pAnchorPos = rFormatAnchor.GetContentAnchor(); + if (pAnchorPos) + { + SwTextNode* pTextNode = pAnchorPos->nNode.GetNode().GetTextNode(); + if (pTextNode) + { + SwTextAttr* pAttr = pTextNode->GetTextAttrAt( + pAnchorPos->nContent.GetIndex(), RES_TXTATR_CONTENTCONTROL, + SwTextNode::PARENT); + if (pAttr) + { + SwTextContentControl* pTextContentControl + = static_txtattr_cast<SwTextContentControl*>(pAttr); + const SwFormatContentControl& rFormatContentControl + = pTextContentControl->GetContentControl(); + rSh.GotoContentControl(rFormatContentControl); + } + } + } + } } rSh.EndDrag( &aDocPt, false ); } diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index 970064c6c164..75219fcbab07 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -380,7 +380,7 @@ bool SwView::InsertGraphicDlg( SfxRequest& rReq ) bool bShowError = !pName; if( pName #if HAVE_FEATURE_DESKTOP - || ERRCODE_NONE == pFileDlg->Execute() + || (!Application::IsHeadlessModeEnabled() && ERRCODE_NONE == pFileDlg->Execute()) #endif ) { diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx index c0567d03427b..978f95397b52 100644 --- a/sw/source/uibase/wrtsh/wrtsh3.cxx +++ b/sw/source/uibase/wrtsh/wrtsh3.cxx @@ -28,6 +28,8 @@ #include <com/sun/star/form/FormButtonType.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <osl/diagnose.h> +#include <sfx2/dispatch.hxx> + #include <swmodule.hxx> #include <wrtsh.hxx> #include <view.hxx> @@ -90,11 +92,25 @@ bool SwWrtShell::GotoField( const SwFormatField& rField ) bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl) { + std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl(); + if (IsFrameSelected() && pContentControl && pContentControl->GetPicture()) + { + // A frame is already selected, and its anchor is inside a picture content control. + if (pContentControl->GetShowingPlaceHolder()) + { + // Replace the placeholder image with a real one. + GetView().StopShellTimer(); + GetView().GetViewFrame()->GetDispatcher()->Execute(SID_CHANGE_PICTURE, + SfxCallMode::SYNCHRON); + pContentControl->SetShowingPlaceHolder(false); + } + return true; + } + (this->*m_fnKillSel)(nullptr, false); bool bRet = SwCursorShell::GotoFormatContentControl(rContentControl); - std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl(); if (bRet && pContentControl && pContentControl->GetCheckbox()) { // Checkbox: GotoFormatContentControl() selected the old state.