sw/qa/extras/htmlexport/htmlexport.cxx | 46 ++++++++++++++ sw/source/core/doc/doclay.cxx | 25 ++++++- sw/source/filter/basflt/shellio.cxx | 14 ++-- sw/source/filter/html/htmlplug.cxx | 91 ++++++++++++++-------------- sw/source/filter/html/wrthtml.cxx | 104 ++++++++++++++++++--------------- sw/source/filter/html/wrthtml.hxx | 2 sw/source/uibase/app/docsh.cxx | 14 +++- 7 files changed, 193 insertions(+), 103 deletions(-)
New commits: commit 2f9c1990a85b0e867400f5952095704e178680ad Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Jul 28 13:06:08 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Fri Jul 28 19:55:06 2023 +0200 ReqIF: allow to output a single selected OLE object To do that, "SelectionOnly" boolean propertyvalue is supported in the store arguments. Change-Id: I265e802256a9a678779bbd021dde9b0c87ca08b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155012 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index ebeab5963eda..7571e3b3535e 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/document/XStorageBasedDocument.hpp> #include <com/sun/star/frame/XStorable.hpp> #include <com/sun/star/packages/zip/ZipFileAccess.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> #include <test/htmltesttools.hxx> #include <tools/urlobj.hxx> @@ -2725,6 +2726,51 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_FrameTextAsObjectAltText) "Some text in frame & <foo>"); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testSingleOleExport) +{ + // Given a document containing an embedded OLE object: + createSwDoc("ole2.odt"); + + // Create a selection for that object: + auto xDrawPageSupplier(mxComponent.queryThrow<css::drawing::XDrawPageSupplier>()); + auto xDrawPage(xDrawPageSupplier->getDrawPage()); + auto xModel(mxComponent.queryThrow<css::frame::XModel>()); + auto xController(xModel->getCurrentController().queryThrow<css::view::XSelectionSupplier>()); + xController->select(xDrawPage->getByIndex(0)); + + // Store only the selection + auto xStorable(mxComponent.queryThrow<css::frame::XStorable>()); + css::uno::Sequence<css::beans::PropertyValue> aStoreProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + comphelper::makePropertyValue("RTFOLEMimeType", OUString("text/rtf")), + comphelper::makePropertyValue("SelectionOnly", true), + }; + xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); + + SvMemoryStream aStream; + WrapReqifFromTempFile(aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + + // The root element must be reqif-xhtml:object + assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object", "type", "text/rtf"); + // It has no children + assertXPathChildren(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object", 0); + // And the content is empty + assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object", ""); + + OUString aRtfData = getXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:object", "data"); + INetURLObject aUrl(maTempFile.GetURL()); + aUrl.setName(aRtfData); + SvMemoryStream aRtf; + HtmlExportTest::wrapRtfFragment(aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE), aRtf); + tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf)); + // The RTF OLE exports correctly + CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error); + CPPUNIT_ASSERT_EQUAL(tools::Long(9358), xReader->GetObjw()); + CPPUNIT_ASSERT_EQUAL(tools::Long(450), xReader->GetObjh()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx index 48e77a284d77..b6398ee8ce7f 100644 --- a/sw/source/core/doc/doclay.cxx +++ b/sw/source/core/doc/doclay.cxx @@ -499,6 +499,13 @@ SwPosFlyFrames SwDoc::GetAllFlyFormats( const SwPaM* pCmpRange, bool bDrawAlso, bool bAsCharAlso ) const { SwPosFlyFrames aRetval; + const SwStartNode* pDirectFly = nullptr; + if (pCmpRange && *pCmpRange->GetPoint() == *pCmpRange->GetMark() + && (pCmpRange->GetPoint()->GetNode().IsOLENode() + || pCmpRange->GetPoint()->GetNode().IsGrfNode())) + { + pDirectFly = pCmpRange->GetPoint()->GetNode().FindFlyStartNode(); + } // collect all anchored somehow to paragraphs for(sw::SpzFrameFormat* pFly: *GetSpzFrameFormats()) @@ -509,11 +516,23 @@ SwPosFlyFrames SwDoc::GetAllFlyFormats( const SwPaM* pCmpRange, bool bDrawAlso, { const SwFormatAnchor& rAnchor = pFly->GetAnchor(); SwNode const*const pAnchorNode = rAnchor.GetAnchorNode(); - if (pAnchorNode && - ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) || + if (!pAnchorNode) + continue; + if (pDirectFly) + { + const SwFormatContent& rContent = pFly->GetContent(); + const SwNodeIndex* pContentNodeIndex = rContent.GetContentIdx(); + if (pContentNodeIndex && pContentNodeIndex->GetIndex() == pDirectFly->GetIndex()) + { + aRetval.insert(SwPosFlyFrame(*pAnchorNode, pFly, aRetval.size())); + break; + } + continue; + } + if ( (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId()) || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) || - ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) && bAsCharAlso))) + ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) && bAsCharAlso) ) { if( pCmpRange && !lcl_TstFlyRange( pCmpRange, rAnchor )) continue; // not a valid FlyFrame diff --git a/sw/source/filter/basflt/shellio.cxx b/sw/source/filter/basflt/shellio.cxx index 2f5145024156..66251f168525 100644 --- a/sw/source/filter/basflt/shellio.cxx +++ b/sw/source/filter/basflt/shellio.cxx @@ -736,6 +736,12 @@ SwWriter::SwWriter(SfxMedium& rMedium, SwDoc &rDocument) { } +static bool isFlyNode(const SwPaM& pam) +{ + return *pam.GetPoint() == *pam.GetMark() + && (pam.GetPoint()->GetNode().IsOLENode() || pam.GetPoint()->GetNode().IsGrfNode()); +} + ErrCode SwWriter::Write( WriterRef const & rxWriter, const OUString* pRealFileName ) { // #i73788# @@ -777,13 +783,11 @@ ErrCode SwWriter::Write( WriterRef const & rxWriter, const OUString* pRealFileNa SwPaM *pEnd = pPam; // 1st round: Check if there is a selection - while(true) + do { - bHasMark = bHasMark || pPam->HasMark(); + bHasMark = pPam->HasMark() || isFlyNode(*pPam); pPam = pPam->GetNext(); - if(bHasMark || pPam == pEnd) - break; - } + } while (!bHasMark && pPam != pEnd); // if there is no selection, select the whole document if(!bHasMark) diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx index 74c8f1b7a958..57f756631a8b 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -1485,7 +1485,7 @@ SwHTMLWriter& OutHTML_FrameFormatOLENode( SwHTMLWriter& rWrt, const SwFrameForma } SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, - bool bInCntnr ) + bool bInCntnr, bool bWriteReplacementGraphic ) { const SwFormatContent& rFlyContent = rFrameFormat.GetContent(); SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1; @@ -1653,58 +1653,61 @@ SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFo rWrt.m_bLFPossible = true; } - OUString aGraphicURL; - OUString aMimeType; - if(!rWrt.mbEmbedImages) + if (!bObjectOpened || bWriteReplacementGraphic) { - const OUString* pTempFileName = rWrt.GetOrigFileName(); - if(pTempFileName) - aGraphicURL = *pTempFileName; + OUString aGraphicURL; + OUString aMimeType; + if(!rWrt.mbEmbedImages) + { + const OUString* pTempFileName = rWrt.GetOrigFileName(); + if(pTempFileName) + aGraphicURL = *pTempFileName; - OUString aFilterName("JPG"); - XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible; + OUString aFilterName("JPG"); + XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible; - if (bObjectOpened) - { - aFilterName = "PNG"; - nFlags = XOutFlags::NONE; - aMimeType = "image/png"; + if (bObjectOpened) + { + aFilterName = "PNG"; + nFlags = XOutFlags::NONE; + aMimeType = "image/png"; - if (aGraphic.GetType() == GraphicType::NONE) + if (aGraphic.GetType() == GraphicType::NONE) + { + // The OLE Object has no replacement image, write a stub. + aGraphicURL = lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"png"); + osl::File aFile(aGraphicURL); + aFile.open(osl_File_OpenFlag_Create); + aFile.close(); + } + } + + ErrCode nErr = XOutBitmap::WriteGraphic( aGraphic, aGraphicURL, + aFilterName, + nFlags ); + if( nErr ) // error, don't write anything { - // The OLE Object has no replacement image, write a stub. - aGraphicURL = lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"png"); - osl::File aFile(aGraphicURL); - aFile.open(osl_File_OpenFlag_Create); - aFile.close(); + rWrt.m_nWarn = WARN_SWG_POOR_LOAD; + if (bObjectOpened) // Still at least close the tag. + rWrt.Strm().WriteOString(Concat2View("</" + rWrt.GetNamespace() + + OOO_STRING_SVTOOLS_HTML_object ">")); + return rWrt; } - } + aGraphicURL = URIHelper::SmartRel2Abs( + INetURLObject(rWrt.GetBaseURL()), aGraphicURL, + URIHelper::GetMaybeFileHdl() ); - ErrCode nErr = XOutBitmap::WriteGraphic( aGraphic, aGraphicURL, - aFilterName, - nFlags ); - if( nErr ) // error, don't write anything - { - rWrt.m_nWarn = WARN_SWG_POOR_LOAD; - if (bObjectOpened) // Still at least close the tag. - rWrt.Strm().WriteOString(Concat2View("</" + rWrt.GetNamespace() - + OOO_STRING_SVTOOLS_HTML_object ">")); - return rWrt; } - aGraphicURL = URIHelper::SmartRel2Abs( - INetURLObject(rWrt.GetBaseURL()), aGraphicURL, - URIHelper::GetMaybeFileHdl() ); - + HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask + : HtmlFrmOpts::GenImgMask; + if (bObjectOpened) + nFlags |= HtmlFrmOpts::Replacement; + HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace); + OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, + pOLENd->GetTitle(), pOLENd->GetTwipSize(), + nFlags, "ole", nullptr, aMimeType ); + OutHTML_ImageEnd(aHtml, rWrt); } - HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask - : HtmlFrmOpts::GenImgMask; - if (bObjectOpened) - nFlags |= HtmlFrmOpts::Replacement; - HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace); - OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, - pOLENd->GetTitle(), pOLENd->GetTwipSize(), - nFlags, "ole", nullptr, aMimeType ); - OutHTML_ImageEnd(aHtml, rWrt); if (bObjectOpened) // Close native data. diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx index d4d7fea41260..97b2de547c7b 100644 --- a/sw/source/filter/html/wrthtml.cxx +++ b/sw/source/filter/html/wrthtml.cxx @@ -542,64 +542,74 @@ ErrCode SwHTMLWriter::WriteStream() m_aHTMLPosFlyFrames.clear(); CollectFlyFrames(); m_nLastParaToken = HtmlTokenId::NONE; - GetControls(); - CollectLinkTargets(); - sal_uInt16 nHeaderAttrs = 0; - m_pCurrPageDesc = MakeHeader( nHeaderAttrs ); + if (mbReqIF && !m_bWriteAll && m_pCurrentPam + && *m_pCurrentPam->GetPoint() == *m_pCurrentPam->GetMark() + && m_pCurrentPam->GetPoint()->GetNode().IsOLENode() && m_aHTMLPosFlyFrames.size() == 1) + { + // A single OLE object selection must be output: do it directly (without replacement) + OutHTML_FrameFormatOLENodeGrf(*this, m_aHTMLPosFlyFrames[0]->GetFormat(), true, false); + } + else + { + GetControls(); + CollectLinkTargets(); - m_bLFPossible = true; + sal_uInt16 nHeaderAttrs = 0; + m_pCurrPageDesc = MakeHeader( nHeaderAttrs ); - // output forms which contain only HiddenControls - OutHiddenForms(); + m_bLFPossible = true; - if( !aStartTags.isEmpty() ) - Strm().WriteOString( aStartTags ); + // output forms which contain only HiddenControls + OutHiddenForms(); - const SwFormatHeader *pFormatHeader; - const SfxItemSet& rPageItemSet = m_pCurrPageDesc->GetMaster().GetAttrSet(); - if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() && - (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && - !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) && - (pFormatHeader = rPageItemSet.GetItemIfSet( RES_HEADER )) ) - { - const SwFrameFormat *pHeaderFormat = pFormatHeader->GetHeaderFormat(); - if( pHeaderFormat ) - OutHTML_HeaderFooter( *this, *pHeaderFormat, true ); - } + if( !aStartTags.isEmpty() ) + Strm().WriteOString( aStartTags ); - m_nTextAttrsToIgnore = nHeaderAttrs; - Out_SwDoc( m_pOrigPam ); - m_nTextAttrsToIgnore = 0; + const SwFormatHeader *pFormatHeader; + const SfxItemSet& rPageItemSet = m_pCurrPageDesc->GetMaster().GetAttrSet(); + if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() && + (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && + !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) && + (pFormatHeader = rPageItemSet.GetItemIfSet( RES_HEADER )) ) + { + const SwFrameFormat *pHeaderFormat = pFormatHeader->GetHeaderFormat(); + if( pHeaderFormat ) + OutHTML_HeaderFooter( *this, *pHeaderFormat, true ); + } - if( mxFormComps.is() ) - OutForm( false, mxFormComps ); + m_nTextAttrsToIgnore = nHeaderAttrs; + Out_SwDoc( m_pOrigPam ); + m_nTextAttrsToIgnore = 0; - if( m_xFootEndNotes ) - OutFootEndNotes(); + if( mxFormComps.is() ) + OutForm( false, mxFormComps ); - const SwFormatFooter* pFormatFooter; - if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() && - (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) && - (pFormatFooter = rPageItemSet.GetItemIfSet( RES_FOOTER )) ) - { - const SwFrameFormat *pFooterFormat = pFormatFooter->GetFooterFormat(); - if( pFooterFormat ) - OutHTML_HeaderFooter( *this, *pFooterFormat, false ); - } + if( m_xFootEndNotes ) + OutFootEndNotes(); - if( m_bLFPossible ) - OutNewLine(); - if (!mbSkipHeaderFooter) - { - HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_body), false ); - OutNewLine(); - HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_html), false ); - } - else if (mbReqIF) - // ReqIF: end xhtml.BlkStruct.class. - HTMLOutFuncs::Out_AsciiTag(Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false); + const SwFormatFooter* pFormatFooter; + if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() && + (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) && + (pFormatFooter = rPageItemSet.GetItemIfSet( RES_FOOTER )) ) + { + const SwFrameFormat *pFooterFormat = pFormatFooter->GetFooterFormat(); + if( pFooterFormat ) + OutHTML_HeaderFooter( *this, *pFooterFormat, false ); + } + if( m_bLFPossible ) + OutNewLine(); + if (!mbSkipHeaderFooter) + { + HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_body), false ); + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_html), false ); + } + else if (mbReqIF) + // ReqIF: end xhtml.BlkStruct.class. + HTMLOutFuncs::Out_AsciiTag(Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false); + } // delete the table with floating frames OSL_ENSURE( m_aHTMLPosFlyFrames.empty(), "Were not all frames output?" ); m_aHTMLPosFlyFrames.clear(); diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index 4b6f7ad5c2a6..4a8ca7007a56 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -672,7 +672,7 @@ public: SwHTMLWriter& OutHTML_FrameFormatOLENode( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat, bool bInCntnr ); SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat, - bool bInCntnr ); + bool bInCntnr, bool bWriteReplacementGraphic = true ); SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter&, const SwContentNode& ); SwHTMLWriter& OutHTML_SwTableNode( SwHTMLWriter& , SwTableNode &, const SwFrameFormat *, diff --git a/sw/source/uibase/app/docsh.cxx b/sw/source/uibase/app/docsh.cxx index c3160e0ead9f..94858922ad0b 100644 --- a/sw/source/uibase/app/docsh.cxx +++ b/sw/source/uibase/app/docsh.cxx @@ -755,16 +755,24 @@ bool SwDocShell::ConvertTo( SfxMedium& rMedium ) ErrCode nErrno; const OUString aFileName( rMedium.GetName() ); - // No View, so the whole Document! - if (m_pWrtShell && !Application::IsHeadlessModeEnabled()) + bool bSelection = false; + if (m_pWrtShell) { + const SfxBoolItem* pSelectionItem = rMedium.GetItemSet().GetItemIfSet(SID_SELECTION); + bSelection = pSelectionItem && pSelectionItem->GetValue(); + } + + // No View, so the whole Document! (unless SID_SELECTION explicitly set) + if (m_pWrtShell && (!Application::IsHeadlessModeEnabled() || bSelection)) + { + SwWait aWait( *this, true ); // #i106906# const bool bFormerLockView = m_pWrtShell->IsViewLocked(); m_pWrtShell->LockView( true ); m_pWrtShell->StartAllAction(); m_pWrtShell->Push(); - SwWriter aWrt( rMedium, *m_pWrtShell, true ); + SwWriter aWrt( rMedium, *m_pWrtShell, !bSelection ); nErrno = aWrt.Write( xWriter, &aFileName ); //JP 16.05.97: In case the SFX revokes the View while saving if (m_pWrtShell)