xref: /trunk/main/formula/source/ui/dlg/FormulaHelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #include "precompiled_formula.hxx"
28 
29 #include "formula/formulahelper.hxx"
30 #include <unotools/charclass.hxx>
31 #include <unotools/syslocale.hxx>
32 
33 namespace formula
34 {
35 
36     namespace
37     {
38         //============================================================================
39         class OEmptyFunctionDescription : public IFunctionDescription
40         {
41         public:
42             OEmptyFunctionDescription(){}
43             virtual ~OEmptyFunctionDescription(){}
44 
45             virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); }
46             virtual const IFunctionCategory* getCategory() const { return NULL; }
47             virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); }
48             virtual xub_StrLen getSuppressedArgumentCount() const { return 0; }
49             virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); }
50             virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {}
51             virtual void initArgumentInfo()  const {}
52             virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); }
53             virtual rtl::OString getHelpId() const { return ""; }
54             virtual sal_uInt32 getParameterCount() const { return 0; }
55             virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); }
56             virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); }
57             virtual bool isParameterOptional(sal_uInt32 ) const { return sal_False; }
58         };
59     }
60 //===================================================================
61 //  class FormulaHelper - statische Methoden
62 //===================================================================
63 
64 #define FUNC_NOTFOUND 0xffff
65 
66 FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
67     :m_pSysLocale(new SvtSysLocale)
68     ,m_pFunctionManager(_pFunctionManager)
69     ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
70     ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
71     ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
72     ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
73     ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
74 {
75     m_pCharClass = m_pSysLocale->GetCharClassPtr();
76 }
77 sal_Bool FormulaHelper::GetNextFunc( const String&  rFormula,
78                                  sal_Bool           bBack,
79                                  xub_StrLen&    rFStart,   // Ein- und Ausgabe
80                                  xub_StrLen*    pFEnd,     // = NULL
81                                  const IFunctionDescription**   ppFDesc,   // = NULL
82                                  ::std::vector< ::rtl::OUString>*   pArgs )  const // = NULL
83 {
84     sal_Bool        bFound = sal_False;
85     xub_StrLen  nOldStart = rFStart;
86     String      aFname;
87 
88     rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
89     bFound  = ( rFStart != FUNC_NOTFOUND );
90 
91     if ( bFound )
92     {
93         if ( pFEnd )
94             *pFEnd = GetFunctionEnd( rFormula, rFStart );
95 
96         if ( ppFDesc )
97         {
98             *ppFDesc = NULL;
99             const ::rtl::OUString sTemp( aFname );
100             const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
101             for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
102             {
103                 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
104                 const sal_uInt32 nCount = pCategory->getCount();
105                 for(sal_uInt32 i = 0 ; i < nCount; ++i)
106                 {
107                     const IFunctionDescription* pCurrent = pCategory->getFunction(i);
108                     if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) )
109                     {
110                         *ppFDesc = pCurrent;
111                         break;
112                     }
113                 } // for(sal_uInt32 i = 0 ; i < nCount; ++i)
114             }
115             if ( *ppFDesc && pArgs )
116             {
117                 GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
118             }
119             else
120             {
121                 static OEmptyFunctionDescription s_aFunctionDescription;
122                 *ppFDesc = &s_aFunctionDescription;
123             }
124         }
125     }
126     else
127         rFStart = nOldStart;
128 
129     return bFound;
130 }
131 
132 //------------------------------------------------------------------------
133 
134 void FormulaHelper::FillArgStrings( const String&   rFormula,
135                                     xub_StrLen      nFuncPos,
136                                     sal_uInt16          nArgs,
137                                     ::std::vector< ::rtl::OUString >& _rArgs ) const
138 {
139     xub_StrLen  nStart  = 0;
140     xub_StrLen  nEnd    = 0;
141     sal_uInt16      i;
142     sal_Bool        bLast   = sal_False;
143 
144     for ( i=0; i<nArgs && !bLast; i++ )
145     {
146         nStart = GetArgStart( rFormula, nFuncPos, i );
147 
148         if ( i+1<nArgs ) // letztes Argument?
149         {
150             nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
151 
152             if ( nEnd != nStart )
153                 _rArgs.push_back(rFormula.Copy( nStart, nEnd-1-nStart ));
154             else
155                 _rArgs.push_back(String()), bLast = sal_True;
156         }
157         else
158         {
159             nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
160             if ( nStart < nEnd )
161                 _rArgs.push_back( rFormula.Copy( nStart, nEnd-nStart ) );
162             else
163                 _rArgs.push_back(String());
164         }
165     }
166 
167     if ( bLast )
168         for ( ; i<nArgs; i++ )
169             _rArgs.push_back(String());
170 }
171 
172 //------------------------------------------------------------------------
173 
174 void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs
175                                       ,const String& rFormula,
176                                        xub_StrLen nFuncPos,
177                                        sal_uInt16 nArgs ) const
178 {
179     if (nArgs)
180     {
181         FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
182     }
183 }
184 
185 //------------------------------------------------------------------------
186 
187 inline sal_Bool IsFormulaText( const CharClass* _pCharClass,const String& rStr, xub_StrLen nPos )
188 {
189     if( _pCharClass->isLetterNumeric( rStr, nPos ) )
190         return sal_True;
191     else
192     {   // In internationalized versions function names may contain a dot
193         //  and in every version also an underscore... ;-)
194         sal_Unicode c = rStr.GetChar(nPos);
195         return c == '.' || c == '_';
196     }
197 
198 }
199 
200 xub_StrLen FormulaHelper::GetFunctionStart( const String&   rFormula,
201                                         xub_StrLen      nStart,
202                                         sal_Bool            bBack,
203                                         String*         pFuncName ) const
204 {
205     xub_StrLen nStrLen = rFormula.Len();
206 
207     if ( nStrLen < nStart )
208         return nStart;
209 
210     xub_StrLen  nFStart = FUNC_NOTFOUND;
211     xub_StrLen  nParPos = nStart;
212 
213     sal_Bool bRepeat, bFound;
214     do
215     {
216         bFound  = sal_False;
217         bRepeat = sal_False;
218 
219         if ( bBack )
220         {
221             while ( !bFound && (nParPos > 0) )
222             {
223                 if ( rFormula.GetChar(nParPos) == '"' )
224                 {
225                     nParPos--;
226                     while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' )
227                         nParPos--;
228                     if (nParPos > 0)
229                         nParPos--;
230                 }
231                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
232                     nParPos--;
233             }
234         }
235         else
236         {
237             while ( !bFound && (nParPos < nStrLen) )
238             {
239                 if ( rFormula.GetChar(nParPos) == '"' )
240                 {
241                     nParPos++;
242                     while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' )
243                         nParPos++;
244                     nParPos++;
245                 }
246                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
247                     nParPos++;
248             }
249         }
250 
251         if ( bFound && (nParPos > 0) )
252         {
253             nFStart = nParPos-1;
254 
255             while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
256                 nFStart--;
257         }
258 
259         nFStart++;
260 
261         if ( bFound )
262         {
263             if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
264             {
265                                     //  Funktion gefunden
266                 if ( pFuncName )
267                     *pFuncName = rFormula.Copy( nFStart, nParPos-nFStart );
268             }
269             else                    // Klammern ohne Funktion -> weitersuchen
270             {
271                 bRepeat = sal_True;
272                 if ( !bBack )
273                     nParPos++;
274                 else if (nParPos > 0)
275                     nParPos--;
276                 else
277                     bRepeat = sal_False;
278             }
279         }
280         else                        // keine Klammern gefunden
281         {
282             nFStart = FUNC_NOTFOUND;
283             if ( pFuncName )
284                 pFuncName->Erase();
285         }
286     }
287     while(bRepeat);
288 
289     return nFStart;
290 }
291 
292 //------------------------------------------------------------------------
293 
294 xub_StrLen  FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const
295 {
296     xub_StrLen nStrLen = rStr.Len();
297 
298     if ( nStrLen < nStart )
299         return nStart;
300 
301     short   nParCount = 0;
302     bool    bInArray = false;
303     sal_Bool    bFound = sal_False;
304 
305     while ( !bFound && (nStart < nStrLen) )
306     {
307         sal_Unicode c = rStr.GetChar(nStart);
308 
309         if ( c == '"' )
310         {
311             nStart++;
312             while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
313                 nStart++;
314         }
315         else if ( c == open )
316             nParCount++;
317         else if ( c == close )
318         {
319             nParCount--;
320             if ( nParCount == 0 )
321                 bFound = sal_True;
322             else if ( nParCount < 0 )
323             {
324                 bFound = sal_True;
325                 nStart--;   // einen zu weit gelesen
326             }
327         }
328         else if ( c == arrayOpen )
329         {
330             bInArray = true;
331         }
332         else if ( c == arrayClose )
333         {
334             bInArray = false;
335         }
336         else if ( c == sep )
337         {
338             if ( !bInArray && nParCount == 0 )
339             {
340                 bFound = sal_True;
341                 nStart--;   // einen zu weit gelesen
342             }
343         }
344         nStart++; // hinter gefundene Position stellen
345     }
346 
347     return nStart;
348 }
349 
350 //------------------------------------------------------------------
351 
352 xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const
353 {
354     xub_StrLen nStrLen = rStr.Len();
355 
356     if ( nStrLen < nStart )
357         return nStart;
358 
359     short   nParCount   = 0;
360     bool    bInArray    = false;
361     sal_Bool    bFound      = sal_False;
362 
363     while ( !bFound && (nStart < nStrLen) )
364     {
365         sal_Unicode c = rStr.GetChar(nStart);
366 
367         if ( c == '"' )
368         {
369             nStart++;
370             while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
371                 nStart++;
372         }
373         else if ( c == open )
374         {
375             bFound = ( nArg == 0 );
376             nParCount++;
377         }
378         else if ( c == close )
379         {
380             nParCount--;
381             bFound = ( nParCount == 0 );
382         }
383         else if ( c == arrayOpen )
384         {
385             bInArray = true;
386         }
387         else if ( c == arrayClose )
388         {
389             bInArray = false;
390         }
391         else if ( c == sep )
392         {
393             if ( !bInArray && nParCount == 1 )
394             {
395                 nArg--;
396                 bFound = ( nArg == 0  );
397             }
398         }
399         nStart++;
400     }
401 
402     return nStart;
403 }
404 // =============================================================================
405 } // formula
406 // =============================================================================
407