sw/qa/extras/htmlexport/htmlexport.cxx | 48 +++++++++++++++ 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, 195 insertions(+), 103 deletions(-)
New commits: commit cf04fc6747d2824bea3014e8c338f4bb14808de9 Author: Mike Kaganski <[email protected]> AuthorDate: Fri Jul 28 13:06:08 2023 +0300 Commit: Mike Kaganski <[email protected]> CommitDate: Sun Jul 30 13:02:27 2023 +0300 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 <[email protected]> diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 7400eb34c556..59b98f44144d 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> @@ -2595,6 +2596,53 @@ 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: + uno::Reference<css::drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, + uno::UNO_QUERY_THROW); + auto xDrawPage(xDrawPageSupplier->getDrawPage()); + uno::Reference<css::frame::XModel> xModel(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference<css::view::XSelectionSupplier> xController(xModel->getCurrentController(), + uno::UNO_QUERY_THROW); + xController->select(xDrawPage->getByIndex(0)); + + // Store only the selection + uno::Reference<css::frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY_THROW); + 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 457ff80b517b..49e0ec239c94 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( auto 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 3157943dcceb..479cc9da528c 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 1aec184d8a6c..819218527bf2 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -1484,7 +1484,7 @@ Writer& OutHTML_FrameFormatOLENode( Writer& rWrt, const SwFrameFormat& rFrameFor } Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrameFormat, - bool bInCntnr ) + bool bInCntnr, bool bWriteReplacementGraphic ) { SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt); @@ -1654,58 +1654,61 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame rHTMLWrt.m_bLFPossible = true; } - OUString aGraphicURL; - OUString aMimeType; - if(!rHTMLWrt.mbEmbedImages) + if (!bObjectOpened || bWriteReplacementGraphic) { - const OUString* pTempFileName = rHTMLWrt.GetOrigFileName(); - if(pTempFileName) - aGraphicURL = *pTempFileName; + OUString aGraphicURL; + OUString aMimeType; + if(!rHTMLWrt.mbEmbedImages) + { + const OUString* pTempFileName = rHTMLWrt.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(rHTMLWrt.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(rHTMLWrt.GetOrigFileName(), aGraphic, u"png"); - osl::File aFile(aGraphicURL); - aFile.open(osl_File_OpenFlag_Create); - aFile.close(); + rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD; + if (bObjectOpened) // Still at least close the tag. + rWrt.Strm().WriteOString(Concat2View("</" + rHTMLWrt.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 - { - rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD; - if (bObjectOpened) // Still at least close the tag. - rWrt.Strm().WriteOString(Concat2View("</" + rHTMLWrt.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(), rHTMLWrt.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(), rHTMLWrt.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 a3b900b6a222..e71459e42007 100644 --- a/sw/source/filter/html/wrthtml.cxx +++ b/sw/source/filter/html/wrthtml.cxx @@ -531,64 +531,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 bd60d1a84e07..3914a27f134c 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -678,7 +678,7 @@ struct HTMLSaveData Writer& OutHTML_FrameFormatOLENode( Writer& rWrt, const SwFrameFormat& rFormat, bool bInCntnr ); Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFormat, - bool bInCntnr ); + bool bInCntnr, bool bWriteReplacementGraphic = true ); Writer& OutHTML_SwTextNode( Writer&, const SwContentNode& ); Writer& OutHTML_SwTableNode( Writer& , SwTableNode &, const SwFrameFormat *, diff --git a/sw/source/uibase/app/docsh.cxx b/sw/source/uibase/app/docsh.cxx index b9a8430deedc..6ae21a6d2f76 100644 --- a/sw/source/uibase/app/docsh.cxx +++ b/sw/source/uibase/app/docsh.cxx @@ -765,16 +765,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)
