tdf#104310: Accept also x14-style dataValidations

See https://msdn.microsoft.com/en-us/library/dd921584

Change-Id: I66c9474cbf83cea10ab0e7c2b44592673c8b683f
Reviewed-on: https://gerrit.libreoffice.org/31456
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
This commit is contained in:
Mike Kaganski
2016-12-01 07:38:32 +03:00
committed by Andras Timar
parent 83b7e1f424
commit 0afbe8d5ca
5 changed files with 198 additions and 123 deletions

View File

@@ -7,66 +7,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/config.h>
#include <unotest/filters-test.hxx>
#include <test/bootstrapfixture.hxx>
#include <rtl/strbuf.hxx>
#include <osl/file.hxx>
#include <sfx2/app.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/sfxmodelfactory.hxx>
#include <svl/stritem.hxx>
#include <svx/svdograf.hxx>
#include "drwlayer.hxx"
#include <svx/svdpage.hxx>
#include <svx/svdoole2.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/borderline.hxx>
#include <editeng/flditem.hxx>
#include <dbdata.hxx>
#include "validat.hxx"
#include "formulacell.hxx"
#include "userdat.hxx"
#include "dpobject.hxx"
#include "dpsave.hxx"
#include "stlsheet.hxx"
#include "docfunc.hxx"
#include "markdata.hxx"
#include "colorscale.hxx"
#include "olinetab.hxx"
#include "patattr.hxx"
#include "scitems.hxx"
#include "docsh.hxx"
#include "editutil.hxx"
#include "cellvalue.hxx"
#include "attrib.hxx"
#include "dpshttab.hxx"
#include "tabvwsh.hxx"
#include <scopetools.hxx>
#include <columnspanset.hxx>
#include <tokenstringcontext.hxx>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
#include <com/sun/star/sheet/GeneralFunction.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/text/textfield/Type.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include "helper/qahelper.hxx"
#include "helper/shared_test_impl.hxx"
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -91,6 +35,7 @@ public:
void testTdf88821_2();
void testTdf103960();
void testRhbz1390776();
void testTdf104310();
CPPUNIT_TEST_SUITE(ScFiltersTest);
CPPUNIT_TEST(testTdf64229);
@@ -104,6 +49,7 @@ public:
CPPUNIT_TEST(testTdf88821_2);
CPPUNIT_TEST(testTdf103960);
CPPUNIT_TEST(testRhbz1390776);
CPPUNIT_TEST(testTdf104310);
CPPUNIT_TEST_SUITE_END();
private:
uno::Reference<uno::XInterface> m_xCalcComponent;
@@ -294,6 +240,24 @@ void ScFiltersTest::testRhbz1390776()
xDocSh->DoClose();
}
void ScFiltersTest::testTdf104310()
{
ScDocShellRef xDocSh = loadDoc("tdf104310.", FORMAT_XLSX);
ScDocument& rDoc = xDocSh->GetDocument();
const ScValidationData* pData = rDoc.GetValidationEntry(1);
CPPUNIT_ASSERT(pData);
// Make sure the list is correct.
std::vector<ScTypedStrData> aList;
pData->FillSelectionList(aList, ScAddress(0, 1, 0));
CPPUNIT_ASSERT_EQUAL(size_t(5), aList.size());
for (size_t i = 0; i < 5; ++i)
CPPUNIT_ASSERT_DOUBLES_EQUAL(double(i+1), aList[i].GetValue(), 1e-8);
xDocSh->DoClose();
}
ScFiltersTest::ScFiltersTest()
: ScBootstrapFixture( "/sc/qa/unit/data" )
{

Binary file not shown.

View File

@@ -25,7 +25,25 @@
namespace oox {
namespace xls {
class DataValidationsContext : public WorksheetContextBase
class DataValidationsContext_Base {
public:
DataValidationsContext_Base() {}
void SetSqref(const OUString& rChars) { mSqref = rChars; }
void SetFormula1(const OUString& rChars) { mFormula1 = rChars; }
void SetFormula2(const OUString& rChars) { mFormula2 = rChars; }
void SetValidation(::oox::xls::WorksheetHelper& rTarget);
/** Imports the dataValidation element containing data validation settings. */
void importDataValidation(const AttributeList& rAttribs);
/** Imports the DATAVALIDATION record containing data validation settings. */
static void importDataValidation(SequenceInputStream& rStrm, ::oox::xls::WorksheetHelper& rTarget);
private:
::std::unique_ptr< ValidationModel > mxValModel;
OUString mSqref;
OUString mFormula1;
OUString mFormula2;
};
class DataValidationsContext : public WorksheetContextBase, private DataValidationsContext_Base
{
public:
explicit DataValidationsContext( WorksheetFragmentBase& rFragment );
@@ -36,15 +54,19 @@ protected:
virtual void onEndElement() override;
virtual ::oox::core::ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
};
private:
/** Imports the dataValidation element containing data validation settings. */
void importDataValidation( const AttributeList& rAttribs );
/** Imports the DATAVALIDATION record containing data validation settings. */
void importDataValidation( SequenceInputStream& rStrm );
class ExtDataValidationsContext : public WorksheetContextBase, private DataValidationsContext_Base
{
public:
explicit ExtDataValidationsContext( WorksheetContextBase& rFragment );
protected:
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override;
virtual void onCharacters( const OUString& rChars ) override;
virtual void onEndElement() override;
private:
::std::unique_ptr< ValidationModel > mxValModel;
sal_Int32 mCurrFormula;
};
class WorksheetFragment : public WorksheetFragmentBase

View File

@@ -229,9 +229,11 @@ ExtGlobalContext::ExtGlobalContext( WorksheetContextBase& rFragment ):
ContextHandlerRef ExtGlobalContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
{
if (nElement == XLS14_TOKEN(conditionalFormatting))
return new ExtConditionalFormattingContext(*this);
switch (nElement)
{
case XLS14_TOKEN(conditionalFormatting): return new ExtConditionalFormattingContext(*this);
case XLS14_TOKEN(dataValidations): return new ExtDataValidationsContext(*this);
}
return this;
}

View File

@@ -75,6 +75,84 @@ const sal_uInt16 BIFF12_OLEOBJECT_AUTOLOAD = 0x0002;
} // namespace
void DataValidationsContext_Base::SetValidation(::oox::xls::WorksheetHelper& rTarget)
{
if (!mxValModel.get())
return;
rTarget.getAddressConverter().convertToCellRangeList(mxValModel->maRanges, mSqref, rTarget.getSheetIndex(), true);
mxValModel->msRef = mSqref;
mxValModel->maTokens1 = rTarget.getFormulaParser().importFormula(mxValModel->maRanges.getBaseAddress(), mFormula1);
// process string list of a list validation (convert to list of string tokens)
if (mxValModel->mnType == XML_list)
rTarget.getFormulaParser().convertStringToStringList(mxValModel->maTokens1, ',', true);
mxValModel->maTokens2 = rTarget.getFormulaParser().importFormula(mxValModel->maRanges.getBaseAddress(), mFormula2);
rTarget.setValidation(*mxValModel);
mxValModel.reset();
}
void DataValidationsContext_Base::importDataValidation(const AttributeList& rAttribs)
{
mxValModel.reset(new ValidationModel);
OUString aSqref = rAttribs.getString(XML_sqref, OUString());
// Only set mSqref if it is set in attributes, to avoid owerwriting already set using SetSqref
if (!aSqref.isEmpty())
{
mSqref = aSqref;
}
mxValModel->maInputTitle = rAttribs.getXString(XML_promptTitle, OUString());
mxValModel->maInputMessage = rAttribs.getXString(XML_prompt, OUString());
mxValModel->maErrorTitle = rAttribs.getXString(XML_errorTitle, OUString());
mxValModel->maErrorMessage = rAttribs.getXString(XML_error, OUString());
mxValModel->mnType = rAttribs.getToken(XML_type, XML_none);
mxValModel->mnOperator = rAttribs.getToken(XML_operator, XML_between);
mxValModel->mnErrorStyle = rAttribs.getToken(XML_errorStyle, XML_stop);
mxValModel->mbShowInputMsg = rAttribs.getBool(XML_showInputMessage, false);
mxValModel->mbShowErrorMsg = rAttribs.getBool(XML_showErrorMessage, false);
/* The attribute showDropDown@dataValidation is in fact a "suppress
dropdown" flag, as it was in the BIFF format! ECMA specification
and attribute name are plain wrong! */
mxValModel->mbNoDropDown = rAttribs.getBool(XML_showDropDown, false);
mxValModel->mbAllowBlank = rAttribs.getBool(XML_allowBlank, false);
}
void DataValidationsContext_Base::importDataValidation(SequenceInputStream& rStrm, ::oox::xls::WorksheetHelper& rTarget)
{
ValidationModel aModel;
sal_uInt32 nFlags;
BinRangeList aRanges;
nFlags = rStrm.readuInt32();
rStrm >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
// equal flags in all BIFFs
aModel.setBiffType(extractValue< sal_uInt8 >(nFlags, 0, 4));
aModel.setBiffOperator(extractValue< sal_uInt8 >(nFlags, 20, 4));
aModel.setBiffErrorStyle(extractValue< sal_uInt8 >(nFlags, 4, 3));
aModel.mbAllowBlank = getFlag(nFlags, BIFF_DATAVAL_ALLOWBLANK);
aModel.mbNoDropDown = getFlag(nFlags, BIFF_DATAVAL_NODROPDOWN);
aModel.mbShowInputMsg = getFlag(nFlags, BIFF_DATAVAL_SHOWINPUT);
aModel.mbShowErrorMsg = getFlag(nFlags, BIFF_DATAVAL_SHOWERROR);
// cell range list
rTarget.getAddressConverter().convertToCellRangeList(aModel.maRanges, aRanges, rTarget.getSheetIndex(), true);
// condition formula(s)
FormulaParser& rParser = rTarget.getFormulaParser();
ScAddress aBaseAddr = aModel.maRanges.getBaseAddress();
aModel.maTokens1 = rParser.importFormula(aBaseAddr, FORMULATYPE_VALIDATION, rStrm);
aModel.maTokens2 = rParser.importFormula(aBaseAddr, FORMULATYPE_VALIDATION, rStrm);
// process string list of a list validation (convert to list of string tokens)
if ((aModel.mnType == XML_list) && getFlag(nFlags, BIFF_DATAVAL_STRINGLIST))
rParser.convertStringToStringList(aModel.maTokens1, ',', true);
// set validation data
rTarget.setValidation(aModel);
}
DataValidationsContext::DataValidationsContext( WorksheetFragmentBase& rFragment ) :
WorksheetContextBase( rFragment )
{
@@ -105,89 +183,98 @@ ContextHandlerRef DataValidationsContext::onCreateContext( sal_Int32 nElement, c
void DataValidationsContext::onCharacters( const OUString& rChars )
{
if( mxValModel.get() ) switch( getCurrentElement() )
switch( getCurrentElement() )
{
case XLS_TOKEN( formula1 ):
mxValModel->maTokens1 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
// process string list of a list validation (convert to list of string tokens)
if( mxValModel->mnType == XML_list )
getFormulaParser().convertStringToStringList( mxValModel->maTokens1, ',', true );
SetFormula1( rChars );
break;
case XLS_TOKEN( formula2 ):
mxValModel->maTokens2 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
SetFormula2( rChars );
break;
}
}
void DataValidationsContext::onEndElement()
{
if( isCurrentElement( XLS_TOKEN( dataValidation ) ) && mxValModel.get() )
if( isCurrentElement( XLS_TOKEN( dataValidation ) ) )
{
setValidation( *mxValModel );
mxValModel.reset();
SetValidation( *this );
}
}
ContextHandlerRef DataValidationsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
{
if( nRecId == BIFF12_ID_DATAVALIDATION )
importDataValidation( rStrm );
importDataValidation( rStrm, *this );
return nullptr;
}
void DataValidationsContext::importDataValidation( const AttributeList& rAttribs )
ExtDataValidationsContext::ExtDataValidationsContext( WorksheetContextBase& rFragment ) :
WorksheetContextBase( rFragment ), mCurrFormula( 0 )
{
mxValModel.reset( new ValidationModel );
getAddressConverter().convertToCellRangeList( mxValModel->maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
mxValModel->msRef = rAttribs.getString( XML_sqref, OUString() );
mxValModel->maInputTitle = rAttribs.getXString( XML_promptTitle, OUString() );
mxValModel->maInputMessage = rAttribs.getXString( XML_prompt, OUString() );
mxValModel->maErrorTitle = rAttribs.getXString( XML_errorTitle, OUString() );
mxValModel->maErrorMessage = rAttribs.getXString( XML_error, OUString() );
mxValModel->mnType = rAttribs.getToken( XML_type, XML_none );
mxValModel->mnOperator = rAttribs.getToken( XML_operator, XML_between );
mxValModel->mnErrorStyle = rAttribs.getToken( XML_errorStyle, XML_stop );
mxValModel->mbShowInputMsg = rAttribs.getBool( XML_showInputMessage, false );
mxValModel->mbShowErrorMsg = rAttribs.getBool( XML_showErrorMessage, false );
/* The attribute showDropDown@dataValidation is in fact a "suppress
dropdown" flag, as it was in the BIFF format! ECMA specification
and attribute name are plain wrong! */
mxValModel->mbNoDropDown = rAttribs.getBool( XML_showDropDown, false );
mxValModel->mbAllowBlank = rAttribs.getBool( XML_allowBlank, false );
}
void DataValidationsContext::importDataValidation( SequenceInputStream& rStrm )
ContextHandlerRef ExtDataValidationsContext::onCreateContext(sal_Int32 nElement, const AttributeList& rAttribs)
{
ValidationModel aModel;
switch( getCurrentElement() )
{
case XLS14_TOKEN( dataValidations ):
if ( nElement == XLS14_TOKEN( dataValidation ) )
{
importDataValidation( rAttribs );
return this;
}
break;
case XLS14_TOKEN( dataValidation ):
switch ( nElement )
{
case XLS14_TOKEN( formula1 ):
case XLS14_TOKEN( formula2 ):
mCurrFormula = nElement;
return this;
case XM_TOKEN( sqref ):
return this; // collect sqref in onCharacters()
}
break;
case XLS14_TOKEN( formula1 ):
case XLS14_TOKEN( formula2 ):
switch( nElement )
{
case XM_TOKEN( f ):
return this; // collect formulas in onCharacters()
}
break;
}
return nullptr;
}
sal_uInt32 nFlags;
BinRangeList aRanges;
nFlags = rStrm.readuInt32();
rStrm >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
void ExtDataValidationsContext::onCharacters( const OUString& rChars )
{
switch( getCurrentElement() )
{
case XM_TOKEN( f ):
switch( mCurrFormula )
{
case XLS14_TOKEN( formula1 ):
SetFormula1( rChars );
break;
case XLS14_TOKEN( formula2 ):
SetFormula2( rChars );
break;
}
break;
case XM_TOKEN( sqref ):
SetSqref( rChars );
break;
}
}
// equal flags in all BIFFs
aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
aModel.setBiffErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
aModel.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
aModel.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
// cell range list
getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
// condition formula(s)
FormulaParser& rParser = getFormulaParser();
ScAddress aBaseAddr = aModel.maRanges.getBaseAddress();
aModel.maTokens1 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
aModel.maTokens2 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
// process string list of a list validation (convert to list of string tokens)
if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
rParser.convertStringToStringList( aModel.maTokens1, ',', true );
// set validation data
setValidation( aModel );
void ExtDataValidationsContext::onEndElement()
{
if( isCurrentElement( XLS14_TOKEN( dataValidation ) ) )
{
SetValidation( *this );
}
}
WorksheetFragment::WorksheetFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :