From aee29ee1ec19f16f2d5bdaa2f809fb6532d36951 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Thu, 7 Apr 2016 16:47:23 +0200 Subject: tdf#99140 DOCX import: fix table at the bottom of the page to span over ... ... multiple pages. In short, one more blacklist entry when conversion should not be performed. Conflicts: sw/qa/extras/ooxmlimport/ooxmlimport.cxx Also (because otherwise the first commit would introduce a regression): tdf#99140 DOCX import: fix table horizontal aligment to be 'from left' ... ... when it was 'manual'. Regression from commit c1e563f6efd09cd3463f1b92a3022ae288c92087 (fdo#76741 [DOCX] Table Alignment and width type, 2014-04-04), DOCX import code had to deal with two kinds of horizontal alignment when it came to floating tables: the alignment of the table itself, and the alignment of the float parameters. The problem is, in general it's wanted that the table is aligned according to the floating parameters, but in Writer the "from left" UI setting is described differently for tables and fly frames: tables use LEFT_AND_WIDTH for that, while fly frames use NONE. Fix the problem by touching the default only in case the floating parameters have something that's different from NONE. With this, the width of tables is no longer lost when they are described to be floating ones in the DOCX markup, but FloatingTableConversion() decides to ignore that. (cherry picked from commits d56deaeb2a1e8007e50fc2334f416fddd4e3cde3, c07f04ab422eadba0f2c3c128a0e3ff78e90cdf2, and fd61dee6457a44687f1142dd55bfee6b64fda2ef) Change-Id: I764f02cc58ae1b7af802b81e570e4feaf73ee2c1 Reviewed-on: https://gerrit.libreoffice.org/23987 Tested-by: Jenkins Reviewed-by: Andras Timar (cherry picked from commit 52f6fb0f4e91ebcd5115e29d25407eeed82992d5) --- sw/qa/extras/ooxmlimport/data/tdf99140.docx | Bin 0 -> 13349 bytes sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 15 ++++ .../source/dmapper/DomainMapperTableHandler.cxx | 13 ++-- writerfilter/source/dmapper/PropertyMap.cxx | 78 ++++++++++++++++----- writerfilter/source/dmapper/PropertyMap.hxx | 3 + 5 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 sw/qa/extras/ooxmlimport/data/tdf99140.docx diff --git a/sw/qa/extras/ooxmlimport/data/tdf99140.docx b/sw/qa/extras/ooxmlimport/data/tdf99140.docx new file mode 100644 index 000000000000..42fa73d2f8e0 Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/tdf99140.docx differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index a5b5cac303e7..39c469a86630 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -2917,6 +2917,21 @@ DECLARE_OOXMLIMPORT_TEST(testTdf98882, "tdf98882.docx") CPPUNIT_ASSERT_EQUAL(nFlyHeight, nContentHeight); } +DECLARE_OOXMLIMPORT_TEST(testTdf99140, "tdf99140.docx") +{ + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPageSupplier(xTextDocument, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + // This was 1: a multi-page floating table was imported as a TextFrame. + CPPUNIT_ASSERT_EQUAL(static_cast(0), xDrawPage->getCount()); + + uno::Reference xTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xTables(xTablesSupplier->getTextTables(), uno::UNO_QUERY); + uno::Reference xTableProperties(xTables->getByIndex(1), uno::UNO_QUERY); + // This was text::HoriOrientation::NONE, the second table was too wide due to this. + CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::LEFT_AND_WIDTH, getProperty(xTableProperties, "HoriOrient")); +} + #endif CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx index 5dcae2b81843..f1c393f4bbe4 100644 --- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -286,20 +286,21 @@ bool lcl_extractTableBorderProperty(PropertyMapPtr pTableProperties, const Prope return false; } -} - -bool lcl_extractHoriOrient(std::vector& rFrameProperties, sal_Int32& nHoriOrient) +void lcl_extractHoriOrient(std::vector& rFrameProperties, sal_Int32& nHoriOrient) { // Shifts the frame left by the given value. for (size_t i = 0; i < rFrameProperties.size(); ++i) { if (rFrameProperties[i].Name == "HoriOrient") { - nHoriOrient = rFrameProperties[i].Value.get(); - return true; + sal_Int32 nValue = rFrameProperties[i].Value.get(); + if (nValue != text::HoriOrientation::NONE) + nHoriOrient = nValue; + return; } } - return false; +} + } void lcl_DecrementHoriOrientPosition(std::vector& rFrameProperties, sal_Int32 nAmount) diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index ad06b9eee043..d2e1b41801e8 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -1021,34 +1023,72 @@ void SectionPropertyMap::HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl) PrepareHeaderFooterProperties( false ); } +bool SectionPropertyMap::FloatingTableConversion(FloatingTableInfo& rInfo) +{ + // Note that this is just a list of heuristics till sw core can have a + // table that is floating and can span over multiple pages at the same + // time. + + sal_Int32 nPageWidth = GetPageWidth(); + sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin(); + // Count the layout width of the table. + sal_Int32 nTableWidth = rInfo.m_nTableWidth; + sal_Int32 nLeftMargin = 0; + if (rInfo.getPropertyValue("LeftMargin") >>= nLeftMargin) + nTableWidth += nLeftMargin; + sal_Int32 nRightMargin = 0; + if (rInfo.getPropertyValue("RightMargin") >>= nRightMargin) + nTableWidth += nRightMargin; + + sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue("HoriOrientRelation").get(); + sal_Int16 nVertOrientRelation = rInfo.getPropertyValue("VertOrientRelation").get(); + if (nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME) + { + sal_Int16 nHoriOrient = rInfo.getPropertyValue("HoriOrient").get(); + sal_Int16 nVertOrient = rInfo.getPropertyValue("VertOrient").get(); + if (nHoriOrient == text::HoriOrientation::NONE && nVertOrient == text::VertOrientation::NONE) + { + // Anchor position is relative to the page horizontally and vertically as well and is an absolute position. + // The more close we are to the left edge, the less likely there will be any wrapping. + // The more close we are to the bottom, the more likely the table will span over to the next page + // So if we're in the bottom left quarter, don't do any conversion. + sal_Int32 nHoriOrientPosition = rInfo.getPropertyValue("HoriOrientPosition").get(); + sal_Int32 nVertOrientPosition = rInfo.getPropertyValue("VertOrientPosition").get(); + sal_Int32 nPageHeight = getProperty(PROP_HEIGHT)->second.get(); + if (nHoriOrientPosition < (nPageWidth / 2) && nVertOrientPosition > (nPageHeight / 2)) + return false; + } + } + + // If the table is wider than the text area, then don't create a fly + // for the table: no wrapping will be performed anyway, but multi-page + // tables will be broken. + if (nTableWidth < nTextAreaWidth) + return true; + + // If the position is relative to the edge of the page, then we always + // create the fly. + if (rInfo.getPropertyValue("HoriOrientRelation") == text::RelOrientation::PAGE_FRAME) + return true; + + // If there are columns, always create the fly, otherwise the columns would + // restrict geometry of the table. + if (ColumnCount() + 1 >= 2) + return true; + + return false; +} + void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) { // Text area width is known at the end of a section: decide if tables should be converted or not. std::vector& rPendingFloatingTables = rDM_Impl.m_aPendingFloatingTables; - sal_Int32 nTextAreaWidth = GetPageWidth() - GetLeftMargin() - GetRightMargin(); uno::Reference xBodyText( rDM_Impl.GetBodyText(), uno::UNO_QUERY ); for (size_t i = 0; i < rPendingFloatingTables.size(); ++i) { FloatingTableInfo& rInfo = rPendingFloatingTables[i]; - // Count the layout width of the table. - sal_Int32 nTableWidth = rInfo.m_nTableWidth; - sal_Int32 nLeftMargin = 0; - if (rInfo.getPropertyValue("LeftMargin") >>= nLeftMargin) - nTableWidth += nLeftMargin; - sal_Int32 nRightMargin = 0; - if (rInfo.getPropertyValue("RightMargin") >>= nRightMargin) - nTableWidth += nRightMargin; - - // If the table is wider than the text area, then don't create a fly - // for the table: no wrapping will be performed anyway, but multi-page - // tables will be broken. - // If the position is relative to the edge of the page, then we always - // create the fly. - // If there are columns, always create the fly, otherwise the columns would - // restrict geometry of the table. - if ( ( rInfo.getPropertyValue("HoriOrientRelation") == text::RelOrientation::PAGE_FRAME ) || - nTableWidth < nTextAreaWidth || ColumnCount() + 1 >= 2 ) + if (FloatingTableConversion(rInfo)) xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd, rInfo.m_aFrameProperties); } rPendingFloatingTables.clear(); diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx index 64cda4d184b2..1be5794b039b 100644 --- a/writerfilter/source/dmapper/PropertyMap.hxx +++ b/writerfilter/source/dmapper/PropertyMap.hxx @@ -56,6 +56,7 @@ namespace com{namespace sun{namespace star{ namespace writerfilter { namespace dmapper{ class DomainMapper_Impl; +struct FloatingTableInfo; enum BorderPosition { @@ -256,6 +257,8 @@ class SectionPropertyMap : public PropertyMap sal_Int32 nDistance, sal_Int32 nOffsetFrom, sal_uInt32 nLineWidth); + /// Determintes if conversion of a given floating table is wanted or not. + bool FloatingTableConversion(FloatingTableInfo& rInfo); public: explicit SectionPropertyMap(bool bIsFirstSection); -- cgit v1.2.3