xref: /AOO41X/main/formula/source/ui/dlg/FormulaHelper.cxx (revision c25918c1c543b2e4817410a4e7739607dba55e06)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #include "precompiled_formula.hxx"
24 
25 #include "formula/formulahelper.hxx"
26 #include <unotools/charclass.hxx>
27 #include <unotools/syslocale.hxx>
28 
29 namespace formula
30 {
31 
32     namespace
33     {
34         //============================================================================
35         class OEmptyFunctionDescription : public IFunctionDescription
36         {
37         public:
OEmptyFunctionDescription()38             OEmptyFunctionDescription(){}
~OEmptyFunctionDescription()39             virtual ~OEmptyFunctionDescription(){}
40 
getFunctionName() const41             virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); }
getCategory() const42             virtual const IFunctionCategory* getCategory() const { return NULL; }
getDescription() const43             virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); }
getSuppressedArgumentCount() const44             virtual xub_StrLen getSuppressedArgumentCount() const { return 0; }
getFormula(const::std::vector<::rtl::OUString> &) const45             virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); }
fillVisibleArgumentMapping(::std::vector<sal_uInt16> &) const46             virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {}
initArgumentInfo() const47             virtual void initArgumentInfo()  const {}
getSignature() const48             virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); }
getHelpId() const49             virtual rtl::OString getHelpId() const { return ""; }
getParameterCount() const50             virtual sal_uInt32 getParameterCount() const { return 0; }
getParameterName(sal_uInt32) const51             virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); }
getParameterDescription(sal_uInt32) const52             virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); }
isParameterOptional(sal_uInt32) const53             virtual bool isParameterOptional(sal_uInt32 ) const { return sal_False; }
54         };
55     }
56 //===================================================================
57 //  class FormulaHelper - statische Methoden
58 //===================================================================
59 
60 #define FUNC_NOTFOUND 0xffff
61 
FormulaHelper(const IFunctionManager * _pFunctionManager)62 FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
63     :m_pSysLocale(new SvtSysLocale)
64     ,m_pFunctionManager(_pFunctionManager)
65     ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
66     ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
67     ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
68     ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
69     ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
70 {
71     m_pCharClass = m_pSysLocale->GetCharClassPtr();
72 }
GetNextFunc(const String & rFormula,sal_Bool bBack,xub_StrLen & rFStart,xub_StrLen * pFEnd,const IFunctionDescription ** ppFDesc,::std::vector<::rtl::OUString> * pArgs) const73 sal_Bool FormulaHelper::GetNextFunc( const String&  rFormula,
74                                  sal_Bool           bBack,
75                                  xub_StrLen&    rFStart,   // Ein- und Ausgabe
76                                  xub_StrLen*    pFEnd,     // = NULL
77                                  const IFunctionDescription**   ppFDesc,   // = NULL
78                                  ::std::vector< ::rtl::OUString>*   pArgs )  const // = NULL
79 {
80     sal_Bool        bFound = sal_False;
81     xub_StrLen  nOldStart = rFStart;
82     String      aFname;
83 
84     rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
85     bFound  = ( rFStart != FUNC_NOTFOUND );
86 
87     if ( bFound )
88     {
89         if ( pFEnd )
90             *pFEnd = GetFunctionEnd( rFormula, rFStart );
91 
92         if ( ppFDesc )
93         {
94             *ppFDesc = NULL;
95             const ::rtl::OUString sTemp( aFname );
96             const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
97             for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
98             {
99                 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
100                 const sal_uInt32 nCount = pCategory->getCount();
101                 for(sal_uInt32 i = 0 ; i < nCount; ++i)
102                 {
103                     const IFunctionDescription* pCurrent = pCategory->getFunction(i);
104                     if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) )
105                     {
106                         *ppFDesc = pCurrent;
107                         break;
108                     }
109                 } // for(sal_uInt32 i = 0 ; i < nCount; ++i)
110             }
111             if ( *ppFDesc && pArgs )
112             {
113                 GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
114             }
115             else
116             {
117                 static OEmptyFunctionDescription s_aFunctionDescription;
118                 *ppFDesc = &s_aFunctionDescription;
119             }
120         }
121     }
122     else
123         rFStart = nOldStart;
124 
125     return bFound;
126 }
127 
128 //------------------------------------------------------------------------
129 
FillArgStrings(const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs,::std::vector<::rtl::OUString> & _rArgs) const130 void FormulaHelper::FillArgStrings( const String&   rFormula,
131                                     xub_StrLen      nFuncPos,
132                                     sal_uInt16          nArgs,
133                                     ::std::vector< ::rtl::OUString >& _rArgs ) const
134 {
135     xub_StrLen  nStart  = 0;
136     xub_StrLen  nEnd    = 0;
137     sal_uInt16      i;
138     sal_Bool        bLast   = sal_False;
139 
140     for ( i=0; i<nArgs && !bLast; i++ )
141     {
142         nStart = GetArgStart( rFormula, nFuncPos, i );
143 
144         if ( i+1<nArgs ) // letztes Argument?
145         {
146             nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
147 
148             if ( nEnd != nStart )
149                 _rArgs.push_back(rFormula.Copy( nStart, nEnd-1-nStart ));
150             else
151                 _rArgs.push_back(String()), bLast = sal_True;
152         }
153         else
154         {
155             nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
156             if ( nStart < nEnd )
157                 _rArgs.push_back( rFormula.Copy( nStart, nEnd-nStart ) );
158             else
159                 _rArgs.push_back(String());
160         }
161     }
162 
163     if ( bLast )
164         for ( ; i<nArgs; i++ )
165             _rArgs.push_back(String());
166 }
167 
168 //------------------------------------------------------------------------
169 
GetArgStrings(::std::vector<::rtl::OUString> & _rArgs,const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs) const170 void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs
171                                       ,const String& rFormula,
172                                        xub_StrLen nFuncPos,
173                                        sal_uInt16 nArgs ) const
174 {
175     if (nArgs)
176     {
177         FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
178     }
179 }
180 
181 //------------------------------------------------------------------------
182 
IsFormulaText(const CharClass * _pCharClass,const String & rStr,xub_StrLen nPos)183 inline sal_Bool IsFormulaText( const CharClass* _pCharClass,const String& rStr, xub_StrLen nPos )
184 {
185     if( _pCharClass->isLetterNumeric( rStr, nPos ) )
186         return sal_True;
187     else
188     {   // In internationalized versions function names may contain a dot
189         //  and in every version also an underscore... ;-)
190         sal_Unicode c = rStr.GetChar(nPos);
191         return c == '.' || c == '_';
192     }
193 
194 }
195 
GetFunctionStart(const String & rFormula,xub_StrLen nStart,sal_Bool bBack,String * pFuncName) const196 xub_StrLen FormulaHelper::GetFunctionStart( const String&   rFormula,
197                                         xub_StrLen      nStart,
198                                         sal_Bool            bBack,
199                                         String*         pFuncName ) const
200 {
201     xub_StrLen nStrLen = rFormula.Len();
202 
203     if ( nStrLen < nStart )
204         return nStart;
205 
206     xub_StrLen  nFStart = FUNC_NOTFOUND;
207     xub_StrLen  nParPos = nStart;
208 
209     sal_Bool bRepeat, bFound;
210     do
211     {
212         bFound  = sal_False;
213         bRepeat = sal_False;
214 
215         if ( bBack )
216         {
217             while ( !bFound && (nParPos > 0) )
218             {
219                 if ( rFormula.GetChar(nParPos) == '"' )
220                 {
221                     nParPos--;
222                     while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' )
223                         nParPos--;
224                     if (nParPos > 0)
225                         nParPos--;
226                 }
227                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
228                     nParPos--;
229             }
230         }
231         else
232         {
233             while ( !bFound && (nParPos < nStrLen) )
234             {
235                 if ( rFormula.GetChar(nParPos) == '"' )
236                 {
237                     nParPos++;
238                     while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' )
239                         nParPos++;
240                     nParPos++;
241                 }
242                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
243                     nParPos++;
244             }
245         }
246 
247         if ( bFound && (nParPos > 0) )
248         {
249             nFStart = nParPos-1;
250 
251             while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
252                 nFStart--;
253         }
254 
255         nFStart++;
256 
257         if ( bFound )
258         {
259             if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
260             {
261                                     //  Funktion gefunden
262                 if ( pFuncName )
263                     *pFuncName = rFormula.Copy( nFStart, nParPos-nFStart );
264             }
265             else                    // Klammern ohne Funktion -> weitersuchen
266             {
267                 bRepeat = sal_True;
268                 if ( !bBack )
269                     nParPos++;
270                 else if (nParPos > 0)
271                     nParPos--;
272                 else
273                     bRepeat = sal_False;
274             }
275         }
276         else                        // keine Klammern gefunden
277         {
278             nFStart = FUNC_NOTFOUND;
279             if ( pFuncName )
280                 pFuncName->Erase();
281         }
282     }
283     while(bRepeat);
284 
285     return nFStart;
286 }
287 
288 //------------------------------------------------------------------------
289 
GetFunctionEnd(const String & rStr,xub_StrLen nStart) const290 xub_StrLen  FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const
291 {
292     xub_StrLen nStrLen = rStr.Len();
293 
294     if ( nStrLen < nStart )
295         return nStart;
296 
297     short   nParCount = 0;
298     bool    bInArray = false;
299     sal_Bool    bFound = sal_False;
300 
301     while ( !bFound && (nStart < nStrLen) )
302     {
303         sal_Unicode c = rStr.GetChar(nStart);
304 
305         if ( c == '"' )
306         {
307             nStart++;
308             while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
309                 nStart++;
310         }
311         else if ( c == open )
312             nParCount++;
313         else if ( c == close )
314         {
315             nParCount--;
316             if ( nParCount == 0 )
317                 bFound = sal_True;
318             else if ( nParCount < 0 )
319             {
320                 bFound = sal_True;
321                 nStart--;   // einen zu weit gelesen
322             }
323         }
324         else if ( c == arrayOpen )
325         {
326             bInArray = true;
327         }
328         else if ( c == arrayClose )
329         {
330             bInArray = false;
331         }
332         else if ( c == sep )
333         {
334             if ( !bInArray && nParCount == 0 )
335             {
336                 bFound = sal_True;
337                 nStart--;   // einen zu weit gelesen
338             }
339         }
340         nStart++; // hinter gefundene Position stellen
341     }
342 
343     return nStart;
344 }
345 
346 //------------------------------------------------------------------
347 
GetArgStart(const String & rStr,xub_StrLen nStart,sal_uInt16 nArg) const348 xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const
349 {
350     xub_StrLen nStrLen = rStr.Len();
351 
352     if ( nStrLen < nStart )
353         return nStart;
354 
355     short   nParCount   = 0;
356     bool    bInArray    = false;
357     sal_Bool    bFound      = sal_False;
358 
359     while ( !bFound && (nStart < nStrLen) )
360     {
361         sal_Unicode c = rStr.GetChar(nStart);
362 
363         if ( c == '"' )
364         {
365             nStart++;
366             while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
367                 nStart++;
368         }
369         else if ( c == open )
370         {
371             bFound = ( nArg == 0 );
372             nParCount++;
373         }
374         else if ( c == close )
375         {
376             nParCount--;
377             bFound = ( nParCount == 0 );
378         }
379         else if ( c == arrayOpen )
380         {
381             bInArray = true;
382         }
383         else if ( c == arrayClose )
384         {
385             bInArray = false;
386         }
387         else if ( c == sep )
388         {
389             if ( !bInArray && nParCount == 1 )
390             {
391                 nArg--;
392                 bFound = ( nArg == 0  );
393             }
394         }
395         nStart++;
396     }
397 
398     return nStart;
399 }
400 // =============================================================================
401 } // formula
402 // =============================================================================
403