sc/inc/dpcache.hxx | 1 sc/inc/dpsave.hxx | 2 sc/qa/unit/data/ods/caseinsensitive-duplicate-fields.ods |binary sc/qa/unit/data/ods/tdf123421_1datafield.ods |binary sc/qa/unit/data/ods/tdf123421_2datafields.ods |binary sc/qa/unit/pivottable_filters_test.cxx | 80 +++++ sc/source/core/data/dpcache.cxx | 97 ++---- sc/source/filter/excel/xepivotxml.cxx | 11 sc/uiconfig/scalc/ui/sheetprintpage.ui | 4 sfx2/source/dialog/mgetempl.cxx | 4 shell/source/backends/desktopbe/desktopbackend.cxx | 21 - solenv/flatpak-manifest.in | 12 sw/inc/ndtxt.hxx | 3 sw/qa/extras/ooxmlimport/data/tdf124670.docx |binary sw/qa/extras/ooxmlimport/ooxmlimport2.cxx | 10 sw/qa/extras/rtfexport/data/para-style-bottom-margin-2.rtf | 12 sw/qa/extras/rtfexport/rtfexport2.cxx | 27 + sw/qa/extras/rtfimport/data/para-style-bottom-margin.rtf | 14 sw/qa/extras/rtfimport/rtfimport.cxx | 31 ++ sw/qa/extras/uiwriter/data2/floating-table-position.docx |binary sw/qa/extras/uiwriter/uiwriter2.cxx | 92 ++++++ sw/source/core/crsr/crstrvl.cxx | 2 sw/source/core/doc/DocumentListItemsManager.cxx | 2 sw/source/core/fields/reffld.cxx | 2 sw/source/core/text/txtfrm.cxx | 2 sw/source/core/tox/txmsrt.cxx | 10 sw/source/core/undo/undel.cxx | 6 sw/source/core/undo/undobj.cxx | 18 - sw/source/filter/ww8/docxattributeoutput.cxx | 197 ++++++++----- sw/source/uibase/docvw/edtwin.cxx | 2 vcl/inc/printerinfomanager.hxx | 2 vcl/inc/qt5/Qt5FilePicker.hxx | 4 vcl/inc/unx/gtk/gtkgdi.hxx | 2 vcl/qt5/Qt5FilePicker.cxx | 41 ++ vcl/uiconfig/ui/cupspassworddialog.ui | 43 ++ vcl/unx/generic/printer/cupsmgr.cxx | 188 ++++++++---- vcl/unx/gtk/salnativewidgets-gtk.cxx | 28 + writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 31 -- writerfilter/source/ooxml/OOXMLFastContextHandler.hxx | 15 writerfilter/source/rtftok/rtfdocumentimpl.cxx | 63 +++- writerfilter/source/rtftok/rtfdocumentimpl.hxx | 2 writerfilter/source/rtftok/rtfsprm.cxx | 11 writerfilter/source/rtftok/rtfsprm.hxx | 4 43 files changed, 810 insertions(+), 286 deletions(-)
New commits: commit 1149d20ce9f8682b58f98d3fa3bf289fc5974087 Author: Michael Stahl <[email protected]> AuthorDate: Mon Apr 15 18:18:27 2019 +0200 Commit: Thorsten Behrens <[email protected]> CommitDate: Wed Apr 17 00:54:16 2019 +0200 tdf#124722 sw_redlinehide: don't set negative SwTextFrame offsets nLen may be larger than the master SwTextFrame, but its follow can't have negative offset. (regression from 0acde7514e666fc04805fd36503bd174162336ca) Change-Id: I6177c748480cdf61e8f15a7032ba52d3ae2ea52c Reviewed-on: https://gerrit.libreoffice.org/70816 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> (cherry picked from commit 2ea6f385d36966de8e30b9a537ac2875075ca9eb) Reviewed-on: https://gerrit.libreoffice.org/70821 Reviewed-by: Thorsten Behrens <[email protected]> diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 7d4e077d58c2..99981405d297 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1796,7 +1796,7 @@ static void lcl_ModifyOfst(SwTextFrame & rFrame, assert(nLen != TextFrameIndex(COMPLETE_STRING)); if (rFrame.IsFollow() && nPos < rFrame.GetOfst()) { - rFrame.ManipOfst( op(rFrame.GetOfst(), nLen) ); + rFrame.ManipOfst( std::max(TextFrameIndex(0), op(rFrame.GetOfst(), nLen)) ); } } commit 51fb5ce0774c463caad7bcf9a6851161a56d60f7 Author: Michael Stahl <[email protected]> AuthorDate: Mon Apr 15 17:11:51 2019 +0200 Commit: Thorsten Behrens <[email protected]> CommitDate: Wed Apr 17 00:54:05 2019 +0200 tdf#123855 sw_redlinehide: fix GetExpandText() not expanding footnotes ... due to change of default argument; the XHTML export is calling it from SwXTextPortion::getString(). This is complicated a bit by a bunch of changes to GetExpandText() callers. (regression from bf488abbf46da51d17c3ad7ccf9e39005a55c2d7) Change-Id: I0b1e10e17c8f3824d6fa1f21fc74cc59b310474f Reviewed-on: https://gerrit.libreoffice.org/70791 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> (cherry picked from commit f32ddd38ef777598901981491ad57bd37efe69e8) Reviewed-on: https://gerrit.libreoffice.org/70809 Reviewed-by: Thorsten Behrens <[email protected]> diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 4c0e6468fb9b..442aecb2b024 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -28,6 +28,7 @@ #include "ndhints.hxx" #include "SwNumberTreeTypes.hxx" #include "IDocumentContentOperations.hxx" +#include "modeltoviewhelper.hxx" #include <sfx2/Metadatable.hxx> @@ -680,7 +681,7 @@ public: const bool bWithNum = false, const bool bAddSpaceAfterListLabelStr = false, const bool bWithSpacesForLevel = false, - const ExpandMode eAdditionalMode = ExpandMode(0)) const; + const ExpandMode eAdditionalMode = ExpandMode::ExpandFootnote) const; bool CopyExpandText( SwTextNode& rDestNd, const SwIndex* pDestIdx, sal_Int32 nIdx, sal_Int32 nLen, SwRootFrame const* pLayout, diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index 42436696840b..3a46219ec7fe 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -1296,7 +1296,7 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt, if( pONd ) { rContentAtPos.eContentAtPos = IsAttrAtPos::Outline; - rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pONd, true, false, ExpandMode(0)); + rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pONd, true, false, ExpandMode::ExpandFootnote); bRet = true; } } diff --git a/sw/source/core/doc/DocumentListItemsManager.cxx b/sw/source/core/doc/DocumentListItemsManager.cxx index 7f69c7210942..d48473003660 100644 --- a/sw/source/core/doc/DocumentListItemsManager.cxx +++ b/sw/source/core/doc/DocumentListItemsManager.cxx @@ -73,7 +73,7 @@ OUString DocumentListItemsManager::getListItemText(const SwNodeNum& rNodeNum, { SwTextNode const*const pNode(rNodeNum.GetTextNode()); assert(pNode); - return sw::GetExpandTextMerged(&rLayout, *pNode, true, true, ExpandMode(0)); + return sw::GetExpandTextMerged(&rLayout, *pNode, true, true, ExpandMode::ExpandFootnote); } bool DocumentListItemsManager::isNumberedInLayout( diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx index c0ce2d7894fc..ed8e907a95b9 100644 --- a/sw/source/core/fields/reffld.cxx +++ b/sw/source/core/fields/reffld.cxx @@ -614,7 +614,7 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) if( nStart != nEnd ) // a section? { - m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false, false); + m_sText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false, false, ExpandMode(0)); if (m_nSubType == REF_OUTLINE || (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == GetFormat())) { diff --git a/sw/source/core/tox/txmsrt.cxx b/sw/source/core/tox/txmsrt.cxx index be7fc9323faa..3cbb6549cd6c 100644 --- a/sw/source/core/tox/txmsrt.cxx +++ b/sw/source/core/tox/txmsrt.cxx @@ -388,9 +388,10 @@ void SwTOXIndex::FillText( SwTextNode& rNd, const SwIndex& rInsPos, sal_uInt16, pTextMark->GetStart(), *pEnd - pTextMark->GetStart(), false, false, false, - pLayout && pLayout->IsHideRedlines() + ExpandMode::ExpandFootnote + | (pLayout && pLayout->IsHideRedlines() ? ExpandMode::HideDeletions - : ExpandMode(0)); + : ExpandMode(0))); if(SwTOIOptions::InitialCaps & nOpt && pTOXIntl && !aRet.sText.isEmpty()) { aRet.sText = pTOXIntl->ToUpper( aRet.sText, 0 ) + aRet.sText.copy(1); @@ -472,9 +473,10 @@ TextAndReading SwTOXContent::GetText_Impl(SwRootFrame const*const pLayout) const pTextMark->GetStart(), *pEnd - pTextMark->GetStart(), false, false, false, - pLayout && pLayout->IsHideRedlines() + ExpandMode::ExpandFootnote + | (pLayout && pLayout->IsHideRedlines() ? ExpandMode::HideDeletions - : ExpandMode(0)), + : ExpandMode(0))), pTextMark->GetTOXMark().GetTextReading()); } commit eeb9e6bfdb6f8d4e3edbd142c8ef129421d4b93f Author: Miklos Vajna <[email protected]> AuthorDate: Fri Apr 12 15:59:38 2019 +0200 Commit: Luboš Luňák <[email protected]> CommitDate: Tue Apr 16 13:41:08 2019 +0200 tdf#97822 vcl opengl gtk2: fix missing list node widget OpenGL just sets GtkSalGraphics::bNeedPixmapPaint to true, and the problem is specific to that flag (can be also enabled via SAL_GTK_USE_PIXMAPPAINT=1). Most other widgets are painted correctly in the GL case as they pass around a drawable explicitly; do the same for ControlType::ListNode as well in the GL case. The non-GL case still needs to go via the pixmap render macros to have correct position, leave that unchanged. (cherry picked from commit fb9c7e31f888a301fecb5257635e12ce7b907d14) Change-Id: Ia82a6772e357b434d706e58664be3a8427e91669 Reviewed-on: https://gerrit.libreoffice.org/70762 Tested-by: Jenkins Reviewed-by: Luboš Luňák <[email protected]> diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx index ee42a2baf433..bc49983d3848 100644 --- a/vcl/inc/unx/gtk/gtkgdi.hxx +++ b/vcl/inc/unx/gtk/gtkgdi.hxx @@ -384,7 +384,7 @@ protected: bool NWPaintGTKSlider( ControlPart nPart, const tools::Rectangle& rControlRectangle, ControlState nState, const ImplControlValue& aValue ); - bool NWPaintGTKListNode( + bool NWPaintGTKListNode( GdkDrawable* gdkDrawable, const tools::Rectangle& rControlRectangle, ControlState nState, const ImplControlValue& aValue ); }; diff --git a/vcl/unx/gtk/salnativewidgets-gtk.cxx b/vcl/unx/gtk/salnativewidgets-gtk.cxx index c95016c712d1..7868f835187e 100644 --- a/vcl/unx/gtk/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/salnativewidgets-gtk.cxx @@ -1018,7 +1018,7 @@ bool GtkSalGraphics::DoDrawNativeControl( } else if( (nType == ControlType::ListNode) && (nPart == ControlPart::Entire) ) { - return NWPaintGTKListNode( aCtrlRect, nState, aValue ); + return NWPaintGTKListNode( pDrawable, aCtrlRect, nState, aValue ); } else if( (nType == ControlType::ListNet) && (nPart == ControlPart::Entire) ) { @@ -3345,7 +3345,18 @@ bool GtkSalGraphics::NWPaintGTKTooltip( return true; } +namespace +{ +void NWPaintGTKListNodeReal(SalX11Screen nXScreen, GdkDrawable* gdkDrawable, GtkStateType stateType, + gint w, int h, GtkExpanderStyle eStyle) +{ + gtk_paint_expander(gWidgetData[nXScreen].gTreeView->style, gdkDrawable, stateType, nullptr, + gWidgetData[nXScreen].gTreeView, "treeview", w / 2, h / 2, eStyle); +} +} + bool GtkSalGraphics::NWPaintGTKListNode( + GdkDrawable* gdkDrawable, const tools::Rectangle& rControlRectangle, ControlState nState, const ImplControlValue& rValue ) { @@ -3375,16 +3386,15 @@ bool GtkSalGraphics::NWPaintGTKListNode( break; } + if (GtkSalGraphics::bNeedPixmapPaint) + { + NWPaintGTKListNodeReal(m_nXScreen, gdkDrawable, stateType, w, h, eStyle); + return true; + } + BEGIN_PIXMAP_RENDER( aRect, pixDrawable ) { - gtk_paint_expander( gWidgetData[m_nXScreen].gTreeView->style, - pixDrawable, - stateType, - nullptr, - gWidgetData[m_nXScreen].gTreeView, - "treeview", - w/2, h/2, - eStyle ); + NWPaintGTKListNodeReal(m_nXScreen, pixDrawable, stateType, w, h, eStyle); } END_PIXMAP_RENDER( aRect ) commit 9da596116d5506e583410db033798c39fa43232a Author: Dennis Francis <[email protected]> AuthorDate: Wed Apr 10 04:30:25 2019 +0530 Commit: Dennis Francis <[email protected]> CommitDate: Tue Apr 16 11:55:09 2019 +0200 tdf#124676 : use case-insensitive normalization of... ScDPCache field labels, else on export to xlsx, Excel will fail to load the pivot table due to case-insensitive duplicate field labels in the pivotCacheDefinition1.xml. This could be done just for xlsx export filter, but we do normalization in dpcache.cxx anyway and it would not hurt if we do a case-insensitive normalization here. The private member ScDPCache::AddLabel had code duplication and more importantly it is called in loop for every label in the database so results in O(n^2) time complexity where n is the number of labels, so removed it to reuse normalizeLabels() at the only call-site. Also added a unit test that checks case-insensitive normalization. Change-Id: Id563dee232a98a2aea9f4fc29254f6942e1c5ba7 Reviewed-on: https://gerrit.libreoffice.org/70498 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Jenkins Reviewed-by: Dennis Francis <[email protected]> (cherry picked from commit 238cadd315901cbacfd9304bb1205e9f53f13eae) Reviewed-on: https://gerrit.libreoffice.org/70703 diff --git a/sc/inc/dpcache.hxx b/sc/inc/dpcache.hxx index 1c88c14fff7e..1d1559755369 100644 --- a/sc/inc/dpcache.hxx +++ b/sc/inc/dpcache.hxx @@ -209,7 +209,6 @@ public: private: void PostInit(); void Clear(); - void AddLabel(const OUString& rLabel); const GroupItems* GetGroupItems(long nDim) const; }; diff --git a/sc/qa/unit/data/ods/caseinsensitive-duplicate-fields.ods b/sc/qa/unit/data/ods/caseinsensitive-duplicate-fields.ods new file mode 100644 index 000000000000..795b74ca3c00 Binary files /dev/null and b/sc/qa/unit/data/ods/caseinsensitive-duplicate-fields.ods differ diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx index 7550746c3e9b..c2546bc29cb7 100644 --- a/sc/qa/unit/pivottable_filters_test.cxx +++ b/sc/qa/unit/pivottable_filters_test.cxx @@ -85,6 +85,7 @@ public: void testPivotTableOutlineModeXLSX(); void testPivotTableDuplicatedMemberFilterXLSX(); void testPivotTableTabularModeXLSX(); + void testPivotTableDuplicateFields(); void testTdf112106(); void testTdf123923(); @@ -126,6 +127,7 @@ public: CPPUNIT_TEST(testPivotTableOutlineModeXLSX); CPPUNIT_TEST(testPivotTableDuplicatedMemberFilterXLSX); CPPUNIT_TEST(testPivotTableTabularModeXLSX); + CPPUNIT_TEST(testPivotTableDuplicateFields); CPPUNIT_TEST(testTdf112106); CPPUNIT_TEST(testTdf123923); @@ -2344,6 +2346,28 @@ void ScPivotTableFiltersTest::testPivotTableTabularModeXLSX() assertXPath(pTable, "/x:pivotTableDefinition/x:pivotFields/x:pivotField[1]", "outline", "0"); } +void ScPivotTableFiltersTest::testPivotTableDuplicateFields() +{ + ScDocShellRef xShell = loadDoc("caseinsensitive-duplicate-fields.", FORMAT_ODS); + CPPUNIT_ASSERT(xShell.is()); + + std::shared_ptr<utl::TempFile> pXPathFile + = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX); + xmlDocPtr pCacheDef + = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotCache/pivotCacheDefinition1.xml"); + CPPUNIT_ASSERT(pCacheDef); + + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields", "count", "6"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[1]", "name", "ID"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[2]", "name", "Name"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[3]", "name", "Score"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[4]", "name", "Method"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[5]", "name", "method2"); + assertXPath(pCacheDef, "/x:pivotCacheDefinition/x:cacheFields/x:cacheField[6]", "name", "Method3"); + + xShell->DoClose(); +} + void ScPivotTableFiltersTest::testTdf112106() { ScDocShellRef xDocSh = loadDoc("tdf112106.", FORMAT_XLSX); diff --git a/sc/source/core/data/dpcache.cxx b/sc/source/core/data/dpcache.cxx index 7820e9090571..fce310bd1ee6 100644 --- a/sc/source/core/data/dpcache.cxx +++ b/sc/source/core/data/dpcache.cxx @@ -33,6 +33,7 @@ #include <cellvalue.hxx> #include <rtl/math.hxx> +#include <unotools/charclass.hxx> #include <unotools/textsearch.hxx> #include <unotools/localedatawrapper.hxx> #include <unotools/collatorwrapper.hxx> @@ -337,43 +338,51 @@ struct InitDocData typedef std::unordered_set<OUString> LabelSet; -class InsertLabel +void normalizeAddLabel(const OUString& rLabel, std::vector<OUString>& rLabels, LabelSet& rExistingNames) { - LabelSet& mrNames; -public: - explicit InsertLabel(LabelSet& rNames) : mrNames(rNames) {} - void operator() (const OUString& r) + const OUString aLabelLower = ScGlobal::pCharClass->lowercase(rLabel); + sal_Int32 nSuffix = 1; + OUString aNewLabel = rLabel; + OUString aNewLabelLower = aLabelLower; + while (true) { - mrNames.insert(r); + if (!rExistingNames.count(aNewLabelLower)) + { + // this is a unique label. + rLabels.push_back(aNewLabel); + rExistingNames.insert(aNewLabelLower); + break; + } + + // This name already exists. + aNewLabel = rLabel + OUString::number(++nSuffix); + aNewLabelLower = aLabelLower + OUString::number(nSuffix); } -}; +} -std::vector<OUString> normalizeLabels( const std::vector<InitColumnData>& rColData ) +std::vector<OUString> normalizeLabels(const std::vector<InitColumnData>& rColData) { std::vector<OUString> aLabels(1u, ScResId(STR_PIVOT_DATA)); LabelSet aExistingNames; for (const InitColumnData& rCol : rColData) - { - const OUString& rLabel = rCol.maLabel; - sal_Int32 nSuffix = 1; - OUString aNewLabel = rLabel; - while (true) - { - if (!aExistingNames.count(aNewLabel)) - { - // this is a unique label. - aLabels.push_back(aNewLabel); - aExistingNames.insert(aNewLabel); - break; - } + normalizeAddLabel(rCol.maLabel, aLabels, aExistingNames); - // This name already exists. - OUStringBuffer aBuf(rLabel); - aBuf.append(++nSuffix); - aNewLabel = aBuf.makeStringAndClear(); - } + return aLabels; +} + +std::vector<OUString> normalizeLabels(const ScDPCache::DBConnector& rDB, const sal_Int32 nLabelCount) +{ + std::vector<OUString> aLabels(nLabelCount+1); + aLabels.push_back(ScResId(STR_PIVOT_DATA)); + + LabelSet aExistingNames; + + for (sal_Int32 nCol = 0; nCol < nLabelCount; ++nCol) + { + OUString aColTitle = rDB.getColumnLabel(nCol); + normalizeAddLabel(aColTitle, aLabels, aExistingNames); } return aLabels; @@ -632,14 +641,7 @@ bool ScDPCache::InitFromDataBase(DBConnector& rDB) maFields.push_back(o3tl::make_unique<Field>()); // Get column titles and types. - maLabelNames.clear(); - maLabelNames.reserve(mnColumnCount+1); - - for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol) - { - OUString aColTitle = rDB.getColumnLabel(nCol); - AddLabel(aColTitle); - } + maLabelNames = normalizeLabels(rDB, mnColumnCount); std::vector<Bucket> aBuckets; ScDPItemData aData; @@ -959,33 +961,6 @@ void ScDPCache::Clear() maStringPools.clear(); } -void ScDPCache::AddLabel(const OUString& rLabel) -{ - - if ( maLabelNames.empty() ) - maLabelNames.push_back(ScResId(STR_PIVOT_DATA)); - - //reset name if needed - LabelSet aExistingNames; - std::for_each(maLabelNames.begin(), maLabelNames.end(), InsertLabel(aExistingNames)); - sal_Int32 nSuffix = 1; - OUString aNewName = rLabel; - while (true) - { - if (!aExistingNames.count(aNewName)) - { - // unique name found! - maLabelNames.push_back(aNewName); - return; - } - - // Name already exists. - OUStringBuffer aBuf(rLabel); - aBuf.append(++nSuffix); - aNewName = aBuf.makeStringAndClear(); - } -} - SCROW ScDPCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, bool bRepeatIfEmpty) const { OSL_ENSURE(nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId "); commit 1e797b00580f341af1fffdbd66511d7a55261f9e Author: Dennis Francis <[email protected]> AuthorDate: Fri Apr 5 22:04:13 2019 +0530 Commit: Dennis Francis <[email protected]> CommitDate: Tue Apr 16 11:54:45 2019 +0200 tdf#123421 : xlsx export : Don't write data field entry... under colFields tag if there is only one data-field. <colFields count=[*]> <field x="-2"/> <--- -2 indicates data field. </colFields> Excel 2013/2016 seems to crash at the presence of '<field x="-2"/>' in colFields when there is only one data-field. Additionally, call GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE) on all ScDPObject's in non-const mode, so that the internal pOuput member of ScDPObject is populated. Otherwise the const GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE) call always return an invalid range. This also adds 2 unit tests :- 1. To check the presence of <field x="-2"/> in colFields tag if there are more than one data-fields. 2. To ensure the absence of <field x="-2"/> in colFields tag if there is only one data-field. Change-Id: I8f470bd1ab883f73586f04a3fcc30e3fbf948c4a Reviewed-on: https://gerrit.libreoffice.org/70316 Tested-by: Jenkins Reviewed-by: Andras Timar <[email protected]> (cherry picked from commit 97af58093978d8e6b9d90eedcc59141304e7200e) Reviewed-on: https://gerrit.libreoffice.org/70704 Reviewed-by: Dennis Francis <[email protected]> diff --git a/sc/inc/dpsave.hxx b/sc/inc/dpsave.hxx index 7558a6b2588d..49cb240ffd24 100644 --- a/sc/inc/dpsave.hxx +++ b/sc/inc/dpsave.hxx @@ -315,7 +315,7 @@ public: ScDPSaveDimension* GetInnermostDimension(css::sheet::DataPilotFieldOrientation nOrientation); ScDPSaveDimension* GetFirstDimension(css::sheet::DataPilotFieldOrientation eOrientation); - long GetDataDimensionCount() const; + SC_DLLPUBLIC long GetDataDimensionCount() const; void SetPosition( ScDPSaveDimension* pDim, long nNew ); SC_DLLPUBLIC void SetColumnGrand( bool bSet ); diff --git a/sc/qa/unit/data/ods/tdf123421_1datafield.ods b/sc/qa/unit/data/ods/tdf123421_1datafield.ods new file mode 100644 index 000000000000..985d6c0c44b6 Binary files /dev/null and b/sc/qa/unit/data/ods/tdf123421_1datafield.ods differ diff --git a/sc/qa/unit/data/ods/tdf123421_2datafields.ods b/sc/qa/unit/data/ods/tdf123421_2datafields.ods new file mode 100644 index 000000000000..c5d8a09647b0 Binary files /dev/null and b/sc/qa/unit/data/ods/tdf123421_2datafields.ods differ diff --git a/sc/qa/unit/pivottable_filters_test.cxx b/sc/qa/unit/pivottable_filters_test.cxx index e68e34904b3d..7550746c3e9b 100644 --- a/sc/qa/unit/pivottable_filters_test.cxx +++ b/sc/qa/unit/pivottable_filters_test.cxx @@ -61,6 +61,8 @@ public: // Export void testPivotTableExportXLSX(); + void testPivotTableExportXLSXSingleDataField(); + void testPivotTableExportXLSXMultipleDataFields(); void testPivotCacheExportXLSX(); void testPivotTableXLSX(); void testPivotTableTwoDataFieldsXLSX(); @@ -100,6 +102,8 @@ public: CPPUNIT_TEST(testTdf112501); CPPUNIT_TEST(testPivotTableExportXLSX); + CPPUNIT_TEST(testPivotTableExportXLSXSingleDataField); + CPPUNIT_TEST(testPivotTableExportXLSXMultipleDataFields); CPPUNIT_TEST(testPivotCacheExportXLSX); CPPUNIT_TEST(testPivotTableXLSX); CPPUNIT_TEST(testPivotTableTwoDataFieldsXLSX); @@ -755,6 +759,58 @@ void ScPivotTableFiltersTest::testPivotTableExportXLSX() "h", "1"); } +void ScPivotTableFiltersTest::testPivotTableExportXLSXSingleDataField() +{ + ScDocShellRef xShell = loadDoc("tdf123421_1datafield.", FORMAT_ODS); + CPPUNIT_ASSERT(xShell.is()); + + std::shared_ptr<utl::TempFile> pXPathFile + = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX); + xmlDocPtr pTable + = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml"); + CPPUNIT_ASSERT(pTable); + + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "ref", "A3:B6"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstHeaderRow", "1"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataRow", "1"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataCol", "1"); + assertXPath(pTable, "/x:pivotTableDefinition/x:dataFields", "count", "1"); + + // There should not be any colFields tag, before the fix there used to be a singleton with + // <field x="-2"/> as child node. + assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", 0); + + xShell->DoClose(); +} + +void ScPivotTableFiltersTest::testPivotTableExportXLSXMultipleDataFields() +{ + ScDocShellRef xShell = loadDoc("tdf123421_2datafields.", FORMAT_ODS); + CPPUNIT_ASSERT(xShell.is()); + + std::shared_ptr<utl::TempFile> pXPathFile + = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX); + xmlDocPtr pTable + = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/pivotTables/pivotTable1.xml"); + CPPUNIT_ASSERT(pTable); + + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "ref", "A1:C6"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstHeaderRow", "1"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataRow", "2"); + assertXPath(pTable, "/x:pivotTableDefinition/x:location", "firstDataCol", "1"); + + assertXPath(pTable, "/x:pivotTableDefinition/x:dataFields", "count", "2"); + + // There should be a single colFields tag with sole child node + // <field x="-2"/>. + assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", 1); + assertXPath(pTable, "/x:pivotTableDefinition/x:colFields", "count", "1"); + assertXPath(pTable, "/x:pivotTableDefinition/x:colFields/x:field", 1); + assertXPath(pTable, "/x:pivotTableDefinition/x:colFields/x:field", "x", "-2"); + + xShell->DoClose(); +} + void ScPivotTableFiltersTest::testPivotCacheExportXLSX() { // tdf#89139 FILESAVE xlsx pivot table corrupted after save with LO and re-open with MS Office diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index 271b4cb8fdf4..611078fa4ec1 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -432,6 +432,7 @@ void XclExpXmlPivotTableManager::Initialize() { ScDPObject& rDPObj = (*pDPColl)[i]; rDPObj.SyncAllDimensionMembers(); + (void)rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE); } // Go through the caches first. @@ -615,6 +616,7 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP std::vector<long> aPageFields; std::vector<DataField> aDataFields; + long nDataDimCount = rSaveData.GetDataDimensionCount(); // Use dimensions in the save data to get their correct ordering. // Dimension order here is significant as they specify the order of // appearance in each axis. @@ -646,6 +648,8 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP switch (eOrient) { case sheet::DataPilotFieldOrientation_COLUMN: + if (nPos == -2 && nDataDimCount <= 1) + break; aColFields.push_back(nPos); break; case sheet::DataPilotFieldOrientation_ROW: @@ -693,15 +697,16 @@ void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDP sal_Int32 nFirstDataRow = 2; sal_Int32 nFirstDataCol = 1; ScRange aResRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT); + + if (!aOutRange.IsValid()) + aOutRange = rDPObj.GetOutRange(); + if (aOutRange.IsValid() && aResRange.IsValid()) { nFirstDataRow = aResRange.aStart.Row() - aOutRange.aStart.Row(); nFirstDataCol = aResRange.aStart.Col() - aOutRange.aStart.Col(); } - if (!aOutRange.IsValid()) - aOutRange = rDPObj.GetOutRange(); - pPivotStrm->write("<")->writeId(XML_location); rStrm.WriteAttributes(XML_ref, XclXmlUtils::ToOString(aOutRange), commit 0eeb3ef5816084afb96f5803375e6a3a1dd89400 Author: Michael Weghorn <[email protected]> AuthorDate: Tue Feb 5 10:59:15 2019 +0100 Commit: Katarina Behrens <[email protected]> CommitDate: Tue Apr 16 10:47:00 2019 +0200 tdf#123058 qt5 fpicker: Honor autoextension setting Store the file extension associated with the named filters in a map, and use that information to set the default file extension in QFileDialog accordingly if the corresponding checkbox in the dialog is enabled. Change-Id: I66f4f35da5d4378ac6337429e39260a4ed710a24 Reviewed-on: https://gerrit.libreoffice.org/67392 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> (cherry picked from commit 9a6818bd73198e6dba3414579a35db6e87dbeb66) Reviewed-on: https://gerrit.libreoffice.org/70763 Reviewed-by: Katarina Behrens <[email protected]> diff --git a/vcl/inc/qt5/Qt5FilePicker.hxx b/vcl/inc/qt5/Qt5FilePicker.hxx index d4802795c588..dbe8020d30ca 100644 --- a/vcl/inc/qt5/Qt5FilePicker.hxx +++ b/vcl/inc/qt5/Qt5FilePicker.hxx @@ -63,6 +63,8 @@ protected: QStringList m_aNamedFilterList; ///< to keep the original sequence QHash<QString, QString> m_aTitleToFilterMap; + // to retrieve the filename extension for a given filter + QHash<QString, QString> m_aNamedFilterToExtensionMap; QString m_aCurrentFilter; QWidget* m_pExtraControls; ///< widget to contain extra custom controls @@ -262,6 +264,8 @@ private Q_SLOTS: void filterSelected(const QString&); // emit XFilePickerListener fileSelectionChanged event void currentChanged(const QString&); + // (un)set automatic file extension + void updateAutomaticFileExtension(); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FilePicker.cxx b/vcl/qt5/Qt5FilePicker.cxx index 7817f4de0488..6db64b3b0824 100644 --- a/vcl/qt5/Qt5FilePicker.cxx +++ b/vcl/qt5/Qt5FilePicker.cxx @@ -150,6 +150,10 @@ Qt5FilePicker::Qt5FilePicker(QFileDialog::FileMode eMode) SLOT(filterSelected(const QString&))); connect(m_pFileDialog.get(), SIGNAL(currentChanged(const QString&)), this, SLOT(currentChanged(const QString&))); + + // update automatic file extension when filter is changed + connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, + SLOT(updateAutomaticFileExtension())); } Qt5FilePicker::~Qt5FilePicker() {} @@ -212,6 +216,8 @@ sal_Int16 SAL_CALL Qt5FilePicker::execute() m_pFileDialog->setFocusProxy(pTransientParent); } + updateAutomaticFileExtension(); + int result = m_pFileDialog->exec(); if (QFileDialog::Rejected == result) return ExecutableDialogResults::CANCEL; @@ -319,6 +325,7 @@ void SAL_CALL Qt5FilePicker::appendFilter(const OUString& title, const OUString& m_aNamedFilterList << QStringLiteral("%1 (%2)").arg(n, f); m_aTitleToFilterMap[t] = m_aNamedFilterList.constLast(); + m_aNamedFilterToExtensionMap[m_aNamedFilterList.constLast()] = f; } void SAL_CALL Qt5FilePicker::setCurrentFilter(const OUString& title) @@ -562,6 +569,7 @@ void Qt5FilePicker::addCustomControl(sal_Int16 controlId) QWidget* widget = nullptr; QLabel* label = nullptr; const char* resId = nullptr; + QCheckBox* pCheckbox = nullptr; switch (controlId) { @@ -611,6 +619,12 @@ void Qt5FilePicker::addCustomControl(sal_Int16 controlId) switch (controlId) { case CHECKBOX_AUTOEXTENSION: + pCheckbox = new QCheckBox(getResString(resId), m_pExtraControls); + // to add/remove automatic file extension based on checkbox + connect(pCheckbox, SIGNAL(stateChanged(int)), this, + SLOT(updateAutomaticFileExtension())); + widget = pCheckbox; + break; case CHECKBOX_PASSWORD: case CHECKBOX_FILTEROPTIONS: case CHECKBOX_READONLY: @@ -796,6 +810,33 @@ uno::Sequence<OUString> SAL_CALL Qt5FilePicker::getSupportedServiceNames() return FilePicker_getSupportedServiceNames(); } +void Qt5FilePicker::updateAutomaticFileExtension() +{ + bool bSetAutoExtension + = getValue(CHECKBOX_AUTOEXTENSION, ControlActions::GET_SELECTED_ITEM).get<bool>(); + if (bSetAutoExtension) + { + QString sSuffix = m_aNamedFilterToExtensionMap.value(m_pFileDialog->selectedNameFilter()); + // string is "*.<SUFFIX>" if a specific filter was selected that has exactly one possible file extension + if (sSuffix.lastIndexOf("*.") == 0) + { + sSuffix = sSuffix.remove("*."); + m_pFileDialog->setDefaultSuffix(sSuffix); + } + else + { + // fall back to setting none otherwise + SAL_INFO( + "vcl.qt5", + "Unable to retrieve unambiguous file extension. Will not add any automatically."); + bSetAutoExtension = false; + } + } + + if (!bSetAutoExtension) + m_pFileDialog->setDefaultSuffix(""); +} + void Qt5FilePicker::filterSelected(const QString&) { FilePickerEvent aEvent; commit 7bba93a99ebb4250f884a68a50aa1912d96f4ba8 Author: Michael Stahl <[email protected]> AuthorDate: Fri Apr 12 18:10:49 2019 +0200 Commit: Thorsten Behrens <[email protected]> CommitDate: Tue Apr 16 00:37:19 2019 +0200 tdf#109376 sw: fix SwUndoDelete with end pos on SwTableNode crash Commit 6ff263b837831d46d0c215963b70543a9ea5bd2a added a check in SwUndoSaveContent::DelContentIndex() to avoid moving the anchor of a FLY_AT_PARA if its new position would be a table node, because SwFlyAtContentFrame::Modify() requires a SwTextNode to be the anchor. However, that doesn't actually avoid moving the anchor - later, SwNodes::RemoveNode() relocates the anchor to the next node regardless of type! It's probably better to just delete the fly in the situation when the end position is a SwTableNode, which fixes the reported crash. Unfortunately on Redo, the SwUndoDelete::UndoImpl() does not recreate the nodes correctly, hence the fly then is inserted on the wrong node, which later crashes again. The problem is that due to the table node, a dummy SwTextNode is inserted, which should be at the end of the range, but ends up at the start due to an erroneous ++aPos.nNode; - the result is that the fly is inserted on the dummy node and is immediately deleted again, triggering another assert. If there is a dummy node, it also doesn't make sense to call SplitNode(). Yet another problem is that in SwUndoDelete::UndoImpl(), the frames for the moved text nodes are not created, because the first node is skipped with the wrong assumption that it already has frames. Reportedly this started to crash with commit e07feb9457f2ffb373ae69b73dda290140e4005f, previously it was just wrong. Reviewed-on: https://gerrit.libreoffice.org/70683 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> (cherry picked from commit 80b73dcc06c671a49fbf238be58c1cd086c5c5f9) Change-Id: I5094638e34c6ed52c836e57691d377b8cd1608f9 Reviewed-on: https://gerrit.libreoffice.org/70764 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <[email protected]> diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index 2344aa743248..ba6caf3f8222 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -22,6 +22,8 @@ #include <wrtsh.hxx> #include <redline.hxx> #include <UndoManager.hxx> +#include <itabenum.hxx> +#include <fmtfsize.hxx> #include <fmtornt.hxx> namespace @@ -37,6 +39,7 @@ public: void testRedlineInHiddenSection(); void testTdf101534(); void testTdf54819(); + void testTdf109376(); void testTdf108687_tabstop(); void testTdf119571(); void testTdf119019(); @@ -52,6 +55,7 @@ public: CPPUNIT_TEST(testRedlineInHiddenSection); CPPUNIT_TEST(testTdf101534); CPPUNIT_TEST(testTdf54819); + CPPUNIT_TEST(testTdf109376); CPPUNIT_TEST(testTdf108687_tabstop); CPPUNIT_TEST(testTdf119571); CPPUNIT_TEST(testTdf119019); @@ -251,6 +255,53 @@ void SwUiWriterTest2::testTdf54819() getProperty<OUString>(getParagraph(1), "ParaStyleName")); } +void SwUiWriterTest2::testTdf109376() +{ + SwDoc* pDoc = createDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + CPPUNIT_ASSERT(pWrtShell); + // need 2 paragraphs to get to the bMoveNds case + pWrtShell->Insert("foo"); + pWrtShell->SplitNode(); + pWrtShell->Insert("bar"); + pWrtShell->SplitNode(); + pWrtShell->StartOfSection(false); + + // add AT_PARA fly at 1st to be deleted node + SwFormatAnchor anchor(RndStdIds::FLY_AT_PARA); + anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint()); + SfxItemSet flySet(pDoc->GetAttrPool(), + svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{}); + flySet.Put(anchor); + SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000); + flySet.Put(size); // set a size, else we get 1 char per line... + SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true); + CPPUNIT_ASSERT(pFly != nullptr); + + pWrtShell->SttEndDoc(false); + SwInsertTableOptions tableOpt(SwInsertTableFlags::DefaultBorder, 0); + const SwTable& rTable = pWrtShell->InsertTable(tableOpt, 1, 1); + + pWrtShell->StartOfSection(false); + SwPaM pam(*pWrtShell->GetCursor()->GetPoint()); + pam.SetMark(); + pam.GetPoint()->nNode = *rTable.GetTableNode(); + pam.GetPoint()->nContent.Assign(nullptr, 0); + pam.Exchange(); // same selection direction as in doc compare... + + // this used to assert/crash with m_pAnchoredFlys mismatch because the + // fly was not deleted but its anchor was moved to the SwTableNode + pDoc->getIDocumentContentOperations().DeleteRange(pam); + CPPUNIT_ASSERT_EQUAL(size_t(0), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM)); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + rUndoManager.Undo(); + CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM)); + rUndoManager.Redo(); + CPPUNIT_ASSERT_EQUAL(size_t(0), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM)); + rUndoManager.Undo(); + CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM)); +} + void SwUiWriterTest2::testTdf108687_tabstop() { SwDoc* pDoc = createDoc("tdf108687_tabstop.odt"); diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx index 8352db8aa2a7..16fe58d462a9 100644 --- a/sw/source/core/undo/undel.cxx +++ b/sw/source/core/undo/undel.cxx @@ -906,7 +906,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext) pTextNd->RestoreMetadata(m_pMetadataUndoEnd); } } - else if( m_aSttStr && bNodeMove ) + else if (m_aSttStr && bNodeMove && pInsNd == nullptr) { SwTextNode * pNd = aPos.nNode.GetNode().GetTextNode(); if( pNd ) @@ -1117,8 +1117,10 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext) { // tdf#121031 if the start node is a text node, it already has a frame; // if it's a table, it does not + // tdf#109376 exception: end on non-text-node -> start node was inserted SwNodeIndex const start(rDoc.GetNodes(), nSttNode + - ((m_bDelFullPara || !rDoc.GetNodes()[nSttNode]->IsTextNode()) ? 0 : 1)); + ((m_bDelFullPara || !rDoc.GetNodes()[nSttNode]->IsTextNode() || pInsNd) + ? 0 : 1)); // don't include end node in the range: it may have been merged already // by the start node, or it may be merged by one of the moved nodes, // but if it isn't merged, its current frame(s) should be good... diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx index 8f45e20e514d..63a8bd949bcc 100644 --- a/sw/source/core/undo/undobj.cxx +++ b/sw/source/core/undo/undobj.cxx @@ -985,17 +985,15 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark, // Moving the anchor? if( !( DelContentType::CheckNoCntnt & nDelContentType ) && - ( rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex() ) ) - { + (rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex()) // Do not try to move the anchor to a table! - if( rMark.nNode.GetNode().GetTextNode() ) - { - pHistory->Add( *pFormat ); - SwFormatAnchor aAnch( *pAnchor ); - SwPosition aPos( rMark.nNode ); - aAnch.SetAnchor( &aPos ); - pFormat->SetFormatAttr( aAnch ); - } + && rMark.nNode.GetNode().IsTextNode()) + { + pHistory->Add( *pFormat ); + SwFormatAnchor aAnch( *pAnchor ); + SwPosition aPos( rMark.nNode ); + aAnch.SetAnchor( &aPos ); + pFormat->SetFormatAttr( aAnch ); } else { commit e160a29333af39151bf4ea520e1cc9e184ac3a8f Author: Caolán McNamara <[email protected]> AuthorDate: Mon Apr 15 19:59:23 2019 +0100 Commit: Adolfo Jayme Barrientos <[email protected]> CommitDate: Tue Apr 16 00:27:45 2019 +0200 tdf#124730 an attempt to remove entry that isn't there Change-Id: If382f0419c8ea0a3b99c85942c05ee1e5a627e76 Reviewed-on: https://gerrit.libreoffice.org/70796 Tested-by: Jenkins Reviewed-by: Adolfo Jayme Barrientos <[email protected]> diff --git a/sfx2/source/dialog/mgetempl.cxx b/sfx2/source/dialog/mgetempl.cxx index 90a66282d5d3..deb5f01f136e 100644 --- a/sfx2/source/dialog/mgetempl.cxx +++ b/sfx2/source/dialog/mgetempl.cxx @@ -281,7 +281,9 @@ void SfxManageStyleSheetPage::UpdateName_Impl( weld::ComboBox* pBox, { // it is the current entry, which name was modified const bool bSelect = pBox->get_active_text() == aBuf; - pBox->remove_text(aBuf); + int nOldIndex = pBox->find_text(aBuf); + if (nOldIndex != -1) + pBox->remove(nOldIndex); pBox->append_text(rNew); if (bSelect) commit 977b362ec73cde1942f3052e5e2d0fa9882b062b Author: Caolán McNamara <[email protected]> AuthorDate: Fri Apr 12 15:59:02 2019 +0100 Commit: Michael Stahl <[email protected]> CommitDate: Mon Apr 15 11:37:31 2019 +0200 rhbz#1699347 __glibcxx_requires_subscript enabled in fedora release builds and so triggering a crash and exit on trying to get address of 0th element of a 0 len vector Change-Id: I205478b6c2878d3758d91812db46fe8ad58e37df Reviewed-on: https://gerrit.libreoffice.org/70673 Reviewed-by: Michael Stahl <[email protected]> Tested-by: Michael Stahl <[email protected]> diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 2e9f77b1a063..4ccbd77d9c1c 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -5870,7 +5870,7 @@ void QuickHelpData::Start( SwWrtShell& rSh, sal_uInt16 nWrdLen ) const ExtTextInputAttr nVal = ExtTextInputAttr::DottedUnderline | ExtTextInputAttr::Highlight; const std::vector<ExtTextInputAttr> aAttrs( nL, nVal ); - CommandExtTextInputData aCETID( sStr, &aAttrs[0], nL, + CommandExtTextInputData aCETID( sStr, aAttrs.data(), nL, 0, false ); //fdo#33092. If the current input language is the default commit 7b6c9c2f52ef80876d494ef966a3ee088c81bcd5 Author: Mike Kaganski <[email protected]> AuthorDate: Sun Apr 14 00:46:15 2019 +0300 Commit: Michael Stahl <[email protected]> CommitDate: Mon Apr 15 11:00:56 2019 +0200 tdf#124670: xml:space attribute may be specified for w:document root element Treat xml:space specially in OOXMLFastContextHandler::startFastElement, to allow this attribute to be handled for any element. Change-Id: I81bd1e0642940ffdfc03d6c65d0ce9f421206c5e Reviewed-on: https://gerrit.libreoffice.org/70723 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Mike Kaganski <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/70725 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> diff --git a/sw/qa/extras/ooxmlimport/data/tdf124670.docx b/sw/qa/extras/ooxmlimport/data/tdf124670.docx new file mode 100644 index 000000000000..d804efa5a990 Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/tdf124670.docx differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx index 991573fd40af..a74501cd708c 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx @@ -330,6 +330,16 @@ DECLARE_OOXMLIMPORT_TEST(testTdf121440, "tdf121440.docx") getProperty<sal_Int32>(getRun(getParagraph(1), 1), "CharEscapement")); } +DECLARE_OOXMLIMPORT_TEST(testTdf124670, "tdf124670.docx") +{ + CPPUNIT_ASSERT_EQUAL(1, getParagraphs()); + // We need to take xml:space attribute into account, even in w:document element + uno::Reference<text::XTextRange> paragraph = getParagraph(1); + CPPUNIT_ASSERT_EQUAL( + OUString("You won't believe, but that's how it was in markup of original bugdoc!"), + paragraph->getString()); +} + // tests should only be added to ooxmlIMPORT *if* they fail round-tripping in ooxmlEXPORT CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index ff3da8a3ba5a..be825d2f01d3 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -144,6 +144,13 @@ void SAL_CALL OOXMLFastContextHandler::startFastElement (Token_t Element, const uno::Reference< xml::sax::XFastAttributeList > & Attribs) { + // Set xml:space value early, to allow child contexts use it when dealing with strings. + if (Attribs && Attribs->hasAttribute(oox::NMSP_xml | oox::XML_space)) + { + mbPreserveSpace = Attribs->getValue(oox::NMSP_xml | oox::XML_space) == "preserve"; + mbPreserveSpaceSet = true; + } + if (oox::getNamespace(Element) == NMSP_mce) m_bDiscardChildren = prepareMceContext(Element, Attribs); @@ -881,6 +888,8 @@ bool OOXMLFastContextHandler::IsPreserveSpace() const { // xml:space attribute applies to all elements within the content of the element where it is specified, // unless overridden with another instance of the xml:space attribute + if (mbPreserveSpaceSet) + return mbPreserveSpace; if (mpParent) return mpParent->IsPreserveSpace(); return false; // default value @@ -893,9 +902,7 @@ bool OOXMLFastContextHandler::IsPreserveSpace() const OOXMLFastContextHandlerStream::OOXMLFastContextHandlerStream (OOXMLFastContextHandler * pContext) : OOXMLFastContextHandler(pContext), - mpPropertySetAttrs(new OOXMLPropertySet), - mbPreserveSpace(false), - mbPreserveSpaceSet(false) + mpPropertySetAttrs(new OOXMLPropertySet) { } @@ -906,14 +913,7 @@ OOXMLFastContextHandlerStream::~OOXMLFastContextHandlerStream() void OOXMLFastContextHandlerStream::newProperty(Id nId, const OOXMLValue::Pointer_t& pVal) { - if (nId == NS_ooxml::LN_CT_Text_space) - { - // Set <xml:space> value early, to allow - // child contexts use it when dealing with strings - mbPreserveSpace = pVal->getString() == "preserve"; - mbPreserveSpaceSet = true; - } - else if (nId != 0x0) + if (nId != 0x0) { mpPropertySetAttrs->add(nId, pVal, OOXMLProperty::ATTRIBUTE); } @@ -943,15 +943,6 @@ void OOXMLFastContextHandlerStream::handleHyperlink() aHyperlinkHandler.writetext(); } -bool OOXMLFastContextHandlerStream::IsPreserveSpace() const -{ - // xml:space attribute applies to all elements within the content of the element where it is specified, - // unless overridden with another instance of the xml:space attribute - if (mbPreserveSpaceSet) - return mbPreserveSpace; - return OOXMLFastContextHandler::IsPreserveSpace(); -} - /* class OOXMLFastContextHandlerProperties */ diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx index 29842cc5071f..097214b8e049 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx @@ -51,7 +51,7 @@ public: virtual ~OOXMLFastContextHandler() override; // css::xml::sax::XFastContextHandler: - virtual void SAL_CALL startFastElement (Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; + virtual void SAL_CALL startFastElement (Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override final; virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override; @@ -224,9 +224,6 @@ protected: void startAction(); void endAction(); - // 2.10 of XML 1.0 specification - virtual bool IsPreserveSpace() const; - const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() { return m_xContext;} bool inPositionV; @@ -237,9 +234,14 @@ private: /// Handles AlternateContent. Returns true, if children of the current element should be ignored. bool prepareMceContext(Token_t nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs); + // 2.10 of XML 1.0 specification + bool IsPreserveSpace() const; + css::uno::Reference< css::uno::XComponentContext > m_xContext; bool m_bDiscardChildren; bool m_bTookChoice; ///< Did we take the Choice or want Fallback instead? + bool mbPreserveSpace = false; + bool mbPreserveSpaceSet = false; }; @@ -259,13 +261,8 @@ public: void handleHyperlink(); -protected: - virtual bool IsPreserveSpace() const override; - private: mutable OOXMLPropertySet::Pointer_t mpPropertySetAttrs; - bool mbPreserveSpace : 1; - bool mbPreserveSpaceSet : 1; }; class OOXMLFastContextHandlerProperties : public OOXMLFastContextHandler commit 64381dad01132f74e513c347db87f304d0e704ff Author: Takeshi Abe <[email protected]> AuthorDate: Thu Mar 28 19:04:30 2019 +0900 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Apr 13 21:44:18 2019 +0200 tdf#119890 followup: Forbid HOME to be the default dir ... of user templates This is kludgy yet better than making innocent users waiting for the template dialog ~forever as pointed out in the comments in <https://gerrit.libreoffice.org/#/c/67741/>. Change-Id: I6dfdc0408effb06cc9175cd976ea6687e52a7136 Reviewed-on: https://gerrit.libreoffice.org/70709 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/shell/source/backends/desktopbe/desktopbackend.cxx b/shell/source/backends/desktopbe/desktopbackend.cxx index 5923c6583fb7..4b1d0c44b182 100644 --- a/shell/source/backends/desktopbe/desktopbackend.cxx +++ b/shell/source/backends/desktopbe/desktopbackend.cxx @@ -127,7 +127,7 @@ void Default::setPropertyValue(OUString const &, css::uno::Any const &) static_cast< cppu::OWeakObject * >(this), -1); } -OUString xdg_user_dir_lookup (const char *type) +OUString xdg_user_dir_lookup (const char *type, bool bAllowHomeDir) { size_t nLenType = strlen(type); char *config_home; @@ -218,16 +218,20 @@ OUString xdg_user_dir_lookup (const char *type) if (aUserDirBuf.getLength()>0 && !bError) { aDocumentsDirURL = aUserDirBuf.makeStringAndClear(); - osl::Directory aDocumentsDir( aDocumentsDirURL ); - if( osl::FileBase::E_None == aDocumentsDir.open() ) - return aDocumentsDirURL; + if ( bAllowHomeDir || + (aDocumentsDirURL != aHomeDirURL && aDocumentsDirURL != aHomeDirURL + "/") ) + { + osl::Directory aDocumentsDir( aDocumentsDirURL ); + if( osl::FileBase::E_None == aDocumentsDir.open() ) + return aDocumentsDirURL; + } } /* Use fallbacks historical compatibility if nothing else exists */ return aHomeDirURL + "/" + OUString::createFromAscii(type); } -css::uno::Any xdgDirectoryIfExists(char const * type) { - auto url = xdg_user_dir_lookup(type); +css::uno::Any xdgDirectoryIfExists(char const * type, bool bAllowHomeDir) { + auto url = xdg_user_dir_lookup(type, bAllowHomeDir); return css::uno::Any( osl::Directory(url).open() == osl::FileBase::E_None ? css::beans::Optional<css::uno::Any>(true, css::uno::Any(url)) @@ -238,12 +242,13 @@ css::uno::Any Default::getPropertyValue(OUString const & PropertyName) { if (PropertyName == "TemplatePathVariable") { - return xdgDirectoryIfExists("Templates"); + // Never pick up the HOME directory as the default location of user's templates + return xdgDirectoryIfExists("Templates", false); } if (PropertyName == "WorkPathVariable") { - return xdgDirectoryIfExists("Documents"); + return xdgDirectoryIfExists("Documents", true); } if ( PropertyName == "EnableATToolSupport" || commit 9dbff5b4e1dabb715ed146827f69f8fbaba8644a Author: Michael Stahl <[email protected]> AuthorDate: Fri Apr 5 19:30:45 2019 +0200 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Apr 13 20:28:39 2019 +0200 writerfilter: implement RTF derived styles defaulting It turns out that the situation fixed in commit 1be0a3fa9ebb22b607c54b47739d4467acfed259 also applies to the definition of the styles themselves. To implement the same style import as Word, the style definitions need to be stored twice: once as read from the file, and another time with attributes defaulted and deduplicated vs. the parent style; the second representation is then sent to the domain mapper. To make this easier, add a bool parameter to cloneAndDeduplicate() to disable the implicit pPr dereferencing that happens when creating the hard formatted paragraph properties (this could potentially be cleaned up further if those paragraph properties would use pPr wrapper themselves). Also implement defaulting of line spacing in getDefaultSPRM(). Reviewed-on: https://gerrit.libreoffice.org/70320 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> (cherry picked from commit 3d74ddd190a5087e0a54ef7b14d0a43006745ec3) Change-Id: I4810e917697b3af244e5dbdd7f5a45b4767c93fc Reviewed-on: https://gerrit.libreoffice.org/70508 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/sw/qa/extras/rtfexport/data/para-style-bottom-margin-2.rtf b/sw/qa/extras/rtfexport/data/para-style-bottom-margin-2.rtf new file mode 100644 index 000000000000..b4261e717070 --- /dev/null +++ b/sw/qa/extras/rtfexport/data/para-style-bottom-margin-2.rtf @@ -0,0 +1,12 @@ +{\rtf1 +\ansi\ansicpg1252\deff0 +{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2 Times New Roman;}} +{\stylesheet +{\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \snext0 Normal;} +{\s15\ql \li720\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\contextualspace \sbasedon0 \snext15 List Paragraph;} +} +\pard\plain \ltrpar\s15\ql \li720\ri0\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\contextualspace +\par +\pard\plain +\par +} diff --git a/sw/qa/extras/rtfexport/rtfexport2.cxx b/sw/qa/extras/rtfexport/rtfexport2.cxx index 307b6465ecad..1607d1754b05 100644 --- a/sw/qa/extras/rtfexport/rtfexport2.cxx +++ b/sw/qa/extras/rtfexport/rtfexport2.cxx @@ -1105,6 +1105,33 @@ DECLARE_RTFEXPORT_TEST(testParaBottomMargin, "para-bottom-margin.rtf") CPPUNIT_ASSERT_EQUAL(sal_Int32(2), getProperty<sal_Int32>(getParagraph(1), "ParaTopMargin")); } +DECLARE_RTFIMPORT_TEST(testParaStyleBottomMargin2, "para-style-bottom-margin-2.rtf") +{ + uno::Reference<beans::XPropertySet> xPropertySet( + getStyles("ParagraphStyles")->getByName("Standard"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(353), getProperty<sal_Int32>(xPropertySet, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, + getProperty<style::LineSpacing>(xPropertySet, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(115), + getProperty<style::LineSpacing>(xPropertySet, "ParaLineSpacing").Height); + + // the derived style contains \sa200, as does its parent + uno::Reference<beans::XPropertySet> xPropertySet1( + getStyles("ParagraphStyles")->getByName("List Paragraph"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(353), getProperty<sal_Int32>(xPropertySet1, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, + getProperty<style::LineSpacing>(xPropertySet1, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(115), + getProperty<style::LineSpacing>(xPropertySet1, "ParaLineSpacing").Height); + // for the paragraph there is no \saN, so it should default to 0 + auto const xPara(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, + getProperty<style::LineSpacing>(xPara, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(115), + getProperty<style::LineSpacing>(xPara, "ParaLineSpacing").Height); +} + DECLARE_RTFEXPORT_TEST(testFdo66040, "fdo66040.rtf") { uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); diff --git a/sw/qa/extras/rtfimport/data/para-style-bottom-margin.rtf b/sw/qa/extras/rtfimport/data/para-style-bottom-margin.rtf new file mode 100644 index 000000000000..d7ebc215f3fc --- /dev/null +++ b/sw/qa/extras/rtfimport/data/para-style-bottom-margin.rtf @@ -0,0 +1,14 @@ +{\rtf1 +\ansi\ansicpg1252\deff0 +{\fonttbl +{\f0 Times New Roman;} +} +{\stylesheet +{\sa200\sl276\slmult1 \snext0 Normal;} +{\s19 \sbasedon0 \snext0 toc 1;} +} +\pard\plain \s19 +foo +\par +\par +} diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx index 5d7e6f34db79..5db5dbc2792c 100644 --- a/sw/qa/extras/rtfimport/rtfimport.cxx +++ b/sw/qa/extras/rtfimport/rtfimport.cxx @@ -18,6 +18,8 @@ #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/LineSpacingMode.hpp> #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/table/BorderLine2.hpp> @@ -1588,6 +1590,35 @@ DECLARE_RTFIMPORT_TEST(testDefaultValues, "default-values.rtf") CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_AUTO), getProperty<sal_Int32>(run, "CharColor")); } +DECLARE_RTFIMPORT_TEST(testParaStyleBottomMargin, "para-style-bottom-margin.rtf") +{ + uno::Reference<beans::XPropertySet> xPropertySet( + getStyles("ParagraphStyles")->getByName("Standard"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(353), getProperty<sal_Int32>(xPropertySet, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, + getProperty<style::LineSpacing>(xPropertySet, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(115), + getProperty<style::LineSpacing>(xPropertySet, "ParaLineSpacing").Height); + + // The reason why this is 0 despite the default style containing \sa200 + // is that Word will actually interpret \basedonN + // as "set style N and for every attribute of that style, + // set an attribute with default value on the style" + uno::Reference<beans::XPropertySet> xPropertySet1( + getStyles("ParagraphStyles")->getByName("Contents 1"), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPropertySet1, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, + getProperty<style::LineSpacing>(xPropertySet1, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(100), + getProperty<style::LineSpacing>(xPropertySet1, "ParaLineSpacing").Height); + auto const xPara(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaBottomMargin")); + CPPUNIT_ASSERT_EQUAL(style::LineSpacingMode::PROP, // 0 or 3 ??? + getProperty<style::LineSpacing>(xPara, "ParaLineSpacing").Mode); + CPPUNIT_ASSERT_EQUAL(sal_Int16(100), + getProperty<style::LineSpacing>(xPara, "ParaLineSpacing").Height); +} + // tests should only be added to rtfIMPORT *if* they fail round-tripping in rtfEXPORT CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index 104e0e004bf6..6c97111bed71 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -517,8 +517,9 @@ RTFDocumentImpl::getProperties(RTFSprms& rAttributes, RTFSprms const& rSprms, Id } // Get rid of direct formatting what is already in the style. - RTFSprms const sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType)); - RTFSprms const attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType)); + RTFSprms const sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true)); + RTFSprms const attributes( + rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true)); return new RTFReferenceProperties(attributes, sprms); } @@ -2026,6 +2027,61 @@ writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStylePrope return pProps; } +/** 2 different representations of the styles are needed: + + 1) flat content, as read from the input file: + stored in m_aStyleTableEntries, used as reference input for + deduplication both here and for hard formatting in getProperties() + + 2) real content, with proper override of sprms/attributes where it differs + from parent style; this is produced here and sent to domain mapper + */ +RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable() +{ + RTFReferenceTable::Entries_t ret; + for (auto const& it : m_aStyleTableEntries) + { + auto pStyle = it.second; + // ugly downcasts here, but can't easily replace the members with + // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway + RTFValue::Pointer_t const pBasedOn( + static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find( + NS_ooxml::LN_CT_Style_basedOn)); + if (pBasedOn) + { + int const nBasedOn(pBasedOn->getInt()); + auto const itParent(m_aStyleTableEntries.find(nBasedOn)); // definition as read! + if (itParent != m_aStyleTableEntries.end()) + { + auto const pStyleType( + static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find( + NS_ooxml::LN_CT_Style_type)); + assert(pStyleType); + int const nStyleType(pStyleType->getInt()); + RTFSprms const sprms( + static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate( + static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(), + nStyleType)); + RTFSprms const attributes( + static_cast<RTFReferenceProperties&>(*pStyle) + .getAttributes() + .cloneAndDeduplicate( + static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(), + nStyleType)); + + pStyle = new RTFReferenceProperties(attributes, sprms); + } + else + { + SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn); + } + } + ret[it.first] = pStyle; + } + assert(ret.size() == m_aStyleTableEntries.size()); + return ret; +} + void RTFDocumentImpl::resetSprms() { m_aStates.top().aTableSprms.clear(); @@ -2089,8 +2145,9 @@ RTFError RTFDocumentImpl::popState() break; case Destination::STYLESHEET: { + RTFReferenceTable::Entries_t const pStyleTableDeduplicated(deduplicateStyleTable()); writerfilter::Reference<Table>::Pointer_t const pTable( - new RTFReferenceTable(m_aStyleTableEntries)); + new RTFReferenceTable(pStyleTableDeduplicated)); Mapper().table(NS_ooxml::LN_STYLESHEET, pTable); } break; diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx index d51512889d74..0ecf59aae42a 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx @@ -504,6 +504,8 @@ public: /// Buffers properties to be sent later. void bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue, const tools::SvRef<TableRowBuffer>& pTableProperties); + /// implement non-obvious RTF specific style inheritance + RTFReferenceTable::Entries_t deduplicateStyleTable(); private: SvStream& Strm(); diff --git a/writerfilter/source/rtftok/rtfsprm.cxx b/writerfilter/source/rtftok/rtfsprm.cxx index a4f3b81be211..9eab27298050 100644 --- a/writerfilter/source/rtftok/rtfsprm.cxx +++ b/writerfilter/source/rtftok/rtfsprm.cxx @@ -160,6 +160,12 @@ static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType) case NS_ooxml::LN_CT_Ind_firstLine: return new RTFValue(0); + case NS_ooxml::LN_CT_Spacing_lineRule: + return new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto); + case NS_ooxml::LN_CT_Spacing_line: + // presumably this means 100%, cf. static const int nSingleLineSpacing = 240; + return new RTFValue(240); + default: break; } @@ -338,7 +344,8 @@ void RTFSprms::duplicateList(const RTFValue::Pointer_t& pAbstract) } } -RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType) const +RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id const nStyleType, + bool const bImplicitPPr) const { RTFSprms ret(*this); ret.ensureCopyBeforeWrite(); @@ -351,7 +358,7 @@ RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType) cons // paragraphs, but they are below NS_ooxml::LN_CT_Style_pPr in case of // styles. So handle those children directly, to avoid unexpected // addition of direct formatting sprms at the paragraph level. - if (rSprm.first == NS_ooxml::LN_CT_Style_pPr) + if (bImplicitPPr && rSprm.first == NS_ooxml::LN_CT_Style_pPr) { for (auto& i : rSprm.second->getSprms()) cloneAndDeduplicateSprm(i, ret, nStyleType); diff --git a/writerfilter/source/rtftok/rtfsprm.hxx b/writerfilter/source/rtftok/rtfsprm.hxx index cc5fb73ff13f..24eb9d6e1da9 100644 --- a/writerfilter/source/rtftok/rtfsprm.hxx +++ b/writerfilter/source/rtftok/rtfsprm.hxx @@ -62,7 +62,9 @@ public: /// Removes elements which are already in the reference set. /// Also insert default values to override attributes of style /// (yes, really; that's what Word does). - RTFSprms cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType) const; + /// @param bImplicitPPr implicit dereference of top-level pPr SPRM + RTFSprms cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType, + bool bImplicitPPr = false) const; /// Inserts default values to override attributes of pAbstract. void duplicateList(const RTFValue::Pointer_t& pAbstract); /// Removes duplicated values based on in-list properties. commit 915ec0b5f5ce9a2da6a51f5278ea4faaffa19839 Author: Stephan Bergmann <[email protected]> AuthorDate: Fri Apr 12 08:18:26 2019 +0200 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Apr 13 00:24:22 2019 +0200 Adapt solenv/flatpak-manifest.in to recent download.lst changes Reviewed-on: https://gerrit.libreoffice.org/70638 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <[email protected]> (cherry picked from commit bc8b40ecbc140217b9b55a44adce506d724af297) Conflicts: solenv/flatpak-manifest.in Change-Id: I9b8bb016721f35032fe214f977f9463c241084ea Reviewed-on: https://gerrit.libreoffice.org/70649 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/solenv/flatpak-manifest.in b/solenv/flatpak-manifest.in index 0ebf18155326..79d4571a2a13 100644 --- a/solenv/flatpak-manifest.in +++ b/solenv/flatpak-manifest.in @@ -234,10 +234,10 @@ "dest-filename": "external/tarballs/libfreehand-0.1.2.tar.xz" }, { - "url": "https://dev-www.libreoffice.org/src/language-subtag-registry-2018-04-23.tar.bz2", - "sha256": "14c21f4533ca74e3af9e09184d6756a750d0cd46099015ba8c595e48499aa878", + "url": "https://dev-www.libreoffice.org/src/language-subtag-registry-2019-04-03.tar.bz2", + "sha256": "a1d7fb901764bb8f251d4f686cdf565764f9987d0fb5d9315d54a7366a84822d", "type": "file", - "dest-filename": "external/tarballs/language-subtag-registry-2018-04-23.tar.bz2" + "dest-filename": "external/tarballs/language-subtag-registry-2019-04-03.tar.bz2" }, { "url": "https://dev-www.libreoffice.org/src/liblangtag-0.6.2.tar.bz2", @@ -360,10 +360,10 @@ "dest-filename": "external/tarballs/liborcus-0.14.1.tar.gz" }, { - "url": "https://dev-www.libreoffice.org/src/poppler-0.73.0.tar.xz", - "sha256": "e44b5543903128884ba4538c2a97d3bcc8889e97ffacc4636112101f0238db03", + "url": "https://dev-www.libreoffice.org/src/poppler-0.74.0.tar.xz", + "sha256": "92e09fd3302567fd36146b36bb707db43ce436e8841219025a82ea9fb0076b2f", "type": "file", - "dest-filename": "external/tarballs/poppler-0.73.0.tar.xz" + "dest-filename": "external/tarballs/poppler-0.74.0.tar.xz" }, { "url": "https://dev-www.libreoffice.org/src/postgresql-9.2.24.tar.bz2", commit cefdf51bc368d1710d334d722c2d2f597b185b25 Author: Caolán McNamara <[email protected]> AuthorDate: Fri Apr 12 13:02:02 2019 +0100 Commit: Adolfo Jayme Barrientos <[email protected]> CommitDate: Fri Apr 12 17:24:47 2019 +0200 Resolves: tdf#124613 stray .05 at end of GtkAdjustment lower value Change-Id: If42b676c3321d73455771b6ea62aefb806caccd2 Reviewed-on: https://gerrit.libreoffice.org/70674 Reviewed-by: Adolfo Jayme Barrientos <[email protected]> Tested-by: Adolfo Jayme Barrientos <[email protected]> diff --git a/sc/uiconfig/scalc/ui/sheetprintpage.ui b/sc/uiconfig/scalc/ui/sheetprintpage.ui index 03930da3fb0b..1ae07334dc7b 100644 --- a/sc/uiconfig/scalc/ui/sheetprintpage.ui +++ b/sc/uiconfig/scalc/ui/sheetprintpage.ui @@ -3,8 +3,8 @@ <interface domain="sc"> <requires lib="gtk+" version="3.18"/> <object class="GtkAdjustment" id="adjustmentFirstPage"> - <property name="lower">1.05</property> - <property name="upper">9999.0400000000009</property> + <property name="lower">1</property> + <property name="upper">9999</property> <property name="step_increment">1</property> <property name="page_increment">10</property> </object> commit a9c00875cfe90920940586d350f8be6898f3e536 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Mar 26 12:09:03 2019 +0000 Commit: Xisco Faulí <[email protected]> CommitDate: Fri Apr 12 14:01:39 2019 +0200 rhbz#1691287 tdf#53029 ui prompt for printer authentication refactor and reuse existing dialog to add potential domain entry Change-Id: Ib884931f8ccc62aad9b3e92ecf93d1da7ffe607b Reviewed-on: https://gerrit.libreoffice.org/69765 Tested-by: Jenkins Reviewed-by: Xisco Faulí <[email protected]> diff --git a/vcl/inc/printerinfomanager.hxx b/vcl/inc/printerinfomanager.hxx index 49bbc1491483..5ef626268c0b 100644 --- a/vcl/inc/printerinfomanager.hxx +++ b/vcl/inc/printerinfomanager.hxx @@ -53,6 +53,8 @@ struct PrinterInfo : JobData // a list of special features separated by ',' not used by psprint // but assigned from the outside (currently for "fax","pdf=","autoqueue","external_dialog") OUString m_aFeatures; + // auth-info-required, potential [domain],[username],[password] to prompt for to authenticate printing + OUString m_aAuthInfoRequired; PrinterSetupMode meSetupMode; PrinterInfo() diff --git a/vcl/uiconfig/ui/cupspassworddialog.ui b/vcl/uiconfig/ui/cupspassworddialog.ui index 9b37d3eacc2d..0bae75795df6 100644 --- a/vcl/uiconfig/ui/cupspassworddialog.ui +++ b/vcl/uiconfig/ui/cupspassworddialog.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.4 --> +<!-- Generated with glade 3.22.1 --> <interface domain="vcl"> <requires lib="gtk+" version="3.18"/> <object class="GtkDialog" id="CUPSPasswordDialog"> @@ -10,6 +10,9 @@ <property name="default_width">0</property> <property name="default_height">0</property> <property name="type_hint">normal</property> + <child> + <placeholder/> + </child> <child internal-child="vbox"> <object class="GtkBox" id="dialog-vbox1"> <property name="can_focus">False</property> @@ -76,7 +79,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">1</property> + <property name="top_attach">2</property> </packing> </child> <child> @@ -90,7 +93,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">2</property> + <property name="top_attach">3</property> </packing> </child> <child> @@ -118,7 +121,7 @@ </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">1</property> + <property name="top_attach">2</property> </packing> </child> <child> @@ -128,10 +131,37 @@ <property name="hexpand">True</property> <property name="visibility">False</property> <property name="activates_default">True</property> + <property name="input_purpose">password</property> </object> <packing> <property name="left_attach">1</property> - <property name="top_attach">2</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label3"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes" context="cupspassworddialog|label1">_Domain:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">domain</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="domain"> + <property name="can_focus">True</property> + <property name="no_show_all">True</property> + <property name="hexpand">True</property> + <property name="activates_default">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> </packing> </child> </object> @@ -147,8 +177,5 @@ <action-widget response="-5">ok</action-widget> <action-widget response="-6">cancel</action-widget> </action-widgets> - <child> - <placeholder/> - </child> </object> </interface> diff --git a/vcl/unx/generic/printer/cupsmgr.cxx b/vcl/unx/generic/printer/cupsmgr.cxx index 49f7ce201516..630e39437119 100644 --- a/vcl/unx/generic/printer/cupsmgr.cxx +++ b/vcl/unx/generic/printer/cupsmgr.cxx @@ -319,6 +319,8 @@ void CUPSManager::initialize() aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding); if(!strcmp(pDest->options[k].name, "printer-location")) aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding); + if(!strcmp(pDest->options[k].name, "auth-info-required")) + aPrinter.m_aInfo.m_aAuthInfoRequired=OStringToOUString(pDest->options[k].value, aEncoding); } OUStringBuffer aBuf( 256 ); @@ -616,6 +618,88 @@ void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner } } +namespace +{ + class RTSPWDialog : public weld::GenericDialogController + { + std::unique_ptr<weld::Label> m_xText; + std::unique_ptr<weld::Label> m_xDomainLabel; + std::unique_ptr<weld::Entry> m_xDomainEdit; + std::unique_ptr<weld::Label> m_xUserLabel; + std::unique_ptr<weld::Entry> m_xUserEdit; + std::unique_ptr<weld::Label> m_xPassLabel; + std::unique_ptr<weld::Entry> m_xPassEdit; + + public: + RTSPWDialog(weld::Window* pParent, const OString& rServer, const OString& rUserName); + + OString getDomain() const + { + return OUStringToOString( m_xDomainEdit->get_text(), osl_getThreadTextEncoding() ); + } + + OString getUserName() const + { + return OUStringToOString( m_xUserEdit->get_text(), osl_getThreadTextEncoding() ); + } + + OString getPassword() const + { + return OUStringToOString( m_xPassEdit->get_text(), osl_getThreadTextEncoding() ); + } + + void SetDomainVisible(bool bShow) + { + m_xDomainLabel->set_visible(bShow); + m_xDomainEdit->set_visible(bShow); + } + + void SetUserVisible(bool bShow) + { + m_xUserLabel->set_visible(bShow); + m_xUserEdit->set_visible(bShow); + } + + void SetPassVisible(bool bShow) + { + m_xPassLabel->set_visible(bShow); + m_xPassEdit->set_visible(bShow); + } + }; + + RTSPWDialog::RTSPWDialog(weld::Window* pParent, const OString& rServer, const OString& rUserName) + : GenericDialogController(pParent, "vcl/ui/cupspassworddialog.ui", "CUPSPasswordDialog") + , m_xText(m_xBuilder->weld_label("text")) + , m_xDomainLabel(m_xBuilder->weld_label("label3")) + , m_xDomainEdit(m_xBuilder->weld_entry("domain")) + , m_xUserLabel(m_xBuilder->weld_label("label1")) + , m_xUserEdit(m_xBuilder->weld_entry("user")) + , m_xPassLabel(m_xBuilder->weld_label("label2")) + , m_xPassEdit(m_xBuilder->weld_entry("pass")) + { + OUString aText(m_xText->get_label()); + aText = aText.replaceFirst("%s", OStringToOUString(rServer, osl_getThreadTextEncoding())); + m_xText->set_label(aText); + m_xUserEdit->set_text(OStringToOUString(rUserName, osl_getThreadTextEncoding())); + } + + bool AuthenticateQuery(const OString& rServer, OString& rUserName, OString& rPassword) + { + bool bRet = false; + + vcl::Window* pWin = Application::GetDefDialogParent(); + RTSPWDialog aDialog(pWin ? pWin->GetFrameWeld() : nullptr, rServer, rUserName); + if (aDialog.run() == RET_OK) + { + rUserName = aDialog.getUserName(); + rPassword = aDialog.getPassword(); + bRet = true; + } + + return bRet; + } +} + bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber ) { SAL_INFO( "vcl.unx.print", "endSpool: " << rPrintername << "," << rJobTitle << " copy count = " << rDocumentJobData.m_nCopies ); @@ -641,7 +725,56 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi // setup cups options int nNumOptions = 0; cups_option_t* pOptions = nullptr; - getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, reinterpret_cast<void**>(&pOptions) ); + auto ppOptions = reinterpret_cast<void**>(&pOptions); + getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, ppOptions ); + + PrinterInfo aInfo(getPrinterInfo(rPrintername)); + if (!aInfo.m_aAuthInfoRequired.isEmpty()) + { + bool bDomain(false), bUser(false), bPass(false); + sal_Int32 nIndex = 0; + do + { + OUString aToken = aInfo.m_aAuthInfoRequired.getToken(0, ',', nIndex); + if (aToken == "domain") + bDomain = true; + else if (aToken == "username") + bUser = true; + else if (aToken == "password") + bPass = true; + } + while (nIndex >= 0); + + if (bDomain || bUser || bPass) + { + OString sPrinterName(OUStringToOString(rPrintername, RTL_TEXTENCODING_UTF8)); + vcl::Window* pWin = Application::GetDefDialogParent(); + RTSPWDialog aDialog(pWin ? pWin->GetFrameWeld() : nullptr, sPrinterName, ""); + aDialog.SetDomainVisible(bDomain); + aDialog.SetUserVisible(bUser); + aDialog.SetPassVisible(bPass); + + if (aDialog.run() == RET_OK) + { + OString sAuth; + if (bDomain) + sAuth = aDialog.getDomain().replaceAll(",", "\\,"); + if (bUser) + { + if (!sAuth.isEmpty()) + sAuth += ","; + sAuth += aDialog.getUserName().replaceAll(",", "\\,"); + } + if (bPass) + { + if (!sAuth.isEmpty()) + sAuth += ","; + sAuth += aDialog.getPassword().replaceAll(",", "\\,"); + } + nNumOptions = cupsAddOption("auth-info", sAuth.getStr(), nNumOptions, &pOptions); + } + } + } OString sJobName(OUStringToOString(rJobTitle, aEnc)); @@ -731,59 +864,6 @@ bool CUPSManager::checkPrintersChanged( bool bWait ) return bChanged; } -namespace -{ - class RTSPWDialog : public weld::GenericDialogController - { - std::unique_ptr<weld::Label> m_xText; - std::unique_ptr<weld::Entry> m_xUserEdit; - std::unique_ptr<weld::Entry> m_xPassEdit; - - public: - RTSPWDialog(const OString& rServer, const OString& rUserName, weld::Window* pParent); - OString getUserName() const; - OString getPassword() const; - }; - - RTSPWDialog::RTSPWDialog( const OString& rServer, const OString& rUserName, weld::Window* pParent ) - : GenericDialogController(pParent, "vcl/ui/cupspassworddialog.ui", "CUPSPasswordDialog") - , m_xText(m_xBuilder->weld_label("text")) - , m_xUserEdit(m_xBuilder->weld_entry("user")) - , m_xPassEdit(m_xBuilder->weld_entry("pass")) - { - OUString aText(m_xText->get_label()); - aText = aText.replaceFirst("%s", OStringToOUString(rServer, osl_getThreadTextEncoding())); - m_xText->set_label(aText); - m_xUserEdit->set_text(OStringToOUString(rUserName, osl_getThreadTextEncoding())); - } - - OString RTSPWDialog::getUserName() const - { - return OUStringToOString( m_xUserEdit->get_text(), osl_getThreadTextEncoding() ); - } - - OString RTSPWDialog::getPassword() const - { - return OUStringToOString( m_xPassEdit->get_text(), osl_getThreadTextEncoding() ); - } - - bool AuthenticateQuery(const OString& rServer, OString& rUserName, OString& rPassword) - { - bool bRet = false; - - vcl::Window* pWin = Application::GetDefDialogParent(); - RTSPWDialog aDialog(rServer, rUserName, pWin ? pWin->GetFrameWeld() : nullptr); - if (aDialog.run() == RET_OK) - { - rUserName = aDialog.getUserName(); - rPassword = aDialog.getPassword(); - bRet = true; - } - - return bRet; - } -} - const char* CUPSManager::authenticateUser() { const char* pRet = nullptr; commit 66e9170028380b04b5cfd80d0de57994af6ab973 Author: Patrick Jaap <[email protected]> AuthorDate: Thu Feb 14 10:08:58 2019 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Apr 12 09:49:07 2019 +0200 FIX: DOCX export: use all updated attributes during table export In a previous commit only x/y coordinate were considered. For better overview make use of the OOXML converter for orients and relations. Change-Id: I9792ccfbc2ebb58fd768c14278cdfd9b54efe62f Reviewed-on: https://gerrit.libreoffice.org/69523 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/70589 diff --git a/sw/qa/extras/uiwriter/data2/floating-table-position.docx b/sw/qa/extras/uiwriter/data2/floating-table-position.docx new file mode 100644 index 000000000000..de7a467aac1b Binary files /dev/null and b/sw/qa/extras/uiwriter/data2/floating-table-position.docx differ diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index 52768e05086e..2344aa743248 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -45,6 +45,7 @@ public: void testTdf101873(); void testTableWidth(); void testTdf122942(); + void testDocxAttributeTableExport(); CPPUNIT_TEST_SUITE(SwUiWriterTest2); CPPUNIT_TEST(testRedlineMoveInsertInDelete); @@ -59,6 +60,7 @@ public: CPPUNIT_TEST(testTdf101873); CPPUNIT_TEST(testTableWidth); CPPUNIT_TEST(testTdf122942); + CPPUNIT_TEST(testDocxAttributeTableExport); CPPUNIT_TEST_SUITE_END(); private: @@ -531,6 +533,45 @@ void SwUiWriterTest2::testTdf122942() CPPUNIT_ASSERT_LESS(static_cast<SwTwips>(0), rVert.GetPos()); } +void SwUiWriterTest2::testDocxAttributeTableExport() +{ + createDoc("floating-table-position.docx"); + + // get the table frame, set new values and dismiss the references + { + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xDrawPage(xDrawPageSupplier->getDrawPage(), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + + // change the properties + // 8133 -> 8000 + xShape->setPropertyValue("VertOrientPosition", uno::makeAny(static_cast<sal_Int32>(8000))); + // 5964 -> 5000 + xShape->setPropertyValue("HoriOrientPosition", uno::makeAny(static_cast<sal_Int32>(5000))); + // 0 (frame) -> 8 (page print area) + xShape->setPropertyValue("VertOrientRelation", uno::makeAny(static_cast<sal_Int16>(8))); + // 8 (page print area) -> 0 (frame) + xShape->setPropertyValue("HoriOrientRelation", uno::makeAny(static_cast<sal_Int16>(0))); + } + // save it to docx + reload("Office Open XML Text", "floating-table-position.docx"); + + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xDrawPage(xDrawPageSupplier->getDrawPage(), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + + // test the new values + sal_Int32 nValue = getProperty<sal_Int32>(xShape, "VertOrientPosition"); + CPPUNIT_ASSERT(sal_Int32(7999) <= nValue && nValue <= sal_Int32(8001)); + nValue = getProperty<sal_Int32>(xShape, "HoriOrientPosition"); + CPPUNIT_ASSERT(sal_Int32(4999) <= nValue && nValue <= sal_Int32(5001)); + + CPPUNIT_ASSERT_EQUAL(sal_Int16(8), getProperty<sal_Int16>(xShape, "VertOrientRelation")); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xShape, "HoriOrientRelation")); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest2); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index aab60d8cec1c..e18557016ec9 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -495,8 +495,6 @@ static OString convertToOOXMLVertOrient(sal_Int16 nOrient) { switch( nOrient ) { - case text::VertOrientation::NONE: - return OString(); case text::VertOrientation::CENTER: case text::VertOrientation::LINE_CENTER: return OString( "center" ); @@ -507,8 +505,9 @@ static OString convertToOOXMLVertOrient(sal_Int16 nOrient) case text::VertOrientation::TOP: return OString( "top" ); case text::VertOrientation::LINE_TOP: - default: return OString( "inside" ); + default: + return OString(); } } @@ -516,17 +515,19 @@ static OString convertToOOXMLHoriOrient(sal_Int16 nOrient, bool bIsPosToggle) { switch( nOrient ) { - case text::HoriOrientation::NONE: - return OString(); case text::HoriOrientation::LEFT: return OString( bIsPosToggle ? "inside" : "left" ); + case text::HoriOrientation::INSIDE: + return OString( "inside" ); case text::HoriOrientation::RIGHT: return OString( bIsPosToggle ? "outside" : "right" ); + case text::HoriOrientation::OUTSIDE: + return OString( "outside" ); case text::HoriOrientation::CENTER: - // fall-through indended case text::HoriOrientation::FULL: - default: return OString( "center" ); + default: + return OString(); } } @@ -3847,84 +3848,132 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t uno::Sequence<beans::PropertyValue> aTablePosition = rGrabBagElement.second.get<uno::Sequence<beans::PropertyValue> >(); // look for a surrounding frame and take it's position values const ww8::Frame* pFrame = m_rExport.GetFloatingTableFrame(); - for (sal_Int32 i = 0; i < aTablePosition.getLength(); ++i) + if( pFrame ) { - if (aTablePosition[i].Name == "vertAnchor" && !aTablePosition[i].Value.get<OUString>().isEmpty()) - { - OString strTemp = OUStringToOString(aTablePosition[i].Value.get<OUString>(), RTL_TEXTENCODING_UTF8); - attrListTablePos->add( FSNS( XML_w, XML_vertAnchor ), strTemp.getStr() ); - } - else if (aTablePosition[i].Name == "tblpYSpec" && !aTablePosition[i].Value.get<OUString>().isEmpty()) - { - OString strTemp = OUStringToOString(aTablePosition[i].Value.get<OUString>(), RTL_TEXTENCODING_UTF8); - attrListTablePos->add( FSNS( XML_w, XML_tblpYSpec ), strTemp.getStr() ); - } - else if (aTablePosition[i].Name == "horzAnchor" && !aTablePosition[i].Value.get<OUString>().isEmpty()) - { - OString strTemp = OUStringToOString(aTablePosition[i].Value.get<OUString>(), RTL_TEXTENCODING_UTF8); - attrListTablePos->add( FSNS( XML_w, XML_horzAnchor ), strTemp.getStr() ); - } - else if (aTablePosition[i].Name == "tblpXSpec" && !aTablePosition[i].Value.get<OUString>().isEmpty()) - { - OString strTemp = OUStringToOString(aTablePosition[i].Value.get<OUString>(), RTL_TEXTENCODING_UTF8); - attrListTablePos->add( FSNS( XML_w, XML_tblpXSpec ), strTemp.getStr() ); - } - else if (aTablePosition[i].Name == "bottomFromText") - { - attrListTablePos->add( FSNS( XML_w, XML_bottomFromText ), OString::number( aTablePosition[i].Value.get<sal_Int32>() ) ); - } - else if (aTablePosition[i].Name == "leftFromText") - { - attrListTablePos->add( FSNS( XML_w, XML_leftFromText ), OString::number( aTablePosition[i].Value.get<sal_Int32>() ) ); - } - else if (aTablePosition[i].Name == "rightFromText") - { - attrListTablePos->add( FSNS( XML_w, XML_rightFromText ), OString::number( aTablePosition[i].Value.get<sal_Int32>() ) ); - } - else if (aTablePosition[i].Name == "topFromText") - { - attrListTablePos->add( FSNS( XML_w, XML_topFromText ), OString::number( aTablePosition[i].Value.get<sal_Int32>() ) ); - } - else if (aTablePosition[i].Name == "tblpX") + // we export the values of the surrounding Frame + OString sOrientation; + sal_Int32 nValue; + + // If tblpXSpec or tblpYSpec are present, we do not write tblpX or tblpY! + OString sTblpXSpec = convertToOOXMLHoriOrient( pFrame->GetFrameFormat().GetHoriOrient().GetHoriOrient(), pFrame->GetFrameFormat().GetHoriOrient().IsPosToggle() ); + OString sTblpYSpec = convertToOOXMLVertOrient( pFrame->GetFrameFormat().GetVertOrient().GetVertOrient() ); + + sOrientation = convertToOOXMLVertOrientRel( pFrame->GetFrameFormat().GetVertOrient().GetRelationOrient() ); + if(sOrientation != "page") // do not write default + attrListTablePos->add( FSNS( XML_w, XML_vertAnchor ), sOrientation.getStr() ); + + if( !sTblpYSpec.isEmpty() ) + attrListTablePos->add( FSNS( XML_w, XML_tblpYSpec ), sTblpYSpec.getStr() ); + + sOrientation = convertToOOXMLHoriOrientRel( pFrame->GetFrameFormat().GetHoriOrient().GetRelationOrient() ); + if(sOrientation != "page") // do not wirte default + attrListTablePos->add( FSNS( XML_w, XML_horzAnchor ), sOrientation.getStr() ); + + if( !sTblpXSpec.isEmpty() ) + attrListTablePos->add( FSNS( XML_w, XML_tblpXSpec ), sTblpXSpec.getStr() ); + + nValue = pFrame->GetFrameFormat().GetULSpace().GetLower(); + if( nValue != 0 ) + attrListTablePos->add( FSNS( XML_w, XML_bottomFromText ), OString::number( nValue ) ); + + nValue = pFrame->GetFrameFormat().GetLRSpace().GetLeft(); + if( nValue != 0 ) + attrListTablePos->add( FSNS( XML_w, XML_leftFromText ), OString::number( nValue ) ); + + nValue = pFrame->GetFrameFormat().GetLRSpace().GetRight(); + if( nValue != 0 ) + attrListTablePos->add( FSNS( XML_w, XML_rightFromText ), OString::number( nValue ) ); + + nValue = pFrame->GetFrameFormat().GetULSpace().GetUpper(); + if( nValue != 0 ) + attrListTablePos->add( FSNS( XML_w, XML_topFromText ), OString::number( nValue ) ); + + if( sTblpXSpec.isEmpty() ) // do not write tblpX if tblpXSpec is present { - sal_Int32 nValue = 0; - if (pFrame) + nValue = pFrame->GetFrameFormat().GetHoriOrient().GetPos(); + // we need to revert the additional shift introduced by + // lcl_DecrementHoriOrientPosition() in writerfilter + // 1st: left distance of the table + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwFrameFormat * pFrameFormat = pTabBox->GetFrameFormat(); + const SvxBoxItem& rBox = pFrameFormat->GetBox( ); + sal_uInt16 nLeftDistance = rBox.GetDistance(SvxBoxItemLine::LEFT); + nValue += nLeftDistance; + + // 2nd: if a left border is given, revert the shift by half the width + // from lcl_DecrementHoriOrientPosition() in writerfilter + if (const editeng::SvxBorderLine* pLeftBorder = rBox.GetLeft()) { - nValue = pFrame->GetFrameFormat().GetHoriOrient().GetPos(); - // we need to revert the additional shift introduced by - // lcl_DecrementHoriOrientPosition() in writerfilter - // 1st: left distance of the table - const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
