include/oox/shape/ShapeDrawingFragmentHandler.hxx | 2 oox/source/shape/ShapeContextHandler.cxx | 2 oox/source/shape/ShapeDrawingFragmentHandler.cxx | 2 sc/qa/unit/data/xlsx/tdf83671_SmartArt_import.xlsx |binary sc/qa/unit/subsequent_filters_test2.cxx | 47 +++++++++++++++++++++ sc/source/filter/oox/drawingfragment.cxx | 22 +++++++++ solenv/clang-format/excludelist | 2 7 files changed, 73 insertions(+), 4 deletions(-)
New commits: commit 9ad7df41572d67687221cb43d53cde27a45fff0f Author: Regina Henschel <rb.hensc...@t-online.de> AuthorDate: Thu Oct 20 14:28:07 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Oct 24 15:09:37 2022 +0200 tdf#83671 make SmartArt visible in import of xlsx Problem is, that Excel writes a zero size in xdr:xfrm for the SmartArt. With that the import generates a background size with zero width and height and no shapes at all in the SmartArt group. The diagram DOM is imported correctly. The actual size is not known until the row and column values of the anchor are evaluated. The idea of this patch is to correct the background size directly and to repeat the import of drawing.xml when the actual size is known. I noticed that in import of SmartArt in docx there is a similar problem that the SmartArt shapes are missing at some point, as can be seen in ShapeContextHandler::getShape(), about line 428. It uses ShapeDrawingFragmentHandler to import the shapes. To be able to use that handler too, I have moved its header file to include. The solution for docx uses a loop over the vector getExtDrawings(). But I have not seen a SmartArt case, where more then one element exists in it. Whether the shape is a diagram, is indirectly tested currently. The shape has yet no direct method for it. Change-Id: I9d705ed5bfb2894e9ce740ebf8589e06b4870bed Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141571 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/oox/source/shape/ShapeDrawingFragmentHandler.hxx b/include/oox/shape/ShapeDrawingFragmentHandler.hxx similarity index 93% rename from oox/source/shape/ShapeDrawingFragmentHandler.hxx rename to include/oox/shape/ShapeDrawingFragmentHandler.hxx index 15b424b6fd8f..340edca5e1d1 100644 --- a/oox/source/shape/ShapeDrawingFragmentHandler.hxx +++ b/include/oox/shape/ShapeDrawingFragmentHandler.hxx @@ -16,7 +16,7 @@ namespace oox::shape { /// Generic (i.e. not specific to PPTX) handler for the prerendered diagram parsing. -class ShapeDrawingFragmentHandler : public oox::core::FragmentHandler2 +class OOX_DLLPUBLIC ShapeDrawingFragmentHandler : public oox::core::FragmentHandler2 { public: ShapeDrawingFragmentHandler(oox::core::XmlFilterBase& rFilter, const OUString& rFragmentPath, oox::drawingml::ShapePtr pGroupShapePtr); diff --git a/oox/source/shape/ShapeContextHandler.cxx b/oox/source/shape/ShapeContextHandler.cxx index 54a455452365..4e8329c1417d 100644 --- a/oox/source/shape/ShapeContextHandler.cxx +++ b/oox/source/shape/ShapeContextHandler.cxx @@ -22,7 +22,7 @@ #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> #include <oox/shape/ShapeContextHandler.hxx> -#include "ShapeDrawingFragmentHandler.hxx" +#include <oox/shape/ShapeDrawingFragmentHandler.hxx> #include "LockedCanvasContext.hxx" #include "WpsContext.hxx" #include "WpgContext.hxx" diff --git a/oox/source/shape/ShapeDrawingFragmentHandler.cxx b/oox/source/shape/ShapeDrawingFragmentHandler.cxx index 0e915058fcb4..456f7df6c80d 100644 --- a/oox/source/shape/ShapeDrawingFragmentHandler.cxx +++ b/oox/source/shape/ShapeDrawingFragmentHandler.cxx @@ -7,7 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "ShapeDrawingFragmentHandler.hxx" +#include <oox/shape/ShapeDrawingFragmentHandler.hxx> #include <oox/drawingml/shapegroupcontext.hxx> #include <oox/token/namespaces.hxx> diff --git a/sc/qa/unit/data/xlsx/tdf83671_SmartArt_import.xlsx b/sc/qa/unit/data/xlsx/tdf83671_SmartArt_import.xlsx new file mode 100644 index 000000000000..9ec0a0e7906c Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf83671_SmartArt_import.xlsx differ diff --git a/sc/qa/unit/subsequent_filters_test2.cxx b/sc/qa/unit/subsequent_filters_test2.cxx index e4bf84b2fade..1ce547a23373 100644 --- a/sc/qa/unit/subsequent_filters_test2.cxx +++ b/sc/qa/unit/subsequent_filters_test2.cxx @@ -60,6 +60,7 @@ #include <tools/UnitConversion.hxx> #include <unotools/syslocaleoptions.hxx> #include "helper/qahelper.hxx" +#include <officecfg/Office/Common.hxx> using namespace ::com::sun::star; using namespace ::com::sun::star::uno; @@ -185,6 +186,7 @@ public: void testAutofilterNamedRangesXLSX(); void testInvalidBareBiff5(); void testTooManyColsRows(); + void testTdf83671_SmartArt_import(); CPPUNIT_TEST_SUITE(ScFiltersTest2); @@ -301,6 +303,7 @@ public: CPPUNIT_TEST(testAutofilterNamedRangesXLSX); CPPUNIT_TEST(testInvalidBareBiff5); CPPUNIT_TEST(testTooManyColsRows); + CPPUNIT_TEST(testTdf83671_SmartArt_import); CPPUNIT_TEST_SUITE_END(); }; @@ -3042,6 +3045,50 @@ void ScFiltersTest2::testTooManyColsRows() xDocSh->DoClose(); } +void ScFiltersTest2::testTdf83671_SmartArt_import() +{ + // The example doc contains a diagram (SmartArt). Such should be imported as group object. + // Error was, that the background shape had size zero and the diagram shapes where missing. + + // Make sure SmartArt is loaded as group shape + bool bUseGroup = officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::get(); + if (!bUseGroup) + { + std::shared_ptr<comphelper::ConfigurationChanges> pChange( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::set(true, pChange); + pChange->commit(); + } + + // Get document and shape + ScDocShellRef xDocSh = loadDoc(u"tdf83671_SmartArt_import.", FORMAT_XLSX); + ScDocument& rDoc = xDocSh->GetDocument(); + ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); + SdrPage* pPage = pDrawLayer->GetPage(0); + SdrObject* pObj = pPage->GetObj(0); + + // Check that it is a group shape with 4 children + CPPUNIT_ASSERT(pObj->IsGroupObject()); + SdrObjList* pChildren = pObj->getChildrenOfSdrObject(); + CPPUNIT_ASSERT_EQUAL(size_t(4), pChildren->GetObjCount()); + + // The background shape should have about 60mm x 42mm size. + // Without fix its size was zero. + tools::Rectangle aBackground = pChildren->GetObj(0)->GetLogicRect(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(6000), aBackground.getOpenWidth(), 10); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(4200), aBackground.getOpenHeight(), 10); + + if (!bUseGroup) + { + std::shared_ptr<comphelper::ConfigurationChanges> pChange( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::set(false, pChange); + pChange->commit(); + } + + xDocSh->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScFiltersTest2); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/source/filter/oox/drawingfragment.cxx b/sc/source/filter/oox/drawingfragment.cxx index 205e9983d3e7..d61e17331428 100644 --- a/sc/source/filter/oox/drawingfragment.cxx +++ b/sc/source/filter/oox/drawingfragment.cxx @@ -39,6 +39,7 @@ #include <oox/drawingml/graphicshapecontext.hxx> #include <oox/helper/attributelist.hxx> #include <oox/helper/propertyset.hxx> +#include <oox/shape/ShapeDrawingFragmentHandler.hxx> #include <oox/token/namespaces.hxx> #include <oox/token/properties.hxx> #include <oox/token/tokens.hxx> @@ -50,6 +51,7 @@ #include <stylesbuffer.hxx> #include <themebuffer.hxx> #include <worksheetbuffer.hxx> + namespace oox::xls { using namespace ::com::sun::star::beans; @@ -303,6 +305,26 @@ void DrawingFragment::onEndElement() mxShape->setPosition(Point(aShapeRectEmu32.X, aShapeRectEmu32.Y)); mxShape->setSize(Size(aShapeRectEmu32.Width, aShapeRectEmu32.Height)); + // tdf#83671. Because Excel saves a diagram with zero size in xdr:xfm, the + // initial diagram import produces a background shape with zero size and no + // diagram shapes at all. Here the size has been determined from the anchor and + // thus repeating the import of diagram.xml gives the diagram shapes. + if (mxShape->getDiagramDoms().getLength() > 0 + && mxShape->getChildren().size() == 1 + && mxShape->getExtDrawings().size() == 1) + { + mxShape->getChildren()[0]->setSize(mxShape->getSize()); + OUString sFragmentPath( + getFragmentPathFromRelId(mxShape->getExtDrawings()[0])); + // Don't know why importFragment looses shape name and id. Rescue them. + OUString sBackupName(mxShape->getName()); + OUString sBackupId(mxShape->getId()); + getOoxFilter().importFragment(new oox::shape::ShapeDrawingFragmentHandler( + getOoxFilter(), sFragmentPath, mxShape)); + mxShape->setName(sBackupName); + mxShape->setId(sBackupId); + } + basegfx::B2DHomMatrix aTransformation; if ( !bIsShapeVisible) mxShape->setHidden(true); diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index ece753ea6256..7812b0c0f277 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -5456,6 +5456,7 @@ include/oox/ppt/soundactioncontext.hxx include/oox/ppt/timenode.hxx include/oox/ppt/timenodelistcontext.hxx include/oox/shape/ShapeContextHandler.hxx +include/oox/shape/ShapeDrawingFragmentHandler.hxx include/oox/shape/ShapeFilterBase.hxx include/oox/token/tokenmap.hxx include/oox/vml/vmldrawing.hxx @@ -7276,7 +7277,6 @@ oox/source/ppt/timetargetelementcontext.cxx oox/source/ppt/timetargetelementcontext.hxx oox/source/shape/ShapeContextHandler.cxx oox/source/shape/ShapeDrawingFragmentHandler.cxx -oox/source/shape/ShapeDrawingFragmentHandler.hxx oox/source/shape/ShapeFilterBase.cxx oox/source/token/relationship.cxx oox/source/token/tokenmap.cxx