include/xmloff/xmltoken.hxx | 2 sc/inc/document.hxx | 7 sc/inc/global.hxx | 5 sc/inc/table.hxx | 3 sc/qa/unit/data/xlsx/tdfSheetProts.xlsx |binary sc/qa/unit/subsequent_export_test4.cxx | 52 +++ sc/qa/unit/ucalc_pivottable.cxx | 27 ++ sc/source/core/data/documen3.cxx | 14 + sc/source/core/data/document10.cxx | 9 sc/source/core/data/table2.cxx | 38 ++ sc/source/core/data/table7.cxx | 51 ++- sc/source/filter/oox/pivottablebuffer.cxx | 3 sc/source/filter/xml/xmlexprt.cxx | 5 sc/source/filter/xml/xmlsubti.cxx | 6 sc/source/filter/xml/xmlsubti.hxx | 2 sc/source/filter/xml/xmltabi.cxx | 10 sc/source/ui/docshell/dbdocfun.cxx | 34 +- sc/source/ui/docshell/docfunc.cxx | 16 - sc/source/ui/docshell/editable.cxx | 43 ++- sc/source/ui/docshell/impex.cxx | 2 sc/source/ui/inc/editable.hxx | 21 - sc/source/ui/inc/protectiondlg.hxx | 4 sc/source/ui/miscdlgs/protectiondlg.cxx | 8 sc/source/ui/view/cellsh.cxx | 12 sc/source/ui/view/cellsh2.cxx | 63 +++- sc/source/ui/view/gridwin.cxx | 20 + sc/source/ui/view/pivotsh.cxx | 14 - sc/uiconfig/scalc/ui/protectsheetdlg.ui | 160 ++++++------ schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng | 10 xmloff/source/core/xmltoken.cxx | 2 xmloff/source/token/tokens.txt | 2 31 files changed, 469 insertions(+), 176 deletions(-)
New commits: commit 83910246044c1e05a3b50e25d21ac6a31566cc38 Author: Balazs Varga <[email protected]> AuthorDate: Wed Nov 6 21:33:46 2024 +0100 Commit: Balazs Varga <[email protected]> CommitDate: Thu Nov 14 23:53:24 2024 +0100 tdf#160404 tdf#160535 tdf#160536 - sc improve sheet protection tdf#160404: Fix FILEOPEN XLSX Pivot table is not imported if sheet protection has Pivot table editing enabled - Import correctly the pivot tables, even if the tab protection is not allowing to use them. tdf#160535: Support sheet protection option: Use AutoFilter - Add new option for tab protection to enable/disable to use autofilter on the sheet. Import/export correctly to odf/ooxml. Add new ext-odf attribute: XML_USE_AUTOFILTER tdf#160536: Support sheet protection option: Use PivotTable&PivotChart - Add new option for tab protection to enable/disable to use Pivot table on the sheet. Import/export correctly to odf/ooxml. Add new ext-odf attribute: XML_USE_PIVOT Change-Id: I5d34e3608aed1a3d004ec553f6125b6428e9c05e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176274 Tested-by: Jenkins Reviewed-by: Balazs Varga <[email protected]> diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index cd61d4d3c065..574beaced5e5 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -2095,6 +2095,7 @@ namespace xmloff::token { XML_UPRIGHT, XML_URL, XML_USE, + XML_USE_AUTOFILTER, XML_USE_CAPTION, XML_USE_CELL_PROTECTION, XML_USE_CHART_OBJECTS, @@ -2112,6 +2113,7 @@ namespace xmloff::token { XML_USE_OPTIMAL_COLUMN_WIDTH, XML_USE_OPTIMAL_ROW_HEIGHT, XML_USE_OTHER_OBJECTS, + XML_USE_PIVOT, XML_USE_SPREADSHEET_OBJECTS, XML_USE_STYLES, XML_USE_TABLES, diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 7caa75d7db1e..9f9a79eb024f 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -934,6 +934,7 @@ public: SC_DLLPUBLIC bool HasPivotTable() const; SC_DLLPUBLIC ScDPCollection* GetDPCollection(); SC_DLLPUBLIC const ScDPCollection* GetDPCollection() const; + SC_DLLPUBLIC const ScDPObject* GetDPAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const; SC_DLLPUBLIC ScDPObject* GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const; SC_DLLPUBLIC ScDPObject* GetDPAtCursor(ScAddress const& rAddress) const { @@ -1040,8 +1041,10 @@ public: SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ) const; - bool IsEditActionAllowed( sc::ColRowEditAction eAction, SCTAB nTab, SCCOLROW nStart, SCCOLROW nEnd ) const; - bool IsEditActionAllowed( sc::ColRowEditAction eAction, const ScMarkData& rMark, SCCOLROW nStart, SCCOLROW nEnd ) const; + bool IsEditActionAllowed( sc::EditAction eAction, SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow ) const; + bool IsEditActionAllowed( sc::EditAction eAction, const ScMarkData& rMark, SCCOL nStartCol, + SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const; SC_DLLPUBLIC bool GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix ); diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index 79d24030179b..616930567210 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -425,7 +425,7 @@ enum ScDBObject namespace sc { -enum class ColRowEditAction +enum class EditAction { Unknown, InsertColumnsBefore, @@ -433,7 +433,8 @@ enum class ColRowEditAction InsertRowsBefore, InsertRowsAfter, DeleteColumns, - DeleteRows + DeleteRows, + UpdatePivotTable }; } diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index c1dfb716b595..5f36e5d9d5c7 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -409,7 +409,8 @@ public: const ScTableProtection* GetProtection() const; void GetUnprotectedCells( ScRangeList& rRangeList ) const; - bool IsEditActionAllowed( sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd ) const; + bool IsEditActionAllowed( sc::EditAction eAction, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow ) const; Size GetPageSize() const; void SetPageSize( const Size& rSize ); diff --git a/sc/qa/unit/data/xlsx/tdfSheetProts.xlsx b/sc/qa/unit/data/xlsx/tdfSheetProts.xlsx new file mode 100644 index 000000000000..ffd9fe127840 Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdfSheetProts.xlsx differ diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx index ae856010b110..fae430bbe6f1 100644 --- a/sc/qa/unit/subsequent_export_test4.cxx +++ b/sc/qa/unit/subsequent_export_test4.cxx @@ -24,6 +24,8 @@ #include <dbdata.hxx> #include <subtotalparam.hxx> #include <globstr.hrc> +#include <tabprotection.hxx> +#include <dpobject.hxx> #include <editeng/wghtitem.hxx> #include <editeng/postitem.hxx> @@ -2061,6 +2063,56 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testNotesAuthor) pBatch->commit(); } +CPPUNIT_TEST_FIXTURE(ScExportTest4, testSheetProtections) +{ + auto verify = [this]() { + ScDocument* pDoc = getScDoc(); + + // 1. tab autofilter allowed, pivot tables not allowed + const ScTableProtection* pTab1Protect = pDoc->GetTabProtection(0); + CPPUNIT_ASSERT(pTab1Protect); + CPPUNIT_ASSERT(pTab1Protect->isOptionEnabled(ScTableProtection::AUTOFILTER)); + CPPUNIT_ASSERT(!pTab1Protect->isOptionEnabled(ScTableProtection::PIVOT_TABLES)); + + // 2. tab autofilter NOT allowed, pivot tables allowed + const ScTableProtection* pTab2Protect = pDoc->GetTabProtection(1); + CPPUNIT_ASSERT(pTab2Protect); + CPPUNIT_ASSERT(!pTab2Protect->isOptionEnabled(ScTableProtection::AUTOFILTER)); + CPPUNIT_ASSERT(pTab2Protect->isOptionEnabled(ScTableProtection::PIVOT_TABLES)); + + // check we have pivot table + ScDPObject* pDPObj1 = pDoc->GetDPAtCursor(0, 0, 1); + CPPUNIT_ASSERT(pDPObj1); + CPPUNIT_ASSERT(!pDPObj1->GetName().isEmpty()); + + // 3. tab autofilter NOT allowed, pivot tables not allowed + const ScTableProtection* pTab3Protect = pDoc->GetTabProtection(2); + CPPUNIT_ASSERT(pTab3Protect); + CPPUNIT_ASSERT(!pTab3Protect->isOptionEnabled(ScTableProtection::AUTOFILTER)); + CPPUNIT_ASSERT(!pTab3Protect->isOptionEnabled(ScTableProtection::PIVOT_TABLES)); + + // 4. tab autofilter allowed, pivot tables not allowed + const ScTableProtection* pTab4Protect = pDoc->GetTabProtection(3); + CPPUNIT_ASSERT(pTab4Protect); + CPPUNIT_ASSERT(pTab4Protect->isOptionEnabled(ScTableProtection::AUTOFILTER)); + CPPUNIT_ASSERT(!pTab4Protect->isOptionEnabled(ScTableProtection::PIVOT_TABLES)); + + // check we have pivot table + ScDPObject* pDPObj2 = pDoc->GetDPAtCursor(0, 0, 3); + CPPUNIT_ASSERT(pDPObj2); + CPPUNIT_ASSERT(!pDPObj2->GetName().isEmpty()); + }; + + createScDoc("xlsx/tdfSheetProts.xlsx"); + verify(); + + saveAndReload(u"Calc Office Open XML"_ustr); + verify(); + + saveAndReload(u"calc8"_ustr); + verify(); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/ucalc_pivottable.cxx b/sc/qa/unit/ucalc_pivottable.cxx index 594d7a7e1265..9517826423bf 100644 --- a/sc/qa/unit/ucalc_pivottable.cxx +++ b/sc/qa/unit/ucalc_pivottable.cxx @@ -17,6 +17,7 @@ #include <stringutil.hxx> #include <dbdocfun.hxx> #include <generalfunction.hxx> +#include <tabprotection.hxx> #include <formula/errorcodes.hxx> #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> @@ -2115,6 +2116,32 @@ CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableDocFunc) CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess); } + // Start: Test Pivot table with tab protection + ScTableProtection aProtect; + aProtect.setProtected(true); + m_pDoc->SetTabProtection(1, &aProtect); + + bSuccess = aFunc.RemovePivotTable(*pDPObject, false, true); + CPPUNIT_ASSERT_MESSAGE("Pivot table should not be allowed to remove.", !bSuccess); + + bSuccess = aFunc.UpdatePivotTable(*pDPObject, false, true); + CPPUNIT_ASSERT_MESSAGE("Pivot table should not be allowed to update.", !bSuccess); + + // Allow pivot table usage + aProtect.setOption(ScTableProtection::PIVOT_TABLES, true); + m_pDoc->SetTabProtection(1, &aProtect); + + bSuccess = aFunc.RemovePivotTable(*pDPObject, false, true); + CPPUNIT_ASSERT_MESSAGE("Pivot table should not be allowed to remove.", !bSuccess); + + bSuccess = aFunc.UpdatePivotTable(*pDPObject, false, true); + CPPUNIT_ASSERT_MESSAGE("Pivot table should be allowed to update.", bSuccess); + + aProtect.setProtected(false); + aProtect.setOption(ScTableProtection::PIVOT_TABLES, false); + m_pDoc->SetTabProtection(1, &aProtect); + // End: Test Pivot table with tab protection + // Remove this pivot table output. This should also clear the pivot cache // it was referencing. bSuccess = aFunc.RemovePivotTable(*pDPObject, false, true); diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 1ef2b40530d5..788f16a135d9 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -379,6 +379,20 @@ const ScDPCollection* ScDocument::GetDPCollection() const return pDPCollection.get(); } +const ScDPObject* ScDocument::GetDPAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const +{ + if (!pDPCollection) + return nullptr; + + sal_uInt16 nCount = pDPCollection->GetCount(); + ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab); + for (sal_uInt16 i = 0; i < nCount; i++) + if ((*pDPCollection)[i].GetOutRange() == aRange) + return &(*pDPCollection)[i]; + + return nullptr; +} + ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const { if (!pDPCollection) diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index 74716ce93dd7..4c6527304a7e 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -961,20 +961,21 @@ bool ScDocument::CopyAdjustRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRange } bool ScDocument::IsEditActionAllowed( - sc::ColRowEditAction eAction, SCTAB nTab, SCCOLROW nStart, SCCOLROW nEnd ) const + sc::EditAction eAction, SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const { const ScTable* pTab = FetchTable(nTab); if (!pTab) return false; - return pTab->IsEditActionAllowed(eAction, nStart, nEnd); + return pTab->IsEditActionAllowed(eAction, nStartCol, nStartRow, nEndCol, nEndRow); } bool ScDocument::IsEditActionAllowed( - sc::ColRowEditAction eAction, const ScMarkData& rMark, SCCOLROW nStart, SCCOLROW nEnd ) const + sc::EditAction eAction, const ScMarkData& rMark, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const { return std::all_of(rMark.begin(), rMark.end(), - [this, &eAction, &nStart, &nEnd](const SCTAB& rTab) { return IsEditActionAllowed(eAction, rTab, nStart, nEnd); }); + [this, &eAction, &nStartCol, &nStartRow, &nEndCol, &nEndRow](const SCTAB& rTab) + { return IsEditActionAllowed(eAction, rTab, nStartCol, nStartRow, nEndCol, nEndRow); }); } std::optional<sc::ColumnIterator> ScDocument::GetColumnIterator( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 933b9a37930e..4321a27893a5 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -52,6 +52,7 @@ #include <compressedarray.hxx> #include <refdata.hxx> #include <docsh.hxx> +#include <dpobject.hxx> #include <scitems.hxx> #include <editeng/boxitem.hxx> @@ -436,9 +437,14 @@ void ScTable::DeleteArea( if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) ) { - ScPatternAttr aPattern(rDocument.getCellAttributeHelper()); - aPattern.GetItemSet().Put( ScProtectionAttr( false ) ); - ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern ); + // 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); + } } if( nDelFlag & InsertDeleteFlags::ATTRIB ) @@ -473,6 +479,18 @@ void ScTable::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMa if ( IsProtected() && (nDelFlag & InsertDeleteFlags::ATTRIB) ) { + // Do not overwrite cell protection if we are in a Pivot table area and its 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 ); @@ -773,9 +791,14 @@ void ScTable::CopyFromClip( // Do not set protected cell in a protected sheet if (IsProtected() && (rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB)) { - ScPatternAttr aPattern(rDocument.getCellAttributeHelper()); - aPattern.GetItemSet().Put( ScProtectionAttr( false ) ); - ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern ); + // 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 @@ -2709,8 +2732,7 @@ bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, if (!bIsEditable) { // An enhanced protection permission may override the attribute. - if (pTabProtection) - bIsEditable = pTabProtection->isBlockEditable( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab)); + bIsEditable = pTabProtection->isBlockEditable( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab)); } if (bIsEditable) { diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index b1aab8dc2052..c41dcf9464a1 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -339,8 +339,8 @@ void ScTable::SetNeedsListeningGroup( SCCOL nCol, SCROW nRow ) CreateColumnIfNotExists(nCol).SetNeedsListeningGroup(nRow); } -bool ScTable::IsEditActionAllowed( - sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd ) const +bool ScTable::IsEditActionAllowed( sc::EditAction eAction, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow ) const { if (!IsProtected()) { @@ -349,20 +349,20 @@ bool ScTable::IsEditActionAllowed( switch (eAction) { - case sc::ColRowEditAction::InsertColumnsBefore: - case sc::ColRowEditAction::InsertColumnsAfter: - case sc::ColRowEditAction::DeleteColumns: + case sc::EditAction::InsertColumnsBefore: + case sc::EditAction::InsertColumnsAfter: + case sc::EditAction::DeleteColumns: { - nCol1 = nStart; - nCol2 = nEnd; + nCol1 = nStartCol; + nCol2 = nEndCol; break; } - case sc::ColRowEditAction::InsertRowsBefore: - case sc::ColRowEditAction::InsertRowsAfter: - case sc::ColRowEditAction::DeleteRows: + case sc::EditAction::InsertRowsBefore: + case sc::EditAction::InsertRowsAfter: + case sc::EditAction::DeleteRows: { - nRow1 = nStart; - nRow2 = nEnd; + nRow1 = nStartRow; + nRow2 = nEndRow; break; } default: @@ -381,37 +381,44 @@ bool ScTable::IsEditActionAllowed( switch (eAction) { - case sc::ColRowEditAction::InsertColumnsBefore: - case sc::ColRowEditAction::InsertColumnsAfter: + case sc::EditAction::InsertColumnsBefore: + case sc::EditAction::InsertColumnsAfter: { // TODO: improve the matrix range handling for the insert-before action. - if (HasBlockMatrixFragment(nStart, 0, nEnd, rDocument.MaxRow())) + if (HasBlockMatrixFragment(nStartCol, nStartRow, nEndCol, nEndRow)) return false; return pTabProtection->isOptionEnabled(ScTableProtection::INSERT_COLUMNS); } - case sc::ColRowEditAction::InsertRowsBefore: - case sc::ColRowEditAction::InsertRowsAfter: + case sc::EditAction::InsertRowsBefore: + case sc::EditAction::InsertRowsAfter: { // TODO: improve the matrix range handling for the insert-before action. - if (HasBlockMatrixFragment(0, nStart, rDocument.MaxCol(), nEnd)) + if (HasBlockMatrixFragment(nStartCol, nStartRow, nEndCol, nEndRow)) return false; return pTabProtection->isOptionEnabled(ScTableProtection::INSERT_ROWS); } - case sc::ColRowEditAction::DeleteColumns: + case sc::EditAction::DeleteColumns: { if (!pTabProtection->isOptionEnabled(ScTableProtection::DELETE_COLUMNS)) return false; - return !HasAttrib(nStart, 0, nEnd, rDocument.MaxRow(), HasAttrFlags::Protected); + return !HasAttrib(nStartCol, nStartRow, nEndCol, nEndRow, HasAttrFlags::Protected); } - case sc::ColRowEditAction::DeleteRows: + case sc::EditAction::DeleteRows: { if (!pTabProtection->isOptionEnabled(ScTableProtection::DELETE_ROWS)) return false; - return !HasAttrib(0, nStart, rDocument.MaxCol(), nEnd, HasAttrFlags::Protected); + return !HasAttrib(nStartCol, nStartRow, nEndCol, nEndRow, HasAttrFlags::Protected); + } + case sc::EditAction::UpdatePivotTable: + { + if (pTabProtection->isOptionEnabled(ScTableProtection::PIVOT_TABLES)) + return true; + + return !HasAttrib(nStartCol, nStartRow, nEndCol, nEndRow, HasAttrFlags::Protected); } default: ; diff --git a/sc/source/filter/oox/pivottablebuffer.cxx b/sc/source/filter/oox/pivottablebuffer.cxx index 249176cf2b7b..f128e27afd0e 100644 --- a/sc/source/filter/oox/pivottablebuffer.cxx +++ b/sc/source/filter/oox/pivottablebuffer.cxx @@ -1355,7 +1355,10 @@ void PivotTable::finalizeImport() mpDPObject->PutInteropGrabBag(std::move(maInteropGrabBag)); // insert the DataPilot table into the sheet + ScDocument& rDoc = getDocImport().getDoc(); + rDoc.SetImportingXML(true); xDPTables->insertNewByName( maDefModel.maName, aPos, mxDPDescriptor ); + rDoc.SetImportingXML(false); } catch( Exception& ) { diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index 19722fe6bbd8..2ca445ba2a1f 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -2907,6 +2907,11 @@ void ScXMLExport::WriteTable(sal_Int32 nTable, const uno::Reference<sheet::XSpre if (pProtect->isOptionEnabled(ScTableProtection::DELETE_ROWS)) AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_ROWS, XML_TRUE); + if (pProtect->isOptionEnabled(ScTableProtection::AUTOFILTER)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_USE_AUTOFILTER, XML_TRUE); + if (pProtect->isOptionEnabled(ScTableProtection::PIVOT_TABLES)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_USE_PIVOT, XML_TRUE); + OUString aElemName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_LO_EXT, GetXMLToken(XML_TABLE_PROTECTION)); diff --git a/sc/source/filter/xml/xmlsubti.cxx b/sc/source/filter/xml/xmlsubti.cxx index 0d865721b930..02cd36264ccb 100644 --- a/sc/source/filter/xml/xmlsubti.cxx +++ b/sc/source/filter/xml/xmlsubti.cxx @@ -49,7 +49,9 @@ ScXMLTabProtectionData::ScXMLTabProtectionData() : mbInsertColumns(false), mbInsertRows(false), mbDeleteColumns(false), - mbDeleteRows(false) + mbDeleteRows(false), + mbUseAutoFilter(false), + mbUsePivot(false) { } @@ -208,6 +210,8 @@ void ScMyTables::DeleteTable() aProtect.setOption(ScTableProtection::INSERT_ROWS, maProtectionData.mbInsertRows); aProtect.setOption(ScTableProtection::DELETE_COLUMNS, maProtectionData.mbDeleteColumns); aProtect.setOption(ScTableProtection::DELETE_ROWS, maProtectionData.mbDeleteRows); + aProtect.setOption(ScTableProtection::AUTOFILTER, maProtectionData.mbUseAutoFilter); + aProtect.setOption(ScTableProtection::PIVOT_TABLES, maProtectionData.mbUsePivot); rImport.GetDocument()->SetTabProtection(maCurrentCellPos.Tab(), &aProtect); } diff --git a/sc/source/filter/xml/xmlsubti.hxx b/sc/source/filter/xml/xmlsubti.hxx index 49e148b3db16..b5ccc4261600 100644 --- a/sc/source/filter/xml/xmlsubti.hxx +++ b/sc/source/filter/xml/xmlsubti.hxx @@ -42,6 +42,8 @@ struct ScXMLTabProtectionData bool mbInsertRows; bool mbDeleteColumns; bool mbDeleteRows; + bool mbUseAutoFilter; + bool mbUsePivot; ScXMLTabProtectionData(); }; diff --git a/sc/source/filter/xml/xmltabi.cxx b/sc/source/filter/xml/xmltabi.cxx index af4ba33d3c6f..5010c70b5e11 100644 --- a/sc/source/filter/xml/xmltabi.cxx +++ b/sc/source/filter/xml/xmltabi.cxx @@ -417,6 +417,8 @@ ScXMLTableProtectionContext::ScXMLTableProtectionContext( bool bInsertRows = false; bool bDeleteColumns = false; bool bDeleteRows = false; + bool bUseAutoFilter = false; + bool bUsePivot = false; if ( rAttrList.is() ) { @@ -447,6 +449,12 @@ ScXMLTableProtectionContext::ScXMLTableProtectionContext( case XML_ELEMENT( LO_EXT, XML_DELETE_ROWS ): bDeleteRows = IsXMLToken(aIter, XML_TRUE); break; + case XML_ELEMENT( LO_EXT, XML_USE_AUTOFILTER ): + bUseAutoFilter = IsXMLToken(aIter, XML_TRUE); + break; + case XML_ELEMENT( LO_EXT, XML_USE_PIVOT ): + bUsePivot = IsXMLToken(aIter, XML_TRUE); + break; default: XMLOFF_WARN_UNKNOWN("sc", aIter); } @@ -460,6 +468,8 @@ ScXMLTableProtectionContext::ScXMLTableProtectionContext( rProtectData.mbInsertRows = bInsertRows; rProtectData.mbDeleteColumns = bDeleteColumns; rProtectData.mbDeleteRows = bDeleteRows; + rProtectData.mbUseAutoFilter = bUseAutoFilter; + rProtectData.mbUsePivot = bUsePivot; } ScXMLTableProtectionContext::~ScXMLTableProtectionContext() diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx index cb7ffe31e9e0..1ded38ed6eda 100644 --- a/sc/source/ui/docshell/dbdocfun.cxx +++ b/sc/source/ui/docshell/dbdocfun.cxx @@ -1213,7 +1213,8 @@ bool lcl_EmptyExcept( ScDocument& rDoc, const ScRange& rRange, const ScRange& rE return true; // nothing found - empty } -bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi) +bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi, + sc::EditAction eAction = sc::EditAction::Unknown) { ScDocument& rDoc = rDocShell.GetDocument(); if (!rDocShell.IsEditable() || rDoc.GetChangeTrack()) @@ -1228,7 +1229,7 @@ bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi) for (size_t i = 0, n = rRanges.size(); i < n; ++i) { const ScRange & r = rRanges[i]; - ScEditableTester aTester(rDoc, r); + ScEditableTester aTester(rDoc, r, eAction); if (!aTester.IsEditable()) { if (!bApi) @@ -1249,7 +1250,8 @@ void createUndoDoc(ScDocumentUniquePtr& pUndoDoc, ScDocument& rDoc, const ScRang rDoc.CopyToDocument(rRange, InsertDeleteFlags::ALL, false, *pUndoDoc); } -bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi) +bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi, + sc::EditAction eAction = sc::EditAction::Unknown) { ScDocument& rDoc = rDocShell.GetDocument(); @@ -1279,14 +1281,17 @@ bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNe return false; } - ScEditableTester aTester(rDoc, rNewOut); - if (!aTester.IsEditable()) + if (!rDoc.IsImportingXML()) { - // destination area isn't editable - if (!bApi) - rDocShell.ErrorMessage(aTester.GetMessageId()); + ScEditableTester aTester(rDoc, rNewOut, eAction); + if (!aTester.IsEditable()) + { + // destination area isn't editable + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); - return false; + return false; + } } return true; @@ -1484,12 +1489,12 @@ bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool weld::WaitObject aWait(ScDocShell::GetActiveDialogParent()); // At least one cell in the output range should be editable. Check in advance. - if (!isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi)) + ScDocument& rDoc = rDocShell.GetDocument(); + if (!rDoc.IsImportingXML() && !isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi)) return false; ScDocumentUniquePtr pNewUndoDoc; - ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; @@ -1537,8 +1542,9 @@ bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool return false; } + if (!rDoc.IsImportingXML()) { - ScEditableTester aTester(rDoc, aNewOut); + ScEditableTester aTester(rDoc, aNewOut, sc::EditAction::Unknown); if (!aTester.IsEditable()) { // destination area isn't editable @@ -1594,7 +1600,7 @@ bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi) ScDocShellModificator aModificator( rDocShell ); weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); - if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi)) + if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi, sc::EditAction::UpdatePivotTable)) return false; ScDocumentUniquePtr pOldUndoDoc; @@ -1621,7 +1627,7 @@ bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi) rDPObj.SetName( rDoc.GetDPCollection()->CreateNewName() ); ScRange aNewOut; - if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi)) + if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi, sc::EditAction::UpdatePivotTable)) { rDPObj = aUndoDPObj; return false; diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 0b16439f29cf..dccbb6d224e7 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -1904,19 +1904,19 @@ bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, { case INS_INSCOLS_BEFORE: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::InsertColumnsBefore, nMergeTestStartCol, nMergeTestEndCol, aMark); + rDoc, sc::EditAction::InsertColumnsBefore, nMergeTestStartCol, 0, nMergeTestEndCol, rDoc.MaxRow(), aMark); break; case INS_INSCOLS_AFTER: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::InsertColumnsAfter, nMergeTestStartCol, nMergeTestEndCol, aMark); + rDoc, sc::EditAction::InsertColumnsAfter, nMergeTestStartCol, 0, nMergeTestEndCol, rDoc.MaxRow(), aMark); break; case INS_INSROWS_BEFORE: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::InsertRowsBefore, nMergeTestStartRow, nMergeTestEndRow, aMark); + rDoc, sc::EditAction::InsertRowsBefore, 0, nMergeTestStartRow, rDoc.MaxCol(), nMergeTestEndRow, aMark); break; case INS_INSROWS_AFTER: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::InsertRowsAfter, nMergeTestStartRow, nMergeTestEndRow, aMark); + rDoc, sc::EditAction::InsertRowsAfter, 0, nMergeTestStartRow, rDoc.MaxCol(), nMergeTestEndRow, aMark); break; default: aTester = ScEditableTester( @@ -2406,11 +2406,11 @@ bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, { case DelCellCmd::Cols: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::DeleteColumns, nUndoStartCol, nUndoEndCol, aMark); + rDoc, sc::EditAction::DeleteColumns, nUndoStartCol, 0, nUndoEndCol, rDoc.MaxRow(), aMark); break; case DelCellCmd::Rows: aTester = ScEditableTester( - rDoc, sc::ColRowEditAction::DeleteRows, nUndoStartRow, nUndoEndRow, aMark); + rDoc, sc::EditAction::DeleteRows, 0, nUndoStartRow, rDoc.MaxCol(), nUndoEndRow, aMark); break; default: aTester = ScEditableTester( @@ -4890,7 +4890,7 @@ bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir e //! Source range can be protected !!! //! but can't contain matrix fragments !!! - ScEditableTester aTester( rDoc, aDestArea ); + ScEditableTester aTester( rDoc, aDestArea, sc::EditAction::Unknown ); if ( !aTester.IsEditable() ) { if (!bApi) @@ -5743,7 +5743,7 @@ void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bInteraction if (!rDoc.IsUndoEnabled()) bRecord = false; - ScEditableTester aTester(rDoc, rRange); + ScEditableTester aTester(rDoc, rRange, sc::EditAction::Unknown); if (!aTester.IsEditable()) { if (bInteraction) diff --git a/sc/source/ui/docshell/editable.cxx b/sc/source/ui/docshell/editable.cxx index 86bbb9f2e004..357897470aa1 100644 --- a/sc/source/ui/docshell/editable.cxx +++ b/sc/source/ui/docshell/editable.cxx @@ -45,11 +45,14 @@ ScEditableTester::ScEditableTester( const ScDocument& rDoc, TestSelectedBlock( rDoc, nStartCol, nStartRow, nEndCol, nEndRow, rMark ); } -ScEditableTester::ScEditableTester( const ScDocument& rDoc, const ScRange& rRange ) : +ScEditableTester::ScEditableTester( const ScDocument& rDoc, const ScRange& rRange, sc::EditAction eAction ) : mbIsEditable(true), mbOnlyMatrix(true) { - TestRange( rDoc, rRange ); + if (eAction == sc::EditAction::Unknown) + TestRange(rDoc, rRange); + else + TestRangeForAction( rDoc, rRange, eAction ); } ScEditableTester::ScEditableTester( const ScDocument& rDoc, const ScMarkData& rMark ) : @@ -73,10 +76,11 @@ ScEditableTester::ScEditableTester( ScViewFunc* pView ) : } ScEditableTester::ScEditableTester( - const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd, const ScMarkData& rMark ) : + const ScDocument& rDoc, sc::EditAction eAction, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ) : ScEditableTester() { - TestBlockForAction(rDoc, eAction, nStart, nEnd, rMark); + TestBlockForAction(rDoc, eAction, nStartCol, nStartRow, nEndCol, nEndRow, rMark); } void ScEditableTester::TestBlock( const ScDocument& rDoc, SCTAB nTab, @@ -85,7 +89,7 @@ void ScEditableTester::TestBlock( const ScDocument& rDoc, SCTAB nTab, if (mbIsEditable || mbOnlyMatrix) { bool bThisMatrix; - if (!rDoc.IsBlockEditable( nTab, nStartCol, nStartRow, nEndCol, nEndRow, &bThisMatrix, bNoMatrixAtAll)) + if (!rDoc.IsBlockEditable( nTab, nStartCol, nStartRow, nEndCol, nEndRow, &bThisMatrix, bNoMatrixAtAll )) { mbIsEditable = false; if ( !bThisMatrix ) @@ -94,6 +98,15 @@ void ScEditableTester::TestBlock( const ScDocument& rDoc, SCTAB nTab, } } +void ScEditableTester::TestBlockForAction( const ScDocument& rDoc, SCTAB nTab, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, sc::EditAction eAction ) +{ + if (mbIsEditable || mbOnlyMatrix) + { + mbIsEditable = rDoc.IsEditActionAllowed(eAction, nTab, nStartCol, nStartRow, nEndCol, nEndRow); + } +} + void ScEditableTester::TestSelectedBlock( const ScDocument& rDoc, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ) @@ -108,7 +121,7 @@ void ScEditableTester::TestSelectedBlock( const ScDocument& rDoc, } } -void ScEditableTester::TestRange( const ScDocument& rDoc, const ScRange& rRange ) +void ScEditableTester::TestRange( const ScDocument& rDoc, const ScRange& rRange ) { SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); @@ -120,6 +133,18 @@ void ScEditableTester::TestRange( const ScDocument& rDoc, const ScRange& rRange TestBlock( rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, false ); } +void ScEditableTester::TestRangeForAction(const ScDocument& rDoc, const ScRange& rRange, sc::EditAction eAction) +{ + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++) + TestBlockForAction(rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, eAction); +} + void ScEditableTester::TestSelection( const ScDocument& rDoc, const ScMarkData& rMark ) { if (mbIsEditable || mbOnlyMatrix) @@ -135,8 +160,8 @@ void ScEditableTester::TestSelection( const ScDocument& rDoc, const ScMarkData& } void ScEditableTester::TestBlockForAction( - const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd, - const ScMarkData& rMark ) + const ScDocument& rDoc, sc::EditAction eAction, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ) { mbOnlyMatrix = false; @@ -145,7 +170,7 @@ void ScEditableTester::TestBlockForAction( if (!mbIsEditable) return; - mbIsEditable = rDoc.IsEditActionAllowed(eAction, rTab, nStart, nEnd); + mbIsEditable = rDoc.IsEditActionAllowed(eAction, rTab, nStartCol, nStartRow, nEndCol, nEndRow); } } diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx index 5bb6fb343ca4..b7a27b5b6711 100644 --- a/sc/source/ui/docshell/impex.cxx +++ b/sc/source/ui/docshell/impex.cxx @@ -230,7 +230,7 @@ bool ScImportExport::StartPaste() { if ( !bAll ) { - ScEditableTester aTester( rDoc, aRange ); + ScEditableTester aTester( rDoc, aRange, sc::EditAction::Unknown ); if ( !aTester.IsEditable() ) { std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(), diff --git a/sc/source/ui/inc/editable.hxx b/sc/source/ui/inc/editable.hxx index 1c229a1b11ef..c5deab9ae699 100644 --- a/sc/source/ui/inc/editable.hxx +++ b/sc/source/ui/inc/editable.hxx @@ -28,7 +28,7 @@ class ScMarkData; namespace sc { -enum class ColRowEditAction; +enum class EditAction; } @@ -54,7 +54,7 @@ public: const ScMarkData& rMark ); // calls TestRange - ScEditableTester( const ScDocument& rDoc, const ScRange& rRange ); + ScEditableTester( const ScDocument& rDoc, const ScRange& rRange, sc::EditAction eAction ); // calls TestSelection ScEditableTester( const ScDocument& rDoc, const ScMarkData& rMark ); @@ -62,24 +62,29 @@ public: // calls TestView ScEditableTester( ScViewFunc* pView ); - ScEditableTester( - const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd, - const ScMarkData& rMark ); + ScEditableTester( + const ScDocument& rDoc, sc::EditAction eAction, SCCOL nStartCol, + SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ); // Several calls to the Test... methods check if *all* of the ranges // are editable. For several independent checks, Reset() has to be used. void TestBlock( const ScDocument& rDoc, SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bNoMatrixAtAll = false ); + void TestBlockForAction( const ScDocument& rDoc, SCTAB nTab, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, + sc::EditAction eAction ); void TestSelectedBlock( const ScDocument& rDoc, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ); void TestRange( const ScDocument& rDoc, const ScRange& rRange ); + void TestRangeForAction( const ScDocument& rDoc, const ScRange& rRange, + sc::EditAction eAction ); void TestSelection( const ScDocument& rDoc, const ScMarkData& rMark ); - void TestBlockForAction( - const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd, - const ScMarkData& rMark ); + void TestBlockForAction( + const ScDocument& rDoc, sc::EditAction eAction, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, const ScMarkData& rMark ); bool IsEditable() const { return mbIsEditable; } bool IsFormatEditable() const { return mbIsEditable || mbOnlyMatrix; } diff --git a/sc/source/ui/inc/protectiondlg.hxx b/sc/source/ui/inc/protectiondlg.hxx index e59fb3accf77..4ad633cbd6d5 100644 --- a/sc/source/ui/inc/protectiondlg.hxx +++ b/sc/source/ui/inc/protectiondlg.hxx @@ -45,6 +45,8 @@ private: OUString m_aInsertRows; OUString m_aDeleteColumns; OUString m_aDeleteRows; + OUString m_aAutoFilter; + OUString m_aPivot; std::unique_ptr<weld::CheckButton> m_xBtnProtect; std::unique_ptr<weld::Container> m_xPasswords; @@ -60,6 +62,8 @@ private: std::unique_ptr<weld::Label> m_xInsertRows; std::unique_ptr<weld::Label> m_xDeleteColumns; std::unique_ptr<weld::Label> m_xDeleteRows; + std::unique_ptr<weld::Label> m_xAutoFilter; + std::unique_ptr<weld::Label> m_xPivot; void InsertEntry(const OUString& rTxt); diff --git a/sc/source/ui/miscdlgs/protectiondlg.cxx b/sc/source/ui/miscdlgs/protectiondlg.cxx index f96cc72c0346..041f50dfa0db 100644 --- a/sc/source/ui/miscdlgs/protectiondlg.cxx +++ b/sc/source/ui/miscdlgs/protectiondlg.cxx @@ -33,6 +33,8 @@ const std::vector<ScTableProtection::Option> aOptions = { ScTableProtection::INSERT_ROWS, ScTableProtection::DELETE_COLUMNS, ScTableProtection::DELETE_ROWS, + ScTableProtection::AUTOFILTER, + ScTableProtection::PIVOT_TABLES, }; } @@ -53,6 +55,8 @@ ScTableProtectionDlg::ScTableProtectionDlg(weld::Window* pParent) , m_xInsertRows(m_xBuilder->weld_label(u"insert-rows"_ustr)) , m_xDeleteColumns(m_xBuilder->weld_label(u"delete-columns"_ustr)) , m_xDeleteRows(m_xBuilder->weld_label(u"delete-rows"_ustr)) + , m_xAutoFilter(m_xBuilder->weld_label(u"useautofilter"_ustr)) + , m_xPivot(m_xBuilder->weld_label(u"usepivot"_ustr)) { m_aSelectLockedCells = m_xProtected->get_label(); m_aSelectUnlockedCells = m_xUnprotected->get_label(); @@ -60,6 +64,8 @@ ScTableProtectionDlg::ScTableProtectionDlg(weld::Window* pParent) m_aInsertRows = m_xInsertRows->get_label(); m_aDeleteColumns = m_xDeleteColumns->get_label(); m_aDeleteRows = m_xDeleteRows->get_label(); + m_aAutoFilter = m_xAutoFilter->get_label(); + m_aPivot = m_xPivot->get_label(); m_xOptionsListBox->enable_toggle_buttons(weld::ColumnToggleType::Check); @@ -114,6 +120,8 @@ void ScTableProtectionDlg::Init() InsertEntry(m_aInsertRows); InsertEntry(m_aDeleteColumns); InsertEntry(m_aDeleteRows); + InsertEntry(m_aAutoFilter); + InsertEntry(m_aPivot); m_xOptionsListBox->set_toggle(0, TRISTATE_TRUE); m_xOptionsListBox->set_toggle(1, TRISTATE_TRUE); diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx index f1ff35b5a379..f18c6ceb30e5 100644 --- a/sc/source/ui/view/cellsh.cxx +++ b/sc/source/ui/view/cellsh.cxx @@ -256,15 +256,15 @@ void ScCellShell::GetBlockState( SfxItemSet& rSet ) case FID_INS_ROWS_BEFORE: // insert rows case FID_INS_ROWS_AFTER: { - sc::ColRowEditAction eAction = sc::ColRowEditAction::InsertRowsBefore; + sc::EditAction eAction = sc::EditAction::InsertRowsBefore; if (nWhich == FID_INS_ROWS_AFTER) - eAction = sc::ColRowEditAction::InsertRowsAfter; + eAction = sc::EditAction::InsertRowsAfter; bDisable = (!bSimpleArea) || GetViewData().SimpleColMarked(); if (!bEditable && nCol1 == 0 && nCol2 == rDoc.MaxCol()) { // See if row insertions are allowed. - bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nRow1, nRow2); + bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nCol1, nRow1, nCol2, nRow2); } break; } @@ -276,16 +276,16 @@ void ScCellShell::GetBlockState( SfxItemSet& rSet ) case FID_INS_COLUMNS_BEFORE: // insert columns case FID_INS_COLUMNS_AFTER: { - sc::ColRowEditAction eAction = sc::ColRowEditAction::InsertColumnsBefore; + sc::EditAction eAction = sc::EditAction::InsertColumnsBefore; if (nWhich == FID_INS_COLUMNS_AFTER) - eAction = sc::ColRowEditAction::InsertColumnsAfter; + eAction = sc::EditAction::InsertColumnsAfter; bDisable = (!bSimpleArea && eMarkType != SC_MARK_SIMPLE_FILTERED) || GetViewData().SimpleRowMarked(); if (!bEditable && nRow1 == 0 && nRow2 == rDoc.MaxRow()) { // See if row insertions are allowed. - bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nCol1, nCol2); + bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nCol1, nRow1, nCol2, nRow2); } break; } diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index bb7c4cf831b3..1a3aa891ffde 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -1116,11 +1116,19 @@ void ScCellShell::GetDBState( SfxItemSet& rSet ) case SID_FILTER: case SID_SPECIAL_FILTER: { - ScRange aDummy; - ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy); - if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED) + const ScTableProtection* pTabProt = rDoc.GetTabProtection(nTab); + if (pTabProt && pTabProt->isProtected() && !pTabProt->isOptionEnabled(ScTableProtection::AUTOFILTER)) { - rSet.DisableItem( nWhich ); + rSet.DisableItem(nWhich); + } + else + { + ScRange aDummy; + ScMarkType eMarkType = GetViewData().GetSimpleArea(aDummy); + if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED) + { + rSet.DisableItem(nWhich); + } } } break; @@ -1139,6 +1147,17 @@ void ScCellShell::GetDBState( SfxItemSet& rSet ) { rSet.DisableItem( nWhich ); } + else + { + if (nWhich == SID_OPENDLG_PIVOTTABLE) + { + const ScTableProtection* pTabProt = rDoc.GetTabProtection(nTab); + if (pTabProt && pTabProt->isProtected() && !pTabProt->isOptionEnabled(ScTableProtection::PIVOT_TABLES)) + { + rSet.DisableItem(nWhich); + } + } + } } break; @@ -1174,29 +1193,37 @@ void ScCellShell::GetDBState( SfxItemSet& rSet ) case SID_AUTO_FILTER: case SID_AUTOFILTER_HIDE: { - if (!bAutoFilterTested) + const ScTableProtection* pTabProt = rDoc.GetTabProtection(nTab); + if (pTabProt && pTabProt->isProtected() && !pTabProt->isOptionEnabled(ScTableProtection::AUTOFILTER)) { - bAutoFilter = rDoc.HasAutoFilter( nPosX, nPosY, nTab ); - bAutoFilterTested = true; + rSet.DisableItem(nWhich); } - if ( nWhich == SID_AUTO_FILTER ) + else { - ScRange aDummy; - ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy); - if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED) + if (!bAutoFilterTested) { - rSet.DisableItem( nWhich ); + bAutoFilter = rDoc.HasAutoFilter(nPosX, nPosY, nTab); + bAutoFilterTested = true; } - else if (rDoc.GetDPAtBlock(aDummy)) + if (nWhich == SID_AUTO_FILTER) { - rSet.DisableItem( nWhich ); + ScRange aDummy; + ScMarkType eMarkType = GetViewData().GetSimpleArea(aDummy); + if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED) + { + rSet.DisableItem(nWhich); + } + else if (rDoc.GetDPAtBlock(aDummy)) + { + rSet.DisableItem(nWhich); + } + else + rSet.Put(SfxBoolItem(nWhich, bAutoFilter)); } else - rSet.Put( SfxBoolItem( nWhich, bAutoFilter ) ); + if (!bAutoFilter) + rSet.DisableItem(nWhich); } - else - if (!bAutoFilter) - rSet.DisableItem( nWhich ); } break; diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index fa75d629a871..81c8a67e0ad6 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -2070,9 +2070,20 @@ void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventSta SCROW nRealPosY; mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nRealPosX, nRealPosY, false );//the real row/col + bool bAutoFilterDisable = false; + bool bPivotDisable = false; + + if (rDoc.IsTabProtected(nTab)) + { + const ScTableProtection* pTabProtection = rDoc.GetTabProtection(nTab); + bAutoFilterDisable = pTabProtection && !pTabProtection->isOptionEnabled(ScTableProtection::AUTOFILTER);//autofilter + bPivotDisable = pTabProtection && !pTabProtection->isOptionEnabled(ScTableProtection::PIVOT_TABLES);//pivot + } + // show in the merged cells the filter of the first cell (nPosX instead of nRealPosX) const ScMergeFlagAttr* pRealPosAttr = rDoc.GetAttr(nPosX, nRealPosY, nTab, ATTR_MERGE_FLAG); - if( pRealPosAttr->HasAutoFilter() ) + + if (!bAutoFilterDisable && pRealPosAttr->HasAutoFilter()) { SC_MOD()->InputEnterHandler(); if (DoAutoFilterButton(nPosX, nRealPosY, rMEvt)) @@ -2080,7 +2091,7 @@ void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventSta } const ScMergeFlagAttr* pAttr = rDoc.GetAttr(nPosX, nPosY, nTab, ATTR_MERGE_FLAG); - if (pAttr->HasAutoFilter()) + if (!bAutoFilterDisable && pAttr->HasAutoFilter()) { if (DoAutoFilterButton(nPosX, nPosY, rMEvt)) { @@ -2089,7 +2100,8 @@ void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventSta } } - if (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton() || pAttr->HasPivotMultiFieldPopupButton()) + if (!bPivotDisable && (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton() || + pAttr->HasPivotMultiFieldPopupButton())) { DoPushPivotButton(nPosX, nPosY, rMEvt, pAttr->HasPivotButton(), pAttr->HasPivotPopupButton(), pAttr->HasPivotMultiFieldPopupButton()); @@ -2097,7 +2109,7 @@ void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventSta return; } - if (pAttr->HasPivotToggle()) + if (!bPivotDisable && pAttr->HasPivotToggle()) { DoPushPivotToggle(nPosX, nPosY, rMEvt); rState.mbActivatePart = false; diff --git a/sc/source/ui/view/pivotsh.cxx b/sc/source/ui/view/pivotsh.cxx index 019e4da8f34e..40c6425a4025 100644 --- a/sc/source/ui/view/pivotsh.cxx +++ b/sc/source/ui/view/pivotsh.cxx @@ -128,6 +128,18 @@ void ScPivotShell::GetState( SfxItemSet& rSet ) ScDocShell* pDocSh = pViewShell->GetViewData().GetDocShell(); ScDocument& rDoc = pDocSh->GetDocument(); bool bDisable = pDocSh->IsReadOnly() || rDoc.GetChangeTrack(); + bool bFilterDisable = bDisable; + if (!bDisable) + { + SCCOL nTab = pViewShell->GetViewData().GetTabNo(); + const ScTableProtection* pTabProt = rDoc.GetTabProtection(nTab); + if (pTabProt && pTabProt->isProtected()) + { + bDisable = true; + if (!pTabProt->isOptionEnabled(ScTableProtection::PIVOT_TABLES)) + bFilterDisable = true; + } + } SfxWhichIter aIter(rSet); sal_uInt16 nWhich = aIter.FirstWhich(); @@ -148,7 +160,7 @@ void ScPivotShell::GetState( SfxItemSet& rSet ) case SID_DP_FILTER: { ScDPObject* pDPObj = GetCurrDPObject(); - if( bDisable || !pDPObj || !pDPObj->IsSheetData() ) + if( bFilterDisable || !pDPObj || !pDPObj->IsSheetData() ) rSet.DisableItem( nWhich ); } break; diff --git a/sc/uiconfig/scalc/ui/protectsheetdlg.ui b/sc/uiconfig/scalc/ui/protectsheetdlg.ui index 83f1a1af012a..20835b596783 100644 --- a/sc/uiconfig/scalc/ui/protectsheetdlg.ui +++ b/sc/uiconfig/scalc/ui/protectsheetdlg.ui @@ -17,30 +17,30 @@ </columns> </object> <object class="GtkDialog" id="ProtectSheetDialog"> - <property name="can_focus">False</property> - <property name="border_width">6</property> + <property name="can-focus">False</property> + <property name="border-width">6</property> <property name="title" translatable="yes" context="protectsheetdlg|ProtectSheetDialog">Protect Sheet</property> <property name="modal">True</property> - <property name="default_width">0</property> - <property name="default_height">0</property> - <property name="type_hint">dialog</property> + <property name="default-width">0</property> + <property name="default-height">0</property> + <property name="type-hint">dialog</property> <child internal-child="vbox"> <object class="GtkBox" id="dialog-vbox1"> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="orientation">vertical</property> <property name="spacing">12</property> <child internal-child="action_area"> <object class="GtkButtonBox" id="dialog-action_area1"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> + <property name="can-focus">False</property> + <property name="layout-style">end</property> <child> <object class="GtkButton" id="ok"> <property name="label" translatable="yes" context="stock">_OK</property> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <property name="receives_default">True</property> + <property name="can-focus">True</property> + <property name="can-default">True</property> + <property name="has-default">True</property> + <property name="receives-default">True</property> <property name="use-underline">True</property> </object> <packing> @@ -53,8 +53,8 @@ <object class="GtkButton" id="cancel"> <property name="label" translatable="yes" context="stock">_Cancel</property> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> <property name="use-underline">True</property> </object> <packing> @@ -67,8 +67,8 @@ <object class="GtkButton" id="help"> <property name="label" translatable="yes" context="stock">_Help</property> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> <property name="use-underline">True</property> </object> <packing> @@ -82,14 +82,14 @@ <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="pack_type">end</property> + <property name="pack-type">end</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="orientation">vertical</property> @@ -97,7 +97,7 @@ <child> <object class="GtkBox" id="box2"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="orientation">vertical</property> <property name="spacing">6</property> @@ -105,10 +105,10 @@ <object class="GtkCheckButton" id="protect"> <property name="label" translatable="yes" context="protectsheetdlg|protect">P_rotect this sheet and the contents of protected cells</property> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> </object> <packing> <property name="expand">False</property> @@ -120,33 +120,33 @@ <!-- n-columns=2 n-rows=3 --> <object class="GtkGrid" id="passwords"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="hexpand">True</property> - <property name="row_spacing">6</property> - <property name="column_spacing">6</property> + <property name="row-spacing">6</property> + <property name="column-spacing">6</property> <child> <object class="GtkLabel" id="label1"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="halign">end</property> <property name="label" translatable="yes" context="protectsheetdlg|label1">_Password:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">password1</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">password1</property> <property name="xalign">1</property> </object> <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> + <property name="left-attach">0</property> + <property name="top-attach">0</property> </packing> </child> <child> <object class="GtkLabel" id="label2"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="halign">end</property> <property name="label" translatable="yes" context="protectsheetdlg|label2">_Confirm:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">password2</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">password2</property> <property name="xalign">1</property> </object> <packing> @@ -157,29 +157,29 @@ <child> <object class="GtkEntry" id="password1"> <property name="visible">True</property> - <property name="can_focus">True</property> + <property name="can-focus">True</property> <property name="hexpand">True</property> <property name="visibility">False</property> - <property name="activates_default">True</property> - <property name="width_chars">24</property> + <property name="activates-default">True</property> + <property name="width-chars">24</property> <property name="truncate-multiline">True</property> - <property name="input_purpose">password</property> + <property name="input-purpose">password</property> </object> <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> + <property name="left-attach">1</property> + <property name="top-attach">0</property> </packing> </child> <child> <object class="GtkEntry" id="password2"> <property name="visible">True</property> - <property name="can_focus">True</property> + <property name="can-focus">True</property> <property name="hexpand">True</property> <property name="visibility">False</property> - <property name="activates_default">True</property> - <property name="width_chars">24</property> + <property name="activates-default">True</property> + <property name="width-chars">24</property> <property name="truncate-multiline">True</property> - <property name="input_purpose">password</property> + <property name="input-purpose">password</property> </object> <packing> <property name="left-attach">1</property> @@ -190,6 +190,11 @@ <object class="GtkLevelBar" id="passwordbar"> <property name="visible">True</property> <property name="can-focus">False</property> + <child internal-child="accessible"> + <object class="AtkObject" id="passwordbar-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="protectsheetdlg|extended_tip|passwordbar">Measure of password strength</property> + </object> + </child> </object> <packing> <property name="left-attach">1</property> @@ -216,7 +221,7 @@ <child> <object class="GtkBox" id="options"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="orientation">vertical</property> @@ -224,10 +229,10 @@ <child> <object class="GtkLabel" id="label4"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|label4">Allow all users of this sheet to:</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">checklist</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">checklist</property> <property name="xalign">0</property> </object> <packing> @@ -239,23 +244,23 @@ <child> <object class="GtkScrolledWindow"> <property name="visible">True</property> - <property name="can_focus">True</property> + <property name="can-focus">True</property> <property name="hexpand">True</property> <property name="vexpand">True</property> - <property name="hscrollbar_policy">never</property> - <property name="vscrollbar_policy">never</property> - <property name="shadow_type">in</property> + <property name="hscrollbar-policy">never</property> + <property name="vscrollbar-policy">never</property> + <property name="shadow-type">in</property> <child> <object class="GtkTreeView" id="checklist"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="model">liststore1</property> - <property name="headers_visible">False</property> - <property name="search_column">0</property> - <property name="show_expanders">False</property> + <property name="headers-visible">False</property> + <property name="search-column">0</property> + <property name="show-expanders">False</property> <child internal-child="selection"> <object class="GtkTreeSelection" id="Macro Library List-selection2"/> </child> @@ -297,12 +302,12 @@ </child> <child> <object class="GtkBox" id="box4"> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="homogeneous">True</property> <child> <object class="GtkLabel" id="protected"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|protected">Select protected cells</property> </object> <packing> @@ -314,7 +319,7 @@ <child> <object class="GtkLabel" id="delete-columns"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|delete-columns">Delete columns</property> </object> <packing> @@ -326,7 +331,7 @@ <child> <object class="GtkLabel" id="delete-rows"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|delete-rows">Delete rows</property> </object> <packing> @@ -338,7 +343,7 @@ <child> <object class="GtkLabel" id="insert-columns"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|insert-columns">Insert columns</property> </object> <packing> @@ -350,7 +355,7 @@ <child> <object class="GtkLabel" id="insert-rows"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|insert-rows">Insert rows</property> </object> <packing> @@ -362,7 +367,7 @@ <child> <object class="GtkLabel" id="unprotected"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can-focus">False</property> <property name="label" translatable="yes" context="protectsheetdlg|unprotected">Select unprotected cells</property> </object> <packing> @@ -371,6 +376,30 @@ <property name="position">1</property> </packing> </child> + <child> + <object class="GtkLabel" id="useautofilter"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="protectsheetdlg|delete-columns">Use AutoFilter</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="usepivot"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="protectsheetdlg|delete-columns">Use Pivot Table and Pivot Chart</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">7</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> @@ -399,9 +428,6 @@ <action-widget response="-6">cancel</action-widget> <action-widget response="-11">help</action-widget> </action-widgets> - <child type="titlebar"> - <placeholder/> - </child> <child internal-child="accessible"> <object class="AtkObject" id="ProtectSheetDialog-atkobject"> <property name="AtkObject::accessible-description" translatable="yes" context="protectsheetdlg|extended_tip|ProtectSheetDialog">Protects the cells in the current sheet from being modified.</property> diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng index 749c6daa3bfc..7ae65dc531ee 100644 --- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng @@ -2809,6 +2809,16 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. <rng:ref name="boolean"/> </rng:attribute> </rng:optional> + <rng:optional> + <rng:attribute name="loext:use-autofilter"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> + <rng:optional> + <rng:attribute name="loext:use-pivot"> + <rng:ref name="boolean"/> + </rng:attribute> + </rng:optional> </rng:element> </rng:define> <rng:define name="office-spreadsheet-attlist" combine="interleave"> diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 7b6e4a269602..9c6ba7833a75 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -2108,6 +2108,7 @@ namespace xmloff::token { TOKEN( "upright", XML_UPRIGHT ), TOKEN( "url", XML_URL ), TOKEN( "use", XML_USE ), + TOKEN( "use-autofilter", XML_USE_AUTOFILTER), TOKEN( "use-caption", XML_USE_CAPTION ), TOKEN( "use-cell-protection", XML_USE_CELL_PROTECTION ), TOKEN( "use-chart-objects", XML_USE_CHART_OBJECTS ), @@ -2125,6 +2126,7 @@ namespace xmloff::token { TOKEN( "use-optimal-column-width", XML_USE_OPTIMAL_COLUMN_WIDTH ), TOKEN( "use-optimal-row-height", XML_USE_OPTIMAL_ROW_HEIGHT ), TOKEN( "use-other-objects", XML_USE_OTHER_OBJECTS ), + TOKEN( "use-pivot", XML_USE_PIVOT), TOKEN( "use-spreadsheet-objects", XML_USE_SPREADSHEET_OBJECTS ), TOKEN( "use-styles", XML_USE_STYLES ), TOKEN( "use-tables", XML_USE_TABLES ), diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 05a6dd1be01d..8752dd63723d 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -2008,6 +2008,7 @@ uplimit upright url use +use-autofilter use-caption use-cell-protection use-chart-objects @@ -2025,6 +2026,7 @@ use-objects use-optimal-column-width use-optimal-row-height use-other-objects +use-pivot use-spreadsheet-objects use-styles use-tables
