xref: /AOO41X/main/formula/source/ui/dlg/FormulaHelper.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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