officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu | 8 + sw/inc/cmdid.h | 1 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 37 ++++++- sw/qa/uibase/wrtsh/wrtsh.cxx | 22 ++++ sw/sdi/_textsh.sdi | 6 + sw/sdi/swriter.sdi | 17 +++ sw/source/filter/ww8/docxattributeoutput.cxx | 5 sw/source/uibase/dochdl/swdtflvr.cxx | 10 - sw/source/uibase/inc/wrtsh.hxx | 2 sw/source/uibase/shells/basesh.cxx | 2 sw/source/uibase/shells/textsh.cxx | 5 sw/source/uibase/uiview/view.cxx | 4 sw/source/uibase/uiview/view2.cxx | 4 sw/source/uibase/wrtsh/wrtsh1.cxx | 52 +++++++++- sw/uiconfig/swriter/menubar/menubar.xml | 1 sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml | 1 writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx | 33 ++++++ writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx |binary writerfilter/source/dmapper/DomainMapper.cxx | 11 ++ writerfilter/source/dmapper/DomainMapper_Impl.cxx | 5 writerfilter/source/dmapper/SdtHelper.hxx | 1 21 files changed, 211 insertions(+), 16 deletions(-)
New commits: commit c18db3c86257974770cd9e7c5aea221222c78667 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 20 13:31:45 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue May 24 13:13:58 2022 +0200 sw content controls, picture: add insert UI - handle the picture case in SwWrtShell::InsertContentControl(): insert a placeholder bitmap & create content control around the as-char image - expose this as a new .uno:InsertPictureContentControl command - add the new uno command to the default & MS-compatible menus - rename the SwWrtShell::Insert() overload taking a Graphic to make this a bit more readable (cherry picked from commit 73ed5e36047b6f46b3777bf6f36591ec4babb1f9) Change-Id: I289d6b6a9cd622c585b6cf0ec0c91d6b51ad81ac Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134849 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu index a460cf46e5eb..ad244722288d 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu @@ -651,6 +651,14 @@ <value>1</value> </prop> </node> + <node oor:name=".uno:InsertPictureContentControl" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Insert Picture Content Control</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:InsertObjectDialog" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Insert Other Objects</value> diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index e477ccd054aa..003c77e7efd0 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -216,6 +216,7 @@ #define FN_INSERT_PAGEBREAK (FN_INSERT + 23) /* Page break*/ #define FN_INSERT_DROPDOWN_CONTENT_CONTROL (FN_INSERT + 24) /* Dropdown content control */ #define FN_CONTENT_CONTROL_PROPERTIES (FN_INSERT + 25) /* Content control properties */ +#define FN_INSERT_PICTURE_CONTENT_CONTROL (FN_INSERT + 26) /* Picture content control */ #define FN_POSTIT (FN_INSERT + 29) /* Insert/edit PostIt */ #define FN_INSERT_TABLE (FN_INSERT + 30) /* Insert Table */ #define FN_INSERT_STRING (FN_INSERT+31) diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx index 9aa3efbaf214..ecb7754f53ca 100644 --- a/sw/qa/uibase/wrtsh/wrtsh.cxx +++ b/sw/qa/uibase/wrtsh/wrtsh.cxx @@ -285,6 +285,28 @@ CPPUNIT_TEST_FIXTURE(Test, testReplacePictureContentControl) // killed the image selection. CPPUNIT_ASSERT(pWrtShell->IsFrameSelected()); } + +CPPUNIT_TEST_FIXTURE(Test, testInsertPictureContentControl) +{ + // Given an empty document: + SwDoc* pDoc = createSwDoc(); + + // When inserting a content control: + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->InsertContentControl(SwContentControlType::PICTURE); + + // Then make sure that the matching text attribute is added to the document model: + 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()); + std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl(); + // Without the accompanying fix in place, this test would have failed, there was no special + // handling for picture content control, no placeholder fly content was inserted. + CPPUNIT_ASSERT(pContentControl->GetPicture()); + CPPUNIT_ASSERT(pTextNode->GetTextAttrForCharAt(1, RES_TXTATR_FLYCNT)); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi index 816439cee140..16cd41e339ce 100644 --- a/sw/sdi/_textsh.sdi +++ b/sw/sdi/_textsh.sdi @@ -290,6 +290,12 @@ interface BaseText StateMethod = NoState ; DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] + FN_INSERT_PICTURE_CONTENT_CONTROL // status(final|play) + [ + ExecMethod = ExecInsert ; + StateMethod = NoState ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] FN_CONTENT_CONTROL_PROPERTIES // status(final|play) [ ExecMethod = ExecInsert ; diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi index 7663d3f2c6b1..3361825974b2 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -3083,6 +3083,23 @@ SfxVoidItem InsertDropdownContentControl FN_INSERT_DROPDOWN_CONTENT_CONTROL GroupId = SfxGroupId::Insert; ] +SfxVoidItem InsertPictureContentControl FN_INSERT_PICTURE_CONTENT_CONTROL +() +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Insert; +] + SfxVoidItem ContentControlProperties FN_CONTENT_CONTROL_PROPERTIES () [ diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index 45b74a55773b..542101829162 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -2506,7 +2506,7 @@ bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData, { case SwPasteSdr::Insert: SwTransferable::SetSelInShell( rSh, false, pPt ); - rSh.Insert(sURL, OUString(), aGraphic); + rSh.InsertGraphic(sURL, OUString(), aGraphic); break; case SwPasteSdr::Replace: @@ -2528,7 +2528,7 @@ bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData, else { SwTransferable::SetSelInShell( rSh, false, pPt ); - rSh.Insert(sURL, OUString(), aGraphic); + rSh.InsertGraphic(sURL, OUString(), aGraphic); } break; default: @@ -2634,7 +2634,7 @@ bool SwTransferable::PasteDDE( const TransferableDataHelper& rData, if ( bReReadGrf ) rWrtShell.ReRead( aCmd, sLnkTyp, &aGrf ); else - rWrtShell.Insert( aCmd, sLnkTyp, aGrf ); + rWrtShell.InsertGraphic( aCmd, sLnkTyp, aGrf ); } return bRet; } @@ -2927,7 +2927,7 @@ bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& case SwPasteSdr::Insert: { SwTransferable::SetSelInShell( rSh, false, pPt ); - rSh.Insert(sURL, OUString(), aGraphic, nullptr, nAnchorType); + rSh.InsertGraphic(sURL, OUString(), aGraphic, nullptr, nAnchorType); break; } @@ -2981,7 +2981,7 @@ bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell& else { SwTransferable::SetSelInShell( rSh, false, pPt ); - rSh.Insert(aBkmk.GetURL(), OUString(), aGraphic); + rSh.InsertGraphic(aBkmk.GetURL(), OUString(), aGraphic); } break; } diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx index a80f42c8315a..91cb72146fc0 100644 --- a/sw/source/uibase/inc/wrtsh.hxx +++ b/sw/source/uibase/inc/wrtsh.hxx @@ -309,7 +309,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)(); bool InsertField2(SwField const &, SwPaM* pAnnotationRange = nullptr); void Insert(const OUString &); // graphic - void Insert( const OUString &rPath, const OUString &rFilter, + void InsertGraphic( const OUString &rPath, const OUString &rFilter, const Graphic &, SwFlyFrameAttrMgr * = nullptr, RndStdIds nAnchorType = RndStdIds::FLY_AT_PARA); diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx index 810f26b873fb..a5ea0e6b1012 100644 --- a/sw/source/uibase/shells/basesh.cxx +++ b/sw/source/uibase/shells/basesh.cxx @@ -916,7 +916,7 @@ void SwBaseShell::Execute(SfxRequest &rReq) if ( nSelType & SelectionType::Graphic ) rSh.ReRead( aGrfName, aFltName, &aGrf ); else - rSh.Insert( aGrfName, aFltName, aGrf ); + rSh.InsertGraphic( aGrfName, aFltName, aGrf ); GetView().GetEditWin().GrabFocus(); } diff --git a/sw/source/uibase/shells/textsh.cxx b/sw/source/uibase/shells/textsh.cxx index a8326e40200e..94b0a50e211a 100644 --- a/sw/source/uibase/shells/textsh.cxx +++ b/sw/source/uibase/shells/textsh.cxx @@ -234,6 +234,11 @@ void SwTextShell::ExecInsert(SfxRequest &rReq) rReq.Done(); break; + case FN_INSERT_PICTURE_CONTENT_CONTROL: + rSh.InsertContentControl(SwContentControlType::PICTURE); + rReq.Done(); + break; + case FN_CONTENT_CONTROL_PROPERTIES: { SwWrtShell& rWrtSh = GetShell(); diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx index d26759e3ea4c..1400e25dcd0e 100644 --- a/sw/source/uibase/uiview/view.cxx +++ b/sw/source/uibase/uiview/view.cxx @@ -595,7 +595,7 @@ void SwView::CheckReadonlyState() FN_INSERT_HARDHYPHEN, FN_INSERT_HARD_SPACE, FN_INSERT_NNBSP, FN_INSERT_BREAK, FN_INSERT_LINEBREAK, FN_INSERT_COLUMN_BREAK, FN_INSERT_BREAK_DLG, FN_INSERT_CONTENT_CONTROL, FN_INSERT_CHECKBOX_CONTENT_CONTROL, - FN_INSERT_DROPDOWN_CONTENT_CONTROL, + FN_INSERT_DROPDOWN_CONTENT_CONTROL, FN_INSERT_PICTURE_CONTENT_CONTROL, FN_DELETE_SENT, FN_DELETE_BACK_SENT, FN_DELETE_WORD, FN_DELETE_BACK_WORD, FN_DELETE_LINE, FN_DELETE_BACK_LINE, FN_DELETE_PARA, FN_DELETE_BACK_PARA, FN_DELETE_WHOLE_LINE, @@ -1777,7 +1777,7 @@ void SwView::ScannerEventHdl() if( !aScanBmp.IsEmpty() ) { Graphic aGrf(aScanBmp); - m_pWrtShell->Insert( OUString(), OUString(), aGrf ); + m_pWrtShell->InsertGraphic( OUString(), OUString(), aGrf ); } } } diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index f83173640f17..60c2395293b6 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -281,11 +281,11 @@ ErrCode SwView::InsertGraphic( const OUString &rPath, const OUString &rFilter, OUString sURL = URIHelper::SmartRel2Abs( aTemp, rPath, URIHelper::GetMaybeFileHdl() ); aGraphic.setOriginURL(sURL); - rShell.Insert( sURL, rFilter, aGraphic, &aFrameManager ); + rShell.InsertGraphic( sURL, rFilter, aGraphic, &aFrameManager ); } else { - rShell.Insert( OUString(), OUString(), aGraphic, &aFrameManager ); + rShell.InsertGraphic( OUString(), OUString(), aGraphic, &aFrameManager ); } // it is too late after "EndAction" because the Shell can already be destroyed. diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx index 51a602fec6e4..07147f9f3a37 100644 --- a/sw/source/uibase/wrtsh/wrtsh1.cxx +++ b/sw/source/uibase/wrtsh/wrtsh1.cxx @@ -102,6 +102,7 @@ #include <svx/postattr.hxx> #include <comphelper/lok.hxx> #include <comphelper/propertyvalue.hxx> +#include <svtools/optionsdrawinglayer.hxx> #include <memory> #include <frmtool.hxx> @@ -266,9 +267,9 @@ void SwWrtShell::Insert( const OUString &rStr ) // Maximum height limit not possible, because the maximum height // of the current frame can not be obtained. -void SwWrtShell::Insert( const OUString &rPath, const OUString &rFilter, - const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr, - RndStdIds nAnchorType ) +void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter, + const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr, + RndStdIds nAnchorType ) { ResetCursorStack(); if ( !CanInsert() ) @@ -1025,7 +1026,6 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType) switch (eType) { case SwContentControlType::RICH_TEXT: - case SwContentControlType::PICTURE: { pContentControl->SetShowingPlaceHolder(true); if (!HasSelection()) @@ -1056,6 +1056,50 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType) pContentControl->SetListItems({ aListItem }); break; } + case SwContentControlType::PICTURE: + { + // Set up the picture content control. + pContentControl->SetShowingPlaceHolder(true); + pContentControl->SetPicture(true); + + // Create the placeholder bitmap. + BitmapEx aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP); + Color aColor = SvtOptionsDrawinglayer::getHilightColor(); + aColor.IncreaseLuminance(255 * 0.75); + aBitmap.Erase(aColor); + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME)); + StartUndo(SwUndoId::INSERT, &aRewriter); + LockPaint(); + StartAction(); + InsertGraphic(OUString(), OUString(), aBitmap, nullptr, RndStdIds::FLY_AS_CHAR); + + // Set properties on the bitmap. + SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet(GetDoc()->GetAttrPool()); + GetFlyFrameAttr(aSet); + SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000); + aSet.Put(aSize); + SetFlyFrameAttr(aSet); + SwFrameFormat* pFrameFormat = GetFlyFrameFormat(); + EndAction(); + UnlockPaint(); + EndUndo(); + + // Go after the anchor position. + UnSelectFrame(); + LeaveSelFrameMode(); + { + SwCursor* pCursor = getShellCursor(true); + pCursor->DeleteMark(); + const SwPosition* pAnchor = pFrameFormat->GetAnchor().GetContentAnchor(); + pCursor->GetPoint()->nContent = pAnchor->nContent; + ++pCursor->GetPoint()->nContent; + } + + // Select before the anchor position. + Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false); + break; + } } if (aPlaceholder.getLength()) { diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index 50be3dde2bba..c755f9cc88da 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -713,6 +713,7 @@ <menu:menu menu:id=".uno:ContentControlsMenu"> <menu:menupopup> <menu:menuitem menu:id=".uno:InsertContentControl"/> + <menu:menuitem menu:id=".uno:InsertPictureContentControl"/> <menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/> <menu:menuitem menu:id=".uno:InsertDropdownContentControl"/> <menu:menuitem menu:id=".uno:ContentControlProperties"/> diff --git a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml index 147b4dd03d6e..cc4483cda320 100644 --- a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml +++ b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml @@ -16,6 +16,7 @@ <menu:menu menu:id=".uno:MSCompatContentControls"> <menu:menupopup> <menu:menuitem menu:id=".uno:InsertContentControl"/> + <menu:menuitem menu:id=".uno:InsertPictureContentControl"/> <menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/> <menu:menuitem menu:id=".uno:InsertDropdownContentControl"/> <menu:menuitem menu:id=".uno:DatePickerFormField"/> commit 2e6b891afacd59c70f5ff164a4144c24ee7988b2 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 20 08:54:28 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue May 24 13:13:46 2022 +0200 sw content controls, picture: add DOCX filter Map Picture UNO property on content controls to: <w:sdt> <w:sdtPr> <w:picture/> ... And do the opposite on import. (cherry picked from commit 22d7cbc0f0c50c59abca7ab5f7db46e4d0e5f86a) Conflicts: sw/qa/extras/ooxmlexport/ooxmlexport17.cxx Change-Id: I5b164f796f194f5fc4bb30d7a30e053e577ed92d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134848 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index 1c4c99597c21..58b7a4845aec 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -185,7 +185,7 @@ CPPUNIT_TEST_FIXTURE(Test, testCheckboxContentControlExport) CPPUNIT_TEST_FIXTURE(Test, testDropdownContentControlExport) { - // Given a document with a checkbox content control around a text portion: + // Given a document with a dropdown content control around a text portion: mxComponent = loadFromDesktop("private:factory/swriter"); uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); @@ -235,6 +235,41 @@ CPPUNIT_TEST_FIXTURE(Test, testDropdownContentControlExport) assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[3]", "value", "B"); } +CPPUNIT_TEST_FIXTURE(Test, testPictureContentControlExport) +{ + // Given a document with a picture content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + 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("Picture", uno::Any(true)); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to DOCX: + save("Office Open XML Text", maTempFile); + mbExported = true; + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + // Without the fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. <w:picture> was lost on export. + assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:picture", 1); +} + DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx") { xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 939f3cffbbf2..322c8e896658 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -2343,6 +2343,11 @@ void DocxAttributeOutput::WriteContentControlStart() m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr); } + if (m_pContentControl->GetPicture()) + { + m_pSerializer->singleElementNS(XML_w, XML_picture); + } + if (m_pContentControl->GetCheckbox()) { m_pSerializer->startElementNS(XML_w14, XML_checkbox); diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx index 633355c79a5f..b2e7f1058f88 100644 --- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx +++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx @@ -181,6 +181,39 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunDropdown) uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(OUString("choose a color"), xContent->getString()); } + +CPPUNIT_TEST_FIXTURE(Test, testSdtRunPicture) +{ + // Given a document with a dropdown inline/run SDT: + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-picture.docx"; + + // When loading the document: + getComponent() = loadFromDesktop(aURL); + + // Then make sure that the doc model has a clickable picture content control: + uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xParagraphsAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParagraphs = xParagraphsAccess->createEnumeration(); + uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration(); + uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), uno::UNO_QUERY); + OUString aPortionType; + xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType; + // Without the accompanying fix in place, this failed with: + // - Expected: ContentControl + // - Actual : Frame + // i.e. the SDT was imported as a plain image, not as a clickable placeholder in a content + // control. + CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType); + uno::Reference<text::XTextContent> xContentControl; + xTextPortion->getPropertyValue("ContentControl") >>= xContentControl; + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + bool bPicture{}; + xContentControlProps->getPropertyValue("Picture") >>= bPicture; + CPPUNIT_ASSERT(bPicture); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx new file mode 100644 index 000000000000..25fcc7f6f8f9 Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 817bd1125ce1..0f9139e80890 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1098,6 +1098,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) case SdtControlType::richText: case SdtControlType::checkBox: case SdtControlType::dropDown: + case SdtControlType::picture: m_pImpl->PopSdt(); break; default: @@ -2787,6 +2788,16 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) } break; } + else if (nSprmId == NS_ooxml::LN_CT_SdtPr_picture) + { + m_pImpl->m_pSdtHelper->setControlType(SdtControlType::picture); + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties) + { + pProperties->resolve(*this); + } + break; + } } // this is an unsupported SDT property, create a grab bag for it diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 813f9943a005..e0eac791f26f 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -920,6 +920,11 @@ void DomainMapper_Impl::PopSdt() } } + if (m_pSdtHelper->getControlType() == SdtControlType::picture) + { + xContentControlProps->setPropertyValue("Picture", uno::Any(true)); + } + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); m_pSdtHelper->clear(); diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index a1aecd2aa704..cdf3bafbb9b0 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -44,6 +44,7 @@ enum class SdtControlType plainText, richText, checkBox, + picture, unsupported, // Sdt block is defined, but we still do not support such type of field unknown };