sc/qa/unit/PivotTableFormatsImportExport.cxx | 35 ++++++ sc/qa/unit/data/xlsx/pivot-table/Pivot_Table_with_Cell_Protection.xlsx |binary sc/source/core/data/table2.cxx | 51 ---------- sc/source/filter/excel/xepivotxml.cxx | 31 +++--- sc/source/filter/inc/stylesbuffer.hxx | 10 + sc/source/filter/oox/stylesbuffer.cxx | 35 ++++++ sc/source/filter/oox/stylesfragment.cxx | 3 7 files changed, 94 insertions(+), 71 deletions(-)
New commits: commit 6ca76f3e6fbb19ef4982b0c178879645e7f72c00 Author: Balazs Varga <balazs.varga.ext...@allotropia.de> AuthorDate: Thu Nov 21 00:53:28 2024 +0100 Commit: Balazs Varga <balazs.varga.ext...@allotropia.de> CommitDate: Thu Nov 21 23:29:22 2024 +0100 Related: tdf#160536 - ooxml import export correctly cell protection property for Pivot tables cells. Change-Id: I1bff7a27cf169fd0876e361b22b4d7017f190b40 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176897 Tested-by: Jenkins Reviewed-by: Balazs Varga <balazs.varga.ext...@allotropia.de> diff --git a/sc/qa/unit/PivotTableFormatsImportExport.cxx b/sc/qa/unit/PivotTableFormatsImportExport.cxx index 22d56c0f11d6..437a25d5e7e6 100644 --- a/sc/qa/unit/PivotTableFormatsImportExport.cxx +++ b/sc/qa/unit/PivotTableFormatsImportExport.cxx @@ -57,6 +57,13 @@ Color getFontColor(ScDocument& rDoc, OUString const& rAddressString) return rItem.getColor(); } +bool getCellProtection(ScDocument& rDoc, OUString const& rAddressString) +{ + const ScPatternAttr* pPattern = rDoc.GetPattern(parseAddress(rDoc, rAddressString)); + const ScProtectionAttr& rItem = pPattern->GetItem(ATTR_PROTECTION); + return rItem.GetProtection(); +} + template <typename T> OUString checkNonEmptyAddresses(ScDocument& rDoc, T const& rArrayOfAddresses) { OUString aString; @@ -66,7 +73,8 @@ template <typename T> OUString checkNonEmptyAddresses(ScDocument& rDoc, T const& aAddress.Parse(rAddressString, rDoc); const ScPatternAttr* pPattern = rDoc.GetPattern(aAddress); if (pPattern->GetItem(ATTR_FONT_COLOR).getColor() != COL_BLACK - || pPattern->GetItem(ATTR_BACKGROUND).GetColor() != COL_TRANSPARENT) + || pPattern->GetItem(ATTR_BACKGROUND).GetColor() != COL_TRANSPARENT + || !pPattern->GetItem(ATTR_PROTECTION).GetProtection()) { aString += rAddressString + " "; } @@ -416,6 +424,31 @@ CPPUNIT_TEST_FIXTURE(ScPivotTableFormatsImportExport, assertTwoDataFieldColumns_WholeDataColumnSelected(*getScDoc()); } +static void assertFields_WithCellProtection(ScDocument& rDoc) +{ + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"F18"_ustr)); + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"F19"_ustr)); + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"F20"_ustr)); + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"G18"_ustr)); + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"G19"_ustr)); + CPPUNIT_ASSERT_EQUAL(false, getCellProtection(rDoc, u"G20"_ustr)); + + // Make sure the other cells have the font color or background set to default + std::vector<OUString> aEmptyAddresses{ + u"F15"_ustr, u"G15"_ustr, u"F16"_ustr, u"G16"_ustr, + u"F17"_ustr, u"G17"_ustr, u"G21"_ustr, u"F21"_ustr, + }; + CPPUNIT_ASSERT_EQUAL(OUString(), checkNonEmptyAddresses(rDoc, aEmptyAddresses)); +} + +CPPUNIT_TEST_FIXTURE(ScPivotTableFormatsImportExport, Pivot_Table_with_Cell_Protection) +{ + createScDoc("xlsx/pivot-table/Pivot_Table_with_Cell_Protection.xlsx"); + assertFields_WithCellProtection(*getScDoc()); + saveAndReload(u"Calc Office Open XML"_ustr); + assertFields_WithCellProtection(*getScDoc()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/data/xlsx/pivot-table/Pivot_Table_with_Cell_Protection.xlsx b/sc/qa/unit/data/xlsx/pivot-table/Pivot_Table_with_Cell_Protection.xlsx new file mode 100644 index 000000000000..d7966a2d9e32 Binary files /dev/null and b/sc/qa/unit/data/xlsx/pivot-table/Pivot_Table_with_Cell_Protection.xlsx differ diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index d6397fb0af0d..388caa164806 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -433,20 +433,6 @@ void ScTable::DeleteArea( aCol[i].DeleteArea(nRow1, nRow2, nDelFlag, bBroadcast, pBroadcastSpans); } - // Do not set protected cell in a protected table - - if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) ) - { - // Do not overwrite cell protection if we are in a Pivot table area and it's not protected - const ScDPObject* pDPObj = rDocument.GetDPAtArea(nTab, nCol1, nRow1, nCol2, nRow2); - if (!pDPObj || (pDPObj && !GetProtection()->isOptionEnabled(ScTableProtection::PIVOT_TABLES))) - { - ScPatternAttr aPattern(rDocument.getCellAttributeHelper()); - aPattern.GetItemSet().Put(ScProtectionAttr(false)); - ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern); - } - } - if( nDelFlag & InsertDeleteFlags::ATTRIB ) mpCondFormatList->DeleteArea( nCol1, nRow1, nCol2, nRow2 ); } @@ -474,29 +460,6 @@ void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMa if((nDelFlag & InsertDeleteFlags::ATTRIB) && rRange.aStart.Tab() == nTab) mpCondFormatList->DeleteArea( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() ); } - - // Do not set protected cell in a protected sheet - - if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) ) - { - // Do not overwrite cell protection if we are in a Pivot table area and it's not protected - const ScRange& rRange = rMark.GetArea(); - const ScDPObject* pDPObj = rDocument.GetDPAtArea(nTab, - rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); - if (!pDPObj || (pDPObj && !GetProtection()->isOptionEnabled(ScTableProtection::PIVOT_TABLES))) - { - SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aSet(*rDocument.GetPool()); - aSet.Put(ScProtectionAttr(false)); - ScItemPoolCache aCache(rDocument.getCellAttributeHelper(), aSet); - ApplySelectionCache(aCache, rMark); - } - - SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aSet(*rDocument.GetPool()); - aSet.Put( ScProtectionAttr( false ) ); - ScItemPoolCache aCache(rDocument.getCellAttributeHelper(), aSet ); - ApplySelectionCache( aCache, rMark ); - } - // TODO: In the future we may want to check if the table has been // really modified before setting the stream invalid. SetStreamValid(false); @@ -787,20 +750,6 @@ void ScTable::CopyFromClip( pRowFlags->AndValue( j, ~CRFlags::ManualSize); } } - - // Do not set protected cell in a protected sheet - if (IsProtected() && (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)) - { - // Do not overwrite cell protection if we are in a Pivot table area and its not protected - const ScDPObject* pDPObj = rDocument.GetDPAtArea(nTab, nCol1, nRow1, nCol2, nRow2); - if (!pDPObj || (pDPObj && !GetProtection()->isOptionEnabled(ScTableProtection::PIVOT_TABLES))) - { - ScPatternAttr aPattern(rDocument.getCellAttributeHelper()); - aPattern.GetItemSet().Put(ScProtectionAttr(false)); - ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern); - } - } - // create deep copies for conditional formatting CopyConditionalFormat( nCol1, nRow1, nCol2, nRow2, nDx, nDy, pTable); } diff --git a/sc/source/filter/excel/xepivotxml.cxx b/sc/source/filter/excel/xepivotxml.cxx index ddccb1cd36f6..90f58aebc574 100644 --- a/sc/source/filter/excel/xepivotxml.cxx +++ b/sc/source/filter/excel/xepivotxml.cxx @@ -1241,25 +1241,28 @@ void XclExpXmlPivotTables::savePivotTableFormats(XclExpXmlStream& rStream, ScDPO pAttributeList->add(XML_fieldPosition, OString::number(*rFormat.oFieldPosition)); pPivotStream->startElement(XML_pivotArea, pAttributeList); } - pPivotStream->startElement(XML_references, XML_count, OString::number(rFormat.aSelections.size())); - for (sc::Selection const& rSelection : rFormat.getSelections()) + if (rFormat.aSelections.size()) { + pPivotStream->startElement(XML_references, XML_count, OString::number(rFormat.aSelections.size())); + for (sc::Selection const& rSelection : rFormat.getSelections()) { - auto pRefAttributeList = sax_fastparser::FastSerializerHelper::createAttrList(); - pRefAttributeList->add(XML_field, OString::number(sal_uInt32(rSelection.nField))); - pRefAttributeList->add(XML_count, "1"); - if (!rSelection.bSelected) // default is true - pRefAttributeList->add(XML_selected, "0"); - pPivotStream->startElement(XML_reference, pRefAttributeList); - } + { + auto pRefAttributeList = sax_fastparser::FastSerializerHelper::createAttrList(); + pRefAttributeList->add(XML_field, OString::number(sal_uInt32(rSelection.nField))); + pRefAttributeList->add(XML_count, "1"); + if (!rSelection.bSelected) // default is true + pRefAttributeList->add(XML_selected, "0"); + pPivotStream->startElement(XML_reference, pRefAttributeList); + } - for (sal_uInt32 nIndex : rSelection.nIndices) - { - pPivotStream->singleElement(XML_x, XML_v, OString::number(nIndex)); + for (sal_uInt32 nIndex : rSelection.nIndices) + { + pPivotStream->singleElement(XML_x, XML_v, OString::number(nIndex)); + } + pPivotStream->endElement(XML_reference); } - pPivotStream->endElement(XML_reference); + pPivotStream->endElement(XML_references); } - pPivotStream->endElement(XML_references); pPivotStream->endElement(XML_pivotArea); pPivotStream->endElement(XML_format); diff --git a/sc/source/filter/inc/stylesbuffer.hxx b/sc/source/filter/inc/stylesbuffer.hxx index ec6f5800cb66..95ec8b8806ff 100644 --- a/sc/source/filter/inc/stylesbuffer.hxx +++ b/sc/source/filter/inc/stylesbuffer.hxx @@ -357,11 +357,14 @@ bool operator==( const ApiProtectionData& rLeft, const ApiProtectionData& rRight class Protection : public WorkbookHelper { public: - explicit Protection( const WorkbookHelper& rHelper ); + explicit Protection( const WorkbookHelper& rHelper, bool bDxf ); /** Sets all attributes from the protection element. */ void importProtection( const AttributeList& rAttribs ); + /** Sets the protection attributes from the passed BIFF12 DXF record data. */ + void importDxfProtection( sal_Int32 nElement, SequenceInputStream& rStrm ); + /** Sets the protection attributes from the passed BIFF12 XF record data. */ void setBiff12Data( sal_uInt32 nFlags ); @@ -375,8 +378,11 @@ public: private: ProtectionModel maModel; /// Protection model data. ApiProtectionData maApiData; /// Protection data converted to API constants. + bool mbDxf; }; +typedef std::shared_ptr< Protection > ProtectionRef; + /** Contains XML attributes of a single border line. */ struct BorderLineModel { @@ -667,6 +673,8 @@ public: BorderRef const & createBorder( bool bAlwaysNew = true ); /** Creates a new empty fill object. */ FillRef const & createFill( bool bAlwaysNew = true ); + /** Creates a new empty protection object. */ + ProtectionRef const & createProtection( bool bAlwaysNew = true ); /** Inserts a new number format code. */ void importNumFmt( const AttributeList& rAttribs ); diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx index f19425c9d9dd..ab0af4cd2149 100644 --- a/sc/source/filter/oox/stylesbuffer.cxx +++ b/sc/source/filter/oox/stylesbuffer.cxx @@ -183,6 +183,8 @@ const sal_uInt16 BIFF12_DXF_FONT_HEIGHT = 36; const sal_uInt16 BIFF12_DXF_FONT_SCHEME = 37; const sal_uInt16 BIFF12_DXF_NUMFMT_CODE = 38; const sal_uInt16 BIFF12_DXF_NUMFMT_ID = 41; +const sal_uInt16 BIFF12_DXF_CELL_LOCKED = 43; +const sal_uInt16 BIFF12_DXF_CELL_HIDDEN = 44; // BIFF12 CELLSTYLE flags const sal_uInt16 BIFF12_CELLSTYLE_BUILTIN = 0x0001; @@ -1368,8 +1370,9 @@ bool operator==( const ApiProtectionData& rLeft, const ApiProtectionData& rRight (rLeft.maCellProt.IsPrintHidden == rRight.maCellProt.IsPrintHidden); } -Protection::Protection( const WorkbookHelper& rHelper ) : - WorkbookHelper( rHelper ) +Protection::Protection( const WorkbookHelper& rHelper, bool bDxf ) : + WorkbookHelper( rHelper ), + mbDxf( bDxf ) { } @@ -1379,6 +1382,23 @@ void Protection::importProtection( const AttributeList& rAttribs ) maModel.mbHidden = rAttribs.getBool( XML_hidden, false ); } +void Protection::importDxfProtection( sal_Int32 nElement, SequenceInputStream& rStrm ) +{ + SAL_WARN_IF( !mbDxf, "sc", "Protection::importDxfProtection - missing protection flag" ); + bool bFlag = rStrm.readuInt8() != 0; + switch( nElement ) + { + case XML_locked: + maModel.mbLocked = bFlag; + break; + case XML_hidden: + maModel.mbHidden = bFlag; + break; + default: + OSL_FAIL( "Protection::importDxfProtection - unexpected element identifier" ); + } +} + void Protection::setBiff12Data( sal_uInt32 nFlags ) { maModel.mbLocked = getFlag( nFlags, BIFF12_XF_LOCKED ); @@ -2005,7 +2025,7 @@ Xf::Xf( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper ), mnScNumFmt(0), maAlignment( rHelper ), - maProtection( rHelper ), + maProtection( rHelper, false ), meRotationRef( css::table::CellVertJustify2::STANDARD ), mpStyleSheet( nullptr ) { @@ -2341,6 +2361,13 @@ FillRef const & Dxf::createFill( bool bAlwaysNew ) return mxFill; } +ProtectionRef const & Dxf::createProtection( bool bAlwaysNew ) +{ + if ( bAlwaysNew || !mxProtection ) + mxProtection = std::make_shared<Protection>( *this, true ); + return mxProtection; +} + void Dxf::importNumFmt( const AttributeList& rAttribs ) { // don't propagate number formats defined in Dxf entries @@ -2391,6 +2418,8 @@ void Dxf::importDxf( SequenceInputStream& rStrm ) case BIFF12_DXF_FONT_SCHEME: createFont( false )->importDxfScheme( rStrm ); break; case BIFF12_DXF_NUMFMT_CODE: aFmtCode = BiffHelper::readString( rStrm, false ); break; case BIFF12_DXF_NUMFMT_ID: nNumFmtId = rStrm.readuInt16(); break; + case BIFF12_DXF_CELL_LOCKED: createProtection( false )->importDxfProtection( XML_locked, rStrm ); break; + case BIFF12_DXF_CELL_HIDDEN: createProtection( false )->importDxfProtection( XML_hidden, rStrm ); break; } rStrm.seek( nRecEnd ); } diff --git a/sc/source/filter/oox/stylesfragment.cxx b/sc/source/filter/oox/stylesfragment.cxx index de6312b9649c..1d20b98519ff 100644 --- a/sc/source/filter/oox/stylesfragment.cxx +++ b/sc/source/filter/oox/stylesfragment.cxx @@ -151,8 +151,8 @@ ContextHandlerRef DxfContext::onCreateContext( sal_Int32 nElement, const Attribu case XLS_TOKEN( numFmt ): mxDxf->importNumFmt( rAttribs ); break; #if 0 case XLS_TOKEN( alignment ): mxDxf->importAlignment( rAttribs ); break; - case XLS_TOKEN( protection ): mxDxf->importProtection( rAttribs ); break; #endif + case XLS_TOKEN( protection ): mxDxf->createProtection()->importProtection( rAttribs ); break; } break; @@ -163,6 +163,7 @@ ContextHandlerRef DxfContext::onCreateContext( sal_Int32 nElement, const Attribu case XLS_TOKEN( border ): return new BorderContext( *this, mxDxf->createBorder() ); case XLS_TOKEN( fill ): return new FillContext( *this, mxDxf->createFill() ); case XLS_TOKEN( numFmt ): mxDxf->importNumFmt( rAttribs ); break; + case XLS_TOKEN( protection ): mxDxf->createProtection()->importProtection( rAttribs ); break; } break; }