tdf#161652 editeng, RTF copy: only write used paragraph styles
Copy a single world from the Impress bugdoc to Writer, number of paragraph styles increase from 126 to 221, while only +0 or +1 are expected. It seems the problem is that the editeng doc of the shape refers to all styles of the masterpage and we write the style table before the content, so we export all styles to be on the safe side. Fix the problem by iterating the paragraphs of the selection in the "copy" (not "export") case, assuming that typically the selection doesn't refer to all available styles in the document, and the number of paragraphs in a shape is not a large amount. An alternative would be to limit the style import on the RTF reading side, but not producing those not needed styles in the first place looks superior. Change-Id: I43e4c542e530ff6422357a28399718e89fdbabe9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169251 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
parent
41d26f14ff
commit
afb4ea6746
6 changed files with 225 additions and 4 deletions
69
editeng/CppunitTest_editeng_editeng.mk
Normal file
69
editeng/CppunitTest_editeng_editeng.mk
Normal file
|
@ -0,0 +1,69 @@
|
|||
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
|
||||
#*************************************************************************
|
||||
#
|
||||
# This file is part of the LibreOffice project.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
#*************************************************************************
|
||||
|
||||
$(eval $(call gb_CppunitTest_CppunitTest,editeng_editeng))
|
||||
|
||||
$(eval $(call gb_CppunitTest_add_exception_objects,editeng_editeng, \
|
||||
editeng/qa/editeng/editeng \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_library_objects,editeng_editeng,editeng))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_libraries,editeng_editeng, \
|
||||
basegfx \
|
||||
comphelper \
|
||||
cppu \
|
||||
cppuhelper \
|
||||
docmodel \
|
||||
i18nlangtag \
|
||||
i18nutil \
|
||||
lng \
|
||||
sal \
|
||||
salhelper \
|
||||
sax \
|
||||
sot \
|
||||
sfx \
|
||||
svl \
|
||||
svt \
|
||||
test \
|
||||
tk \
|
||||
tl \
|
||||
ucbhelper \
|
||||
unotest \
|
||||
utl \
|
||||
vcl \
|
||||
xo \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_externals,editeng_editeng,\
|
||||
boost_headers \
|
||||
icuuc \
|
||||
libxml2 \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_set_include,editeng_editeng,\
|
||||
-I$(SRCDIR)/editeng/inc \
|
||||
-I$(SRCDIR)/editeng/source/editeng \
|
||||
$$(INCLUDE) \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_sdk_api,editeng_editeng))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_ure,editeng_editeng))
|
||||
$(eval $(call gb_CppunitTest_use_vcl,editeng_editeng))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_rdb,editeng_editeng,services))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_configuration,editeng_editeng))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_more_fonts,editeng_editeng))
|
||||
|
||||
# vim: set noet sw=4 ts=4:
|
|
@ -31,6 +31,7 @@ $(eval $(call gb_Module_add_l10n_targets,editeng,\
|
|||
|
||||
$(eval $(call gb_Module_add_check_targets,editeng,\
|
||||
$(if $(and $(filter $(COM),MSC),$(MERGELIBS)),, \
|
||||
CppunitTest_editeng_editeng \
|
||||
CppunitTest_editeng_core) \
|
||||
CppunitTest_editeng_borderline \
|
||||
CppunitTest_editeng_lookuptree \
|
||||
|
|
101
editeng/qa/editeng/editeng.cxx
Normal file
101
editeng/qa/editeng/editeng.cxx
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This file is part of the LibreOffice project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <test/bootstrapfixture.hxx>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <editeng/editeng.hxx>
|
||||
#include <sfx2/app.hxx>
|
||||
#include <svtools/parrtf.hxx>
|
||||
#include <svtools/rtftoken.h>
|
||||
|
||||
#include <editdoc.hxx>
|
||||
#include <eeobj.hxx>
|
||||
|
||||
using namespace com::sun::star;
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Covers editeng/source/editeng/ fixes.
|
||||
class Test : public test::BootstrapFixture
|
||||
{
|
||||
public:
|
||||
Test() {}
|
||||
|
||||
void setUp() override
|
||||
{
|
||||
test::BootstrapFixture::setUp();
|
||||
mpItemPool = new EditEngineItemPool();
|
||||
SfxApplication::GetOrCreate();
|
||||
}
|
||||
|
||||
void tearDown() override
|
||||
{
|
||||
mpItemPool.clear();
|
||||
test::BootstrapFixture::tearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
rtl::Reference<EditEngineItemPool> mpItemPool;
|
||||
};
|
||||
|
||||
/// RTF parser that counts the styles in the document.
|
||||
class StyleCounter : public SvRTFParser
|
||||
{
|
||||
public:
|
||||
StyleCounter(SvStream& rStream);
|
||||
void NextToken(int nToken) override;
|
||||
|
||||
int m_nStyles = 0;
|
||||
};
|
||||
|
||||
StyleCounter::StyleCounter(SvStream& rStream)
|
||||
: SvRTFParser(rStream)
|
||||
{
|
||||
}
|
||||
|
||||
void StyleCounter::NextToken(int nToken)
|
||||
{
|
||||
if (nToken == RTF_S)
|
||||
{
|
||||
++m_nStyles;
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testRTFStyleExport)
|
||||
{
|
||||
// Given a document with an unreferenced style:
|
||||
EditEngine aEditEngine(mpItemPool.get());
|
||||
rtl::Reference<SfxStyleSheetPool> xStyles(new SfxStyleSheetPool(*mpItemPool));
|
||||
xStyles->Make("mystyle", SfxStyleFamily::Para);
|
||||
aEditEngine.SetStyleSheetPool(xStyles.get());
|
||||
OUString aText = u"mytest"_ustr;
|
||||
aEditEngine.SetText(aText);
|
||||
|
||||
// When copying a word from that document:
|
||||
uno::Reference<datatransfer::XTransferable> xData
|
||||
= aEditEngine.CreateTransferable(ESelection(0, 0, 0, aText.getLength()));
|
||||
|
||||
// Then make sure the RTF result doesn't contain the style:
|
||||
auto pData = dynamic_cast<EditDataObject*>(xData.get());
|
||||
SvMemoryStream& rStream = pData->GetRTFStream();
|
||||
tools::SvRef<StyleCounter> xReader(new StyleCounter(rStream));
|
||||
CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error);
|
||||
// Without the accompanying fix in place, this test would have failed with:
|
||||
// - Expected: 0
|
||||
// - Actual : 1
|
||||
// i.e. unreferenced paragraph styles were exported.
|
||||
CPPUNIT_ASSERT_EQUAL(0, xReader->m_nStyles);
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
@ -770,7 +770,7 @@ private:
|
|||
EditPaM ReadXML( SvStream& rInput, EditSelection aSel );
|
||||
EditPaM ReadHTML( SvStream& rInput, const OUString& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs );
|
||||
ErrCode WriteText( SvStream& rOutput, EditSelection aSel );
|
||||
ErrCode WriteRTF( SvStream& rOutput, EditSelection aSel );
|
||||
ErrCode WriteRTF( SvStream& rOutput, EditSelection aSel, bool bClipboard );
|
||||
void WriteXML(SvStream& rOutput, const EditSelection& rSel);
|
||||
|
||||
void WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_Int32 nPara, sal_Int32 nPos,
|
||||
|
|
|
@ -3951,7 +3951,7 @@ uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable(
|
|||
|
||||
pDataObj->GetString() = convertLineEnd(GetSelected(aSelection), GetSystemLineEnd()); // System specific
|
||||
|
||||
WriteRTF( pDataObj->GetRTFStream(), aSelection );
|
||||
WriteRTF( pDataObj->GetRTFStream(), aSelection, /*bClipboard=*/true );
|
||||
pDataObj->GetRTFStream().Seek( 0 );
|
||||
|
||||
WriteXML( pDataObj->GetODFStream(), aSelection );
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
using namespace ::com::sun::star;
|
||||
using namespace ::com::sun::star::uno;
|
||||
|
@ -206,7 +207,7 @@ void ImpEditEngine::Write(SvStream& rOutput, EETextFormat eFormat, const EditSel
|
|||
if ( eFormat == EETextFormat::Text )
|
||||
WriteText( rOutput, rSel );
|
||||
else if ( eFormat == EETextFormat::Rtf )
|
||||
WriteRTF( rOutput, rSel );
|
||||
WriteRTF( rOutput, rSel, /*bClipboard=*/false );
|
||||
else if ( eFormat == EETextFormat::Xml )
|
||||
WriteXML( rOutput, rSel );
|
||||
else if ( eFormat == EETextFormat::Html )
|
||||
|
@ -291,7 +292,7 @@ void ImpEditEngine::WriteXML(SvStream& rOutput, const EditSelection& rSel)
|
|||
SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel );
|
||||
}
|
||||
|
||||
ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
|
||||
ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel, bool bClipboard )
|
||||
{
|
||||
assert( IsUpdateLayout() && "WriteRTF for UpdateMode = sal_False!" );
|
||||
CheckIdleFormatter();
|
||||
|
@ -456,6 +457,50 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
|
|||
nId++;
|
||||
}
|
||||
|
||||
// Collect used paragraph styles when copying to the clipboard.
|
||||
std::set<SfxStyleSheetBase*> aUsedParagraphStyles;
|
||||
if (bClipboard)
|
||||
{
|
||||
for (sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++)
|
||||
{
|
||||
ContentNode* pNode = maEditDoc.GetObject(nNode);
|
||||
if (!pNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SfxStyleSheet* pParaStyle = pNode->GetStyleSheet();
|
||||
if (!pParaStyle)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
aUsedParagraphStyles.insert(pParaStyle);
|
||||
|
||||
const OUString& rParent = pParaStyle->GetParent();
|
||||
if (!rParent.isEmpty())
|
||||
{
|
||||
auto pParent = static_cast<SfxStyleSheet*>(
|
||||
GetStyleSheetPool()->Find(rParent, pParaStyle->GetFamily()));
|
||||
if (pParent)
|
||||
{
|
||||
aUsedParagraphStyles.insert(pParent);
|
||||
}
|
||||
}
|
||||
|
||||
const OUString& rFollow = pParaStyle->GetFollow();
|
||||
if (!rFollow.isEmpty())
|
||||
{
|
||||
auto pFollow = static_cast<SfxStyleSheet*>(
|
||||
GetStyleSheetPool()->Find(rFollow, pParaStyle->GetFamily()));
|
||||
if (pFollow)
|
||||
{
|
||||
aUsedParagraphStyles.insert(pFollow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( aSSSIterator->Count() )
|
||||
{
|
||||
|
||||
|
@ -465,6 +510,11 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
|
|||
for ( SfxStyleSheetBase* pStyle = aSSSIterator->First(); pStyle;
|
||||
pStyle = aSSSIterator->Next() )
|
||||
{
|
||||
if (bClipboard && !aUsedParagraphStyles.contains(pStyle))
|
||||
{
|
||||
// Don't write unused paragraph styles in the clipboard case.
|
||||
continue;
|
||||
}
|
||||
|
||||
rOutput << endl;
|
||||
rOutput.WriteChar( '{' ).WriteOString( OOO_STRING_SVTOOLS_RTF_S );
|
||||
|
|
Loading…
Reference in a new issue