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;
     }

Reply via email to