tdf#144786 Implement XML_hiddenButton functionality
Now hides autofilter button when there's an XML_hiddenButton=true
or a XML_showButton=false attribute
Change-Id: I911ef23fb5e4feff8c7de0ec154bff871a29f2e8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143300
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/sc/qa/unit/data/xlsx/hiddenButton.xlsx b/sc/qa/unit/data/xlsx/hiddenButton.xlsx
new file mode 100644
index 0000000..20019f4
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/hiddenButton.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx
index 6284011..77b033d 100644
--- a/sc/qa/unit/subsequent_export_test2.cxx
+++ b/sc/qa/unit/subsequent_export_test2.cxx
@@ -189,6 +189,7 @@ public:
void testTdf148820();
void testEmbeddedTextInDecimal();
void testTotalsRowFunction();
void testAutofilterHiddenButton();
CPPUNIT_TEST_SUITE(ScExportTest2);
@@ -315,6 +316,7 @@ public:
CPPUNIT_TEST(testTdf148820);
CPPUNIT_TEST(testEmbeddedTextInDecimal);
CPPUNIT_TEST(testTotalsRowFunction);
CPPUNIT_TEST(testAutofilterHiddenButton);
CPPUNIT_TEST_SUITE_END();
};
@@ -2849,6 +2851,19 @@ void ScExportTest2::testTotalsRowFunction()
}
}
void ScExportTest2::testAutofilterHiddenButton()
{
createScDoc("xlsx/hiddenButton.xlsx");
saveAndReload("Calc Office Open XML");
xmlDocUniquePtr pDocXml = parseExport("xl/tables/table1.xml");
CPPUNIT_ASSERT(pDocXml);
for (int i = 1; i <= 5; i++)
{
auto sPath = "/x:table/x:autoFilter/x:filterColumn[" + std::to_string(i) + "]";
assertXPath(pDocXml, sPath.c_str(), "hiddenButton", "1");
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx
index b175445..3feac86 100644
--- a/sc/source/filter/excel/excrecds.cxx
+++ b/sc/source/filter/excel/excrecds.cxx
@@ -47,6 +47,8 @@
#include <xcl97rec.hxx>
#include <tabprotection.hxx>
#include <scitems.hxx>
#include <attrib.hxx>
using namespace ::oox;
@@ -603,11 +605,12 @@ void ExcFilterCondition::SaveText( XclExpStream& rStrm )
}
}
XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC ) :
XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC, bool bIsEmpty ) :
XclExpRecord( EXC_ID_AUTOFILTER, 24 ),
XclExpRoot( rRoot ),
meType(FilterCondition),
meType(bIsEmpty ? Empty : FilterCondition),
nCol( nC ),
bIsButtonHidden( false ),
nFlags( 0 ),
bHasBlankValue( false )
{
@@ -818,10 +821,13 @@ void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm )
sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
std::optional<OString> sHiddenButtonValue;
if (bIsButtonHidden)
sHiddenButtonValue = "1";
rWorksheet->startElement( XML_filterColumn,
XML_colId, OString::number(nCol)
// OOXTODO: XML_hiddenButton, AutoFilter12 fHideArrow?
// OOXTODO: XML_showButton
XML_colId, OString::number(nCol),
XML_hiddenButton, sHiddenButtonValue
);
switch (meType)
@@ -911,6 +917,8 @@ void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm )
rWorksheet->endElement(XML_filters);
}
break;
// Used for constructing an empty filterColumn element for exporting the XML_hiddenButton attribute
case Empty: break;
}
rWorksheet->endElement( XML_filterColumn );
}
@@ -971,6 +979,8 @@ ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab, const
bool bContLoop = true;
bool bHasOr = false;
SCCOLROW nFirstField = aParam.GetEntry( 0 ).nField;
ScDocument& rDoc = rRoot.GetDoc();
SCROW nRow = aRange.aStart.Row();
// create AUTOFILTER records for filtered columns
for( SCSIZE nEntry = 0; !bConflict && bContLoop && (nEntry < aParam.GetEntryCount()); nEntry++ )
@@ -980,7 +990,11 @@ ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab, const
bContLoop = rEntry.bDoQuery;
if( bContLoop )
{
XclExpAutofilter* pFilter = GetByCol( static_cast<SCCOL>(rEntry.nField) - aRange.aStart.Col() );
SCCOL nCol = static_cast<SCCOL>( rEntry.nField ) - aRange.aStart.Col();
auto nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
bool bIsButtonHidden = !( nFlag & ScMF::Auto );
XclExpAutofilter* pFilter = GetByCol( nCol );
pFilter->SetButtonHidden( bIsButtonHidden );
if( nEntry > 0 )
bHasOr |= (rEntry.eConnect == SC_OR);
@@ -994,6 +1008,34 @@ ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab, const
}
}
sal_uInt16 nColId = 0;
for ( auto nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); nCol++, nColId++ )
{
auto nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
bool bIsButtonHidden = !( nFlag & ScMF::Auto );
if ( bIsButtonHidden )
{
// Create filter column with hiddenButton=1 attribute if it doesn't exist
XclExpAutofilterRef xFilter;
bool bFilterFound = false;
for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos )
{
xFilter = maFilterList.GetRecord( nPos );
if( xFilter->GetCol() == static_cast<sal_uInt16>(nCol) )
{
bFilterFound = true;
break;
}
}
if ( !bFilterFound )
{
xFilter = new XclExpAutofilter( GetRoot(), nColId, /*bIsEmpty*/true );
xFilter->SetButtonHidden( true );
maFilterList.AppendRecord( xFilter );
}
}
}
// additional tests for conflicts
for( size_t nPos = 0, nSize = maFilterList.GetSize(); !bConflict && (nPos < nSize); ++nPos )
{
diff --git a/sc/source/filter/inc/autofilterbuffer.hxx b/sc/source/filter/inc/autofilterbuffer.hxx
index 6721c18..fad4de5 100644
--- a/sc/source/filter/inc/autofilterbuffer.hxx
+++ b/sc/source/filter/inc/autofilterbuffer.hxx
@@ -197,6 +197,7 @@ public:
/** Returns converted UNO API filter settings representing all filter
settings of this column. */
ApiFilterSettings finalizeImport();
bool isButtonHidden();
private:
std::shared_ptr< FilterSettingsBase >
diff --git a/sc/source/filter/inc/excrecds.hxx b/sc/source/filter/inc/excrecds.hxx
index 2e4885a..c7ab0aa9 100644
--- a/sc/source/filter/inc/excrecds.hxx
+++ b/sc/source/filter/inc/excrecds.hxx
@@ -361,6 +361,7 @@ class XclExpAutofilter : public XclExpRecord, protected XclExpRoot
private:
enum FilterType
{
Empty,
FilterCondition,
MultiValue,
BlankValue,
@@ -368,6 +369,7 @@ private:
};
FilterType meType;
sal_uInt16 nCol;
bool bIsButtonHidden;
sal_uInt16 nFlags;
bool bHasBlankValue;
ExcFilterCondition aCond[ 2 ];
@@ -380,7 +382,7 @@ private:
virtual void WriteBody( XclExpStream& rStrm ) override;
public:
XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC );
XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC, bool bIsEmpty = false );
sal_uInt16 GetCol() const { return nCol; }
bool HasTop10() const { return ::get_flag( nFlags, EXC_AFFLAG_TOP10 ); }
@@ -388,6 +390,7 @@ public:
bool HasCondition() const;
bool AddEntry( const ScQueryEntry& rEntry );
void AddMultiValueEntry( const ScQueryEntry& rEntry );
void SetButtonHidden(bool bValue) { bIsButtonHidden = bValue; }
void AddColorEntry( const ScQueryEntry& rEntry );
virtual void SaveXml( XclExpXmlStream& rStrm ) override;
diff --git a/sc/source/filter/oox/autofilterbuffer.cxx b/sc/source/filter/oox/autofilterbuffer.cxx
index 3295087..b7f14d8 100644
--- a/sc/source/filter/oox/autofilterbuffer.cxx
+++ b/sc/source/filter/oox/autofilterbuffer.cxx
@@ -656,6 +656,11 @@ ApiFilterSettings FilterColumn::finalizeImport()
return aSettings;
}
bool FilterColumn::isButtonHidden()
{
return (mbShowButton == false) || (mbHiddenButton == true);
}
// SortCondition
SortCondition::SortCondition( const WorkbookHelper& rHelper ) :
@@ -743,6 +748,11 @@ void AutoFilter::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRa
'(A1 and B1) or (B2 and C1)'. */
bool bHasOrConnection = false;
ScDocument& rDoc = getScDocument();
SCCOL nCol = maRange.aStart.Col();
SCROW nRow = maRange.aStart.Row();
SCTAB nTab = maRange.aStart.Tab();
// process all filter column objects, exit when 'or' connection exists
for( const auto& rxFilterColumn : maFilterColumns )
{
@@ -750,6 +760,13 @@ void AutoFilter::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRa
ApiFilterSettings aSettings = rxFilterColumn->finalizeImport();
ApiFilterSettings::FilterFieldVector& rColumnFields = aSettings.maFilterFields;
if (rxFilterColumn->isButtonHidden())
{
auto nFlag = rDoc.GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG)->GetValue();
rDoc.ApplyAttr(nCol, nRow, nTab, ScMergeFlagAttr(nFlag & ~ScMF::Auto));
}
nCol++;
/* Check whether mode for regular expressions is compatible with
the global mode in obNeedsRegExp. If either one is still in
don't-care state, all is fine. If both are set, they must be
@@ -838,7 +855,6 @@ void AutoFilter::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRa
aParam.maKeyState[0].nField += nStartPos;
}
ScDocument& rDoc = getScDocument();
ScDBData* pDBData = rDoc.GetDBAtArea(
nSheet,
maRange.aStart.Col(), maRange.aStart.Row(),