tdf#144576 Copy a table from Writer to plain text editor as a Matrix
sw ascii filter - check for table nodes, output them seperately with formating to be displayed as a matrix when copy/pasted to a text file sw qa filter ascii - add new test suite along with test to check for correct output Change-Id: I8ca31bced3860e8e9752db8530ea6caaf31f2e5e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164833 Reviewed-by: Hossein <hossein@libreoffice.org> Tested-by: Jenkins
This commit is contained in:
parent
779a3b26ed
commit
3e7de6b1bc
5 changed files with 289 additions and 1 deletions
76
sw/CppunitTest_sw_filter_ascii.mk
Normal file
76
sw/CppunitTest_sw_filter_ascii.mk
Normal file
|
@ -0,0 +1,76 @@
|
|||
# -*- 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,sw_filter_ascii))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_filter_ascii))
|
||||
|
||||
$(eval $(call gb_CppunitTest_add_exception_objects,sw_filter_ascii, \
|
||||
sw/qa/filter/ascii/ascii \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_libraries,sw_filter_ascii, \
|
||||
comphelper \
|
||||
cppu \
|
||||
cppuhelper \
|
||||
editeng \
|
||||
sal \
|
||||
sfx \
|
||||
subsequenttest \
|
||||
svl \
|
||||
svx \
|
||||
svxcore \
|
||||
sw \
|
||||
swqahelper \
|
||||
test \
|
||||
unotest \
|
||||
utl \
|
||||
vcl \
|
||||
tl \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_externals,sw_filter_ascii,\
|
||||
boost_headers \
|
||||
libxml2 \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_set_include,sw_filter_ascii,\
|
||||
-I$(SRCDIR)/sw/inc \
|
||||
-I$(SRCDIR)/sw/source/core/inc \
|
||||
-I$(SRCDIR)/sw/source/uibase/inc \
|
||||
-I$(SRCDIR)/sw/qa/inc \
|
||||
$$(INCLUDE) \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_api,sw_filter_ascii,\
|
||||
udkapi \
|
||||
offapi \
|
||||
oovbaapi \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_ure,sw_filter_ascii))
|
||||
$(eval $(call gb_CppunitTest_use_vcl,sw_filter_ascii))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_rdb,sw_filter_ascii,services))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_custom_headers,sw_filter_ascii,\
|
||||
officecfg/registry \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_configuration,sw_filter_ascii))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_uiconfigs,sw_filter_ascii, \
|
||||
modules/swriter \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_more_fonts,sw_filter_ascii))
|
||||
|
||||
# vim: set noet sw=4 ts=4:
|
|
@ -167,6 +167,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
|
|||
CppunitTest_sw_filter_ww8 \
|
||||
CppunitTest_sw_filter_html \
|
||||
CppunitTest_sw_filter_xml \
|
||||
CppunitTest_sw_filter_ascii \
|
||||
CppunitTest_sw_a11y \
|
||||
CppunitTest_sw_core_theme \
|
||||
CppunitTest_sw_pdf_test \
|
||||
|
|
153
sw/qa/filter/ascii/ascii.cxx
Normal file
153
sw/qa/filter/ascii/ascii.cxx
Normal file
|
@ -0,0 +1,153 @@
|
|||
/* -*- 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 <swmodeltestbase.hxx>
|
||||
|
||||
#include <unotxdoc.hxx>
|
||||
#include <itabenum.hxx>
|
||||
#include <wrtsh.hxx>
|
||||
#include <com/sun/star/text/XTextTable.hpp>
|
||||
#include <ndtxt.hxx>
|
||||
#include <swdtflvr.hxx>
|
||||
#include <swmodule.hxx>
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Covers sw/source/filter/ascii/ fixes.
|
||||
*
|
||||
* Note that these tests are meant to be simple: either load a file and assert some result or build
|
||||
* a document model with code, export and assert that result.
|
||||
*
|
||||
* Keep using the various sw_<format>import/export suites for multiple filter calls inside a single
|
||||
* test.
|
||||
*/
|
||||
class Test : public SwModelTestBase
|
||||
{
|
||||
public:
|
||||
Test()
|
||||
: SwModelTestBase("/sw/qa/filter/ascii/data/")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testTdf144576_ascii)
|
||||
{
|
||||
// Given a document with a 2x2 table
|
||||
createSwDoc();
|
||||
SwDoc* pDoc = getSwDoc();
|
||||
SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
|
||||
SwInsertTableOptions aTableOptions(SwInsertTableFlags::DefaultBorder, 0);
|
||||
pWrtShell->InsertTable(aTableOptions, /*nRows=*/2, /*nCols=*/2);
|
||||
|
||||
uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
|
||||
uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
|
||||
CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
|
||||
uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
|
||||
|
||||
pWrtShell->GotoTable(u"Table1"_ustr);
|
||||
pWrtShell->Insert(u"A"_ustr);
|
||||
pWrtShell->GoNextCell(false);
|
||||
pWrtShell->Insert(u"B"_ustr);
|
||||
pWrtShell->GoNextCell(false);
|
||||
pWrtShell->Insert(u"C"_ustr);
|
||||
pWrtShell->GoNextCell(false);
|
||||
pWrtShell->Insert(u"D"_ustr);
|
||||
|
||||
// Select the whole table
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
|
||||
rtl::Reference<SwTransferable> xTransferable(new SwTransferable(*pWrtShell));
|
||||
xTransferable->Copy(); // Ctl-C
|
||||
xTransferable.get();
|
||||
|
||||
// Get the plain text version of the selection
|
||||
datatransfer::DataFlavor aFlavor;
|
||||
aFlavor.MimeType = "text/plain;charset=utf-16";
|
||||
aFlavor.DataType = cppu::UnoType<OUString>::get();
|
||||
uno::Any aData = xTransferable->getTransferData(aFlavor);
|
||||
OUString aActual;
|
||||
aData >>= aActual;
|
||||
pWrtShell->ClearMark();
|
||||
|
||||
CPPUNIT_ASSERT(aData.hasValue());
|
||||
|
||||
OUString aExpected = u"A\tB"_ustr SAL_NEWLINE_STRING u"C\tD"_ustr SAL_NEWLINE_STRING u""_ustr;
|
||||
|
||||
// Without the fix in place, the test fails with:
|
||||
// - Expected: A B
|
||||
// C D
|
||||
//
|
||||
// - Actual : A
|
||||
// B
|
||||
// C
|
||||
// D
|
||||
// i.e. Each cell is seperated by a tab
|
||||
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
|
||||
|
||||
// Add some newlines in the first two cells
|
||||
// and test to see if they're handled correctly
|
||||
uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName("A1"), uno::UNO_QUERY);
|
||||
xCellA1->setString(u""_ustr);
|
||||
uno::Reference<text::XTextRange> xCellB1(xTable1->getCellByName("B1"), uno::UNO_QUERY);
|
||||
xCellB1->setString(u""_ustr);
|
||||
|
||||
pWrtShell->GotoTable(u"Table1"_ustr);
|
||||
pWrtShell->Insert(u"A"_ustr);
|
||||
pWrtShell->SplitNode();
|
||||
pWrtShell->Insert(u"A1"_ustr);
|
||||
pWrtShell->GoNextCell(false);
|
||||
pWrtShell->Insert(u"B"_ustr);
|
||||
pWrtShell->SplitNode();
|
||||
pWrtShell->Insert(u"B1"_ustr);
|
||||
pWrtShell->SplitNode();
|
||||
pWrtShell->Insert(u"B2"_ustr);
|
||||
|
||||
aExpected
|
||||
= u"A"_ustr SAL_NEWLINE_STRING u"A1\tB"_ustr SAL_NEWLINE_STRING u"B1"_ustr SAL_NEWLINE_STRING u"B2"_ustr SAL_NEWLINE_STRING u"C\tD"_ustr SAL_NEWLINE_STRING u""_ustr;
|
||||
|
||||
// Select the whole table
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
dispatchCommand(mxComponent, ".uno:SelectAll", {});
|
||||
|
||||
// Get the plain text version of the selection
|
||||
rtl::Reference<SwTransferable> xNewTransferable(new SwTransferable(*pWrtShell));
|
||||
xNewTransferable->Copy(); // Ctl-C
|
||||
xNewTransferable.get();
|
||||
aData = xNewTransferable->getTransferData(aFlavor);
|
||||
CPPUNIT_ASSERT(aData.hasValue());
|
||||
aData >>= aActual;
|
||||
|
||||
// Without the fix in place, the test fails with:
|
||||
// - Expected: A
|
||||
// A1 B
|
||||
// B1
|
||||
// B2
|
||||
// C D
|
||||
//
|
||||
// - Actual : A
|
||||
// A1
|
||||
// B
|
||||
// B1
|
||||
// B2
|
||||
// C
|
||||
// D
|
||||
// i.e. Each cell is seperated by a tab, a newline inside
|
||||
// a cell gets written to the next line in the furthest
|
||||
// left spot available
|
||||
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
|
||||
}
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
@ -186,7 +186,14 @@ ErrCode SwASCWriter::WriteStream()
|
|||
}
|
||||
bWriteSttTag = false;
|
||||
}
|
||||
Out( aASCNodeFnTab, *pNd, *this );
|
||||
|
||||
SwTableNode* pTableNd = pNd->FindTableNode();
|
||||
|
||||
// Handle a table
|
||||
if (pTableNd && m_bWriteAll)
|
||||
WriteTable(pTableNd, pNd);
|
||||
else
|
||||
Out( aASCNodeFnTab, *pNd, *this );
|
||||
}
|
||||
bTstFly = false; // Testing once is enough
|
||||
}
|
||||
|
@ -221,6 +228,56 @@ void SwASCWriter::SetupFilterOptions(SfxMedium& rMedium)
|
|||
}
|
||||
}
|
||||
|
||||
void SwASCWriter::WriteTable(SwTableNode* pTableNd, SwTextNode* pNd)
|
||||
{
|
||||
OUString sPreLineEnd = this->m_sLineEnd;
|
||||
m_sLineEnd = u""_ustr;
|
||||
|
||||
const SwTableLine* pEndTabLine = pTableNd->GetTable().GetTabLines().back();
|
||||
const SwTableBox* pEndTabBox = pEndTabLine->GetTabBoxes().back();
|
||||
|
||||
for( const SwTableLine* pLine : pTableNd->GetTable().GetTabLines() )
|
||||
{
|
||||
for( const SwTableBox* pBox : pLine->GetTabBoxes() )
|
||||
{
|
||||
Out( aASCNodeFnTab, *pNd, *this );
|
||||
|
||||
Point aPrevBoxPoint = pNd->GetTableBox()->GetCoordinates();
|
||||
m_pCurrentPam->Move(fnMoveForward, GoInNode);
|
||||
pNd = m_pCurrentPam->GetPoint()->GetNode().GetTextNode();
|
||||
|
||||
// Line break in a box
|
||||
// Each line is a new SwTextNode so we
|
||||
// need to parse inside the current box
|
||||
while (pNd->GetTableBox() && (pNd->GetTableBox()->GetCoordinates() == aPrevBoxPoint))
|
||||
{
|
||||
Strm().WriteUnicodeOrByteText(sPreLineEnd);
|
||||
Out(aASCNodeFnTab, *pNd, *this);
|
||||
|
||||
m_pCurrentPam->Move(fnMoveForward, GoInNode);
|
||||
pNd = m_pCurrentPam->GetPoint()->GetNode().GetTextNode();
|
||||
}
|
||||
if (pBox != pLine->GetTabBoxes().back())
|
||||
Strm().WriteUChar( 0x9 );
|
||||
|
||||
if (pBox == pEndTabBox)
|
||||
this->m_sLineEnd = sPreLineEnd;
|
||||
|
||||
}// end for each Box
|
||||
|
||||
if (pLine == pEndTabLine)
|
||||
{
|
||||
m_pCurrentPam->Move(fnMoveBackward, GoInNode);
|
||||
pNd = m_pCurrentPam->GetPoint()->GetNode().GetTextNode();
|
||||
Strm().WriteUnicodeOrByteText( sPreLineEnd );
|
||||
}
|
||||
if (pLine != pEndTabLine)
|
||||
Strm().WriteUnicodeOrByteText( sPreLineEnd );
|
||||
|
||||
}// end For each row
|
||||
this->m_sLineEnd = sPreLineEnd;
|
||||
}
|
||||
|
||||
void GetASCWriter(
|
||||
std::u16string_view rFltNm, [[maybe_unused]] const OUString& /*rBaseURL*/, WriterRef& xRet )
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ class SwASCWriter : public Writer
|
|||
OUString m_sLineEnd;
|
||||
|
||||
virtual ErrCode WriteStream() override;
|
||||
void WriteTable(SwTableNode* pTableNd, SwTextNode* pNd);
|
||||
|
||||
public:
|
||||
SwASCWriter(std::u16string_view rFilterName);
|
||||
|
|
Loading…
Reference in a new issue