office-gobmx/formula/source/ui/dlg/FormulaHelper.cxx
Stephan Bergmann 2304eef0af loplugin:includeform: formula
Change-Id: I50b898e477e0842577bcc648540e7f4b66d5b693
2017-10-23 22:46:07 +02:00

409 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <algorithm>
#include <formula/formulahelper.hxx>
#include <formula/IFunctionDescription.hxx>
#include <unotools/charclass.hxx>
#include <unotools/syslocale.hxx>
namespace formula
{
namespace
{
class OEmptyFunctionDescription : public IFunctionDescription
{
public:
OEmptyFunctionDescription(){}
virtual ~OEmptyFunctionDescription(){}
virtual OUString getFunctionName() const override { return OUString(); }
virtual const IFunctionCategory* getCategory() const override { return nullptr; }
virtual OUString getDescription() const override { return OUString(); }
virtual sal_Int32 getSuppressedArgumentCount() const override { return 0; }
virtual OUString getFormula(const ::std::vector< OUString >& ) const override { return OUString(); }
virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const override {}
virtual void initArgumentInfo() const override {}
virtual OUString getSignature() const override { return OUString(); }
virtual OString getHelpId() const override { return ""; }
virtual bool isHidden() const override { return false; }
virtual sal_uInt32 getParameterCount() const override { return 0; }
virtual sal_uInt32 getVarArgsStart() const override { return 0; }
virtual OUString getParameterName(sal_uInt32 ) const override { return OUString(); }
virtual OUString getParameterDescription(sal_uInt32 ) const override { return OUString(); }
virtual bool isParameterOptional(sal_uInt32 ) const override { return false; }
};
}
// class FormulaHelper - static Method
#define FUNC_NOTFOUND -1
FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
:m_pSysLocale(new SvtSysLocale)
,m_pFunctionManager(_pFunctionManager)
,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
{
m_pCharClass = m_pSysLocale->GetCharClassPtr();
}
bool FormulaHelper::GetNextFunc( const OUString& rFormula,
bool bBack,
sal_Int32& rFStart, // Input and output
sal_Int32* pFEnd, // = NULL
const IFunctionDescription** ppFDesc, // = NULL
::std::vector< OUString>* pArgs ) const // = NULL
{
sal_Int32 nOldStart = rFStart;
OUString aFname;
rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : nullptr );
bool bFound = ( rFStart != FUNC_NOTFOUND );
if ( bFound )
{
if ( pFEnd )
*pFEnd = GetFunctionEnd( rFormula, rFStart );
if ( ppFDesc )
{
*ppFDesc = nullptr;
const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
{
const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
const sal_uInt32 nCount = pCategory->getCount();
for(sal_uInt32 i = 0 ; i < nCount; ++i)
{
const IFunctionDescription* pCurrent = pCategory->getFunction(i);
if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(aFname) )
{
*ppFDesc = pCurrent;
break;
}
}// for(sal_uInt32 i = 0 ; i < nCount; ++i)
}
if ( *ppFDesc && pArgs )
{
GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
}
else
{
static OEmptyFunctionDescription s_aFunctionDescription;
*ppFDesc = &s_aFunctionDescription;
}
}
}
else
rFStart = nOldStart;
return bFound;
}
void FormulaHelper::FillArgStrings( const OUString& rFormula,
sal_Int32 nFuncPos,
sal_uInt16 nArgs,
::std::vector< OUString >& _rArgs ) const
{
sal_Int32 nStart = 0;
sal_Int32 nEnd = 0;
sal_uInt16 i;
bool bLast = false;
for ( i=0; i<nArgs && !bLast; i++ )
{
nStart = GetArgStart( rFormula, nFuncPos, i );
if ( i+1<nArgs ) // last argument?
{
nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
if ( nEnd != nStart )
_rArgs.push_back(rFormula.copy( nStart, nEnd-1-nStart ));
else
{
_rArgs.emplace_back();
bLast = true;
}
}
else
{
nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
if ( nStart < nEnd )
_rArgs.push_back( rFormula.copy( nStart, nEnd-nStart ) );
else
_rArgs.emplace_back();
}
}
if ( bLast )
for ( ; i<nArgs; i++ )
_rArgs.emplace_back();
}
void FormulaHelper::GetArgStrings( ::std::vector< OUString >& _rArgs,
const OUString& rFormula,
sal_Int32 nFuncPos,
sal_uInt16 nArgs ) const
{
if (nArgs)
{
FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
}
}
inline bool IsFormulaText( const CharClass* _pCharClass,const OUString& rStr, sal_Int32 nPos )
{
if( _pCharClass->isLetterNumeric( rStr, nPos ) )
return true;
else
{ // In internationalized versions function names may contain a dot
// and in every version also an underscore... ;-)
sal_Unicode c = rStr[nPos];
return c == '.' || c == '_';
}
}
sal_Int32 FormulaHelper::GetFunctionStart( const OUString& rFormula,
sal_Int32 nStart,
bool bBack,
OUString* pFuncName ) const
{
sal_Int32 nStrLen = rFormula.getLength();
if ( nStrLen < nStart )
return nStart;
sal_Int32 nFStart = FUNC_NOTFOUND;
sal_Int32 nParPos = bBack ? ::std::min( nStart, nStrLen - 1) : nStart;
bool bRepeat;
do
{
bool bFound = false;
bRepeat = false;
if ( bBack )
{
while ( !bFound && (nParPos > 0) )
{
if ( rFormula[nParPos] == '"' )
{
nParPos--;
while ( (nParPos > 0) && rFormula[nParPos] != '"' )
nParPos--;
if (nParPos > 0)
nParPos--;
}
else
{
bFound = rFormula[nParPos] == '(';
if ( !bFound )
nParPos--;
}
}
}
else
{
while ( !bFound && (0 <= nParPos && nParPos < nStrLen) )
{
if ( rFormula[nParPos] == '"' )
{
nParPos++;
while ( (nParPos < nStrLen) && rFormula[nParPos] != '"' )
nParPos++;
nParPos++;
}
else
{
bFound = rFormula[nParPos] == '(';
if ( !bFound )
nParPos++;
}
}
}
if ( bFound && (nParPos > 0) )
{
nFStart = nParPos-1;
while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
nFStart--;
}
nFStart++;
if ( bFound )
{
if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
{
// Function found
if ( pFuncName )
*pFuncName = rFormula.copy( nFStart, nParPos-nFStart );
}
else // Brackets without function -> keep searching
{
bRepeat = true;
if ( !bBack )
nParPos++;
else if (nParPos > 0)
nParPos--;
else
bRepeat = false;
}
}
else // No brackets found
{
nFStart = FUNC_NOTFOUND;
if ( pFuncName )
pFuncName->clear();
}
}
while(bRepeat);
return nFStart;
}
sal_Int32 FormulaHelper::GetFunctionEnd( const OUString& rStr, sal_Int32 nStart ) const
{
sal_Int32 nStrLen = rStr.getLength();
if ( nStrLen < nStart )
return nStart;
short nParCount = 0;
bool bInArray = false;
bool bFound = false;
while ( !bFound && (nStart < nStrLen) )
{
sal_Unicode c = rStr[nStart];
if ( c == '"' )
{
nStart++;
while ( (nStart < nStrLen) && rStr[nStart] != '"' )
nStart++;
}
else if ( c == open )
nParCount++;
else if ( c == close )
{
nParCount--;
if ( nParCount == 0 )
bFound = true;
else if ( nParCount < 0 )
{
bFound = true;
nStart--; // read one too far
}
}
else if ( c == arrayOpen )
{
bInArray = true;
}
else if ( c == arrayClose )
{
bInArray = false;
}
else if ( c == sep )
{
if ( !bInArray && nParCount == 0 )
{
bFound = true;
nStart--; // read one too far
}
}
nStart++; // Set behind found position
}
return nStart;
}
sal_Int32 FormulaHelper::GetArgStart( const OUString& rStr, sal_Int32 nStart, sal_uInt16 nArg ) const
{
sal_Int32 nStrLen = rStr.getLength();
if ( nStrLen < nStart )
return nStart;
short nParCount = 0;
bool bInArray = false;
bool bFound = false;
while ( !bFound && (nStart < nStrLen) )
{
sal_Unicode c = rStr[nStart];
if ( c == '"' )
{
nStart++;
while ( (nStart < nStrLen) && rStr[nStart] != '"' )
nStart++;
}
else if ( c == open )
{
bFound = ( nArg == 0 );
nParCount++;
}
else if ( c == close )
{
nParCount--;
bFound = ( nParCount == 0 );
}
else if ( c == arrayOpen )
{
bInArray = true;
}
else if ( c == arrayClose )
{
bInArray = false;
}
else if ( c == sep )
{
if ( !bInArray && nParCount == 1 )
{
nArg--;
bFound = ( nArg == 0 );
}
}
nStart++;
}
return nStart;
}
} // formula
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */