xref: /trunk/main/sc/source/core/tool/rangeutl.cxx (revision 22407013)
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 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 // INCLUDE ---------------------------------------------------------------
30 
31 #include <tools/debug.hxx>
32 
33 #include "rangeutl.hxx"
34 #include "document.hxx"
35 #include "global.hxx"
36 #include "dbcolect.hxx"
37 #include "rangenam.hxx"
38 #include "scresid.hxx"
39 #include "globstr.hrc"
40 #include "convuno.hxx"
41 #include "externalrefmgr.hxx"
42 #include "compiler.hxx"
43 
44 using ::rtl::OUString;
45 using ::rtl::OUStringBuffer;
46 using ::formula::FormulaGrammar;
47 using namespace ::com::sun::star;
48 
49 //------------------------------------------------------------------------
50 
MakeArea(const String & rAreaStr,ScArea & rArea,ScDocument * pDoc,SCTAB nTab,ScAddress::Details const & rDetails) const51 sal_Bool ScRangeUtil::MakeArea( const String&	rAreaStr,
52 							ScArea&			rArea,
53 							ScDocument*		pDoc,
54 							SCTAB			nTab,
55 							ScAddress::Details const & rDetails ) const
56 {
57 	// Eingabe in rAreaStr: "$Tabelle1.$A1:$D17"
58 
59 	// BROKEN BROKEN BROKEN
60 	// but it is only used in the consolidate dialog.  Ignore for now.
61 
62 	sal_Bool		nSuccess	= sal_False;
63 	sal_uInt16		nPointPos	= rAreaStr.Search('.');
64 	sal_uInt16		nColonPos	= rAreaStr.Search(':');
65 	String		aStrArea( rAreaStr );
66 	ScRefAddress	startPos;
67 	ScRefAddress	endPos;
68 
69 	if ( nColonPos == STRING_NOTFOUND )
70 		if ( nPointPos != STRING_NOTFOUND )
71 		{
72 			aStrArea += ':';
73 			aStrArea += rAreaStr.Copy( nPointPos+1 ); // '.' nicht mitkopieren
74 		}
75 
76 	nSuccess = ConvertDoubleRef( pDoc, aStrArea, nTab, startPos, endPos, rDetails );
77 
78 	if ( nSuccess )
79 		rArea = ScArea( startPos.Tab(),
80 						startPos.Col(),	startPos.Row(),
81 						endPos.Col(),	endPos.Row() );
82 
83 	return nSuccess;
84 }
85 
86 //------------------------------------------------------------------------
87 
CutPosString(const String & theAreaStr,String & thePosStr) const88 void ScRangeUtil::CutPosString( const String&	theAreaStr,
89 								String&			thePosStr ) const
90 {
91 	String	aPosStr;
92 	// BROKEN BROKEN BROKEN
93 	// but it is only used in the consolidate dialog.  Ignore for now.
94 
95 	sal_uInt16	nColonPos = theAreaStr.Search(':');
96 
97 	if ( nColonPos != STRING_NOTFOUND )
98 		aPosStr = theAreaStr.Copy( 0, nColonPos ); // ':' nicht mitkopieren
99 	else
100 		aPosStr = theAreaStr;
101 
102 	thePosStr = aPosStr;
103 }
104 
105 //------------------------------------------------------------------------
106 
IsAbsTabArea(const String & rAreaStr,ScDocument * pDoc,ScArea *** pppAreas,sal_uInt16 * pAreaCount,sal_Bool,ScAddress::Details const & rDetails) const107 sal_Bool ScRangeUtil::IsAbsTabArea( const String& 	rAreaStr,
108 								ScDocument*		pDoc,
109 								ScArea***		pppAreas,
110 								sal_uInt16*			pAreaCount,
111                                 sal_Bool            /* bAcceptCellRef */,
112 								ScAddress::Details const & rDetails ) const
113 {
114 	DBG_ASSERT( pDoc, "Kein Dokument uebergeben!" );
115 	if ( !pDoc )
116 		return sal_False;
117 
118 	// BROKEN BROKEN BROKEN
119 	// but it is only used in the consolidate dialog.  Ignore for now.
120 
121 	/*
122 	 * Erwartet wird ein String der Form
123 	 *		"$Tabelle1.$A$1:$Tabelle3.$D$17"
124 	 * Wenn bAcceptCellRef == sal_True ist, wird auch ein String der Form
125 	 *		"$Tabelle1.$A$1"
126 	 * akzeptiert.
127 	 *
128 	 * als Ergebnis wird ein ScArea-Array angelegt,
129 	 * welches ueber ppAreas bekannt gegeben wird und auch
130 	 * wieder geloescht werden muss!
131 	 */
132 
133 	sal_Bool	bStrOk = sal_False;
134 	String	aTempAreaStr(rAreaStr);
135 	String	aStartPosStr;
136 	String	aEndPosStr;
137 
138 	if ( STRING_NOTFOUND == aTempAreaStr.Search(':') )
139 	{
140 		aTempAreaStr.Append(':');
141 		aTempAreaStr.Append(rAreaStr);
142 	}
143 
144 	sal_uInt16	 nColonPos = aTempAreaStr.Search(':');
145 
146 	if (   STRING_NOTFOUND != nColonPos
147 		&& STRING_NOTFOUND != aTempAreaStr.Search('.') )
148 	{
149 		ScRefAddress	aStartPos;
150 		ScRefAddress	aEndPos;
151 
152 		aStartPosStr = aTempAreaStr.Copy( 0,		   nColonPos  );
153 		aEndPosStr	 = aTempAreaStr.Copy( nColonPos+1, STRING_LEN );
154 
155 		if ( ConvertSingleRef( pDoc, aStartPosStr, 0, aStartPos, rDetails ) )
156 		{
157 			if ( ConvertSingleRef( pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) )
158 			{
159 				aStartPos.SetRelCol( sal_False );
160 				aStartPos.SetRelRow( sal_False );
161 				aStartPos.SetRelTab( sal_False );
162 				aEndPos.SetRelCol( sal_False );
163 				aEndPos.SetRelRow( sal_False );
164 				aEndPos.SetRelTab( sal_False );
165 
166 				bStrOk = sal_True;
167 
168 				if ( pppAreas && pAreaCount ) // Array zurueckgegeben?
169 				{
170 					SCTAB		nStartTab	= aStartPos.Tab();
171 					SCTAB		nEndTab		= aEndPos.Tab();
172 					sal_uInt16		nTabCount	= static_cast<sal_uInt16>(nEndTab-nStartTab+1);
173 					ScArea** 	theAreas	= new ScArea*[nTabCount];
174 					SCTAB		nTab		= 0;
175 					sal_uInt16		i			= 0;
176 					ScArea		theArea( 0, aStartPos.Col(), aStartPos.Row(),
177 											aEndPos.Col(), aEndPos.Row() );
178 
179 					nTab = nStartTab;
180 					for ( i=0; i<nTabCount; i++ )
181 					{
182 						theAreas[i] = new ScArea( theArea );
183 						theAreas[i]->nTab = nTab;
184 						nTab++;
185 					}
186 					*pppAreas   = theAreas;
187 					*pAreaCount = nTabCount;
188 				}
189 			}
190 		}
191 	}
192 
193 	return bStrOk;
194 }
195 
196 //------------------------------------------------------------------------
197 
IsAbsArea(const String & rAreaStr,ScDocument * pDoc,SCTAB nTab,String * pCompleteStr,ScRefAddress * pStartPos,ScRefAddress * pEndPos,ScAddress::Details const & rDetails) const198 sal_Bool ScRangeUtil::IsAbsArea( const String&	rAreaStr,
199 							 ScDocument*	pDoc,
200 							 SCTAB			nTab,
201 							 String*		pCompleteStr,
202 							 ScRefAddress*	pStartPos,
203 							 ScRefAddress*	pEndPos,
204 							 ScAddress::Details const & rDetails ) const
205 {
206 	sal_Bool		bIsAbsArea = sal_False;
207 	ScRefAddress	startPos;
208 	ScRefAddress	endPos;
209 
210 	bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails );
211 
212 	if ( bIsAbsArea )
213 	{
214 		startPos.SetRelCol( sal_False );
215 		startPos.SetRelRow( sal_False );
216 		startPos.SetRelTab( sal_False );
217 		endPos  .SetRelCol( sal_False );
218 		endPos  .SetRelRow( sal_False );
219 		endPos  .SetRelTab( sal_False );
220 
221 		if ( pCompleteStr )
222 		{
223 			*pCompleteStr  = startPos.GetRefString( pDoc, MAXTAB+1, rDetails );
224 			*pCompleteStr += ':';
225 			*pCompleteStr += endPos  .GetRefString( pDoc, nTab, rDetails );
226 		}
227 
228 		if ( pStartPos && pEndPos )
229 		{
230 			*pStartPos = startPos;
231 			*pEndPos   = endPos;
232 		}
233 	}
234 
235 	return bIsAbsArea;
236 }
237 
238 //------------------------------------------------------------------------
239 
IsAbsPos(const String & rPosStr,ScDocument * pDoc,SCTAB nTab,String * pCompleteStr,ScRefAddress * pPosTripel,ScAddress::Details const & rDetails) const240 sal_Bool ScRangeUtil::IsAbsPos( const String&	rPosStr,
241 							ScDocument*		pDoc,
242 							SCTAB			nTab,
243 							String*			pCompleteStr,
244 							ScRefAddress*	pPosTripel,
245 							ScAddress::Details const & rDetails ) const
246 {
247 	sal_Bool		bIsAbsPos = sal_False;
248 	ScRefAddress	thePos;
249 
250 	bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails );
251 	thePos.SetRelCol( sal_False );
252 	thePos.SetRelRow( sal_False );
253 	thePos.SetRelTab( sal_False );
254 
255 	if ( bIsAbsPos )
256 	{
257 		if ( pPosTripel )
258 			*pPosTripel = thePos;
259 		if ( pCompleteStr )
260 			*pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails );
261 	}
262 
263 	return bIsAbsPos;
264 }
265 
266 //------------------------------------------------------------------------
267 
MakeRangeFromName(const String & rName,ScDocument * pDoc,SCTAB nCurTab,ScRange & rRange,RutlNameScope eScope,ScAddress::Details const & rDetails) const268 sal_Bool ScRangeUtil::MakeRangeFromName	(
269 	const String&	rName,
270 	ScDocument*		pDoc,
271 	SCTAB			nCurTab,
272 	ScRange&		rRange,
273 	RutlNameScope 	eScope,
274 	ScAddress::Details const & rDetails ) const
275 {
276 	sal_Bool bResult=sal_False;
277 	ScRangeUtil		aRangeUtil;
278     SCTAB nTab = 0;
279     SCCOL nColStart = 0;
280     SCCOL nColEnd = 0;
281     SCROW nRowStart = 0;
282     SCROW nRowEnd = 0;
283 
284 	if( eScope==RUTL_NAMES )
285 	{
286 		ScRangeName& rRangeNames = *(pDoc->GetRangeName());
287 		sal_uInt16		 nAt		 = 0;
288 
289 		if ( rRangeNames.SearchName( rName, nAt ) )
290 		{
291 			ScRangeData* pData = rRangeNames[nAt];
292 			String		 aStrArea;
293 			ScRefAddress	 aStartPos;
294 			ScRefAddress	 aEndPos;
295 
296 			pData->GetSymbol( aStrArea );
297 
298 			if ( IsAbsArea( aStrArea, pDoc, nCurTab,
299 							NULL, &aStartPos, &aEndPos, rDetails ) )
300 			{
301 				nTab	   = aStartPos.Tab();
302 				nColStart  = aStartPos.Col();
303 				nRowStart  = aStartPos.Row();
304 				nColEnd    = aEndPos.Col();
305 				nRowEnd    = aEndPos.Row();
306 				bResult	   = sal_True;
307 			}
308 			else
309 			{
310 				CutPosString( aStrArea, aStrArea );
311 
312 				if ( IsAbsPos( aStrArea, pDoc, nCurTab,
313 										  NULL, &aStartPos, rDetails ) )
314 				{
315 					nTab	   = aStartPos.Tab();
316 					nColStart  = nColEnd = aStartPos.Col();
317 					nRowStart  = nRowEnd = aStartPos.Row();
318 					bResult	   = sal_True;
319 				}
320 			}
321 		}
322 	}
323 	else if( eScope==RUTL_DBASE )
324 	{
325 		ScDBCollection&	rDbNames = *(pDoc->GetDBCollection());
326 		sal_uInt16		 	nAt = 0;
327 
328 		if ( rDbNames.SearchName( rName, nAt ) )
329 		{
330 			ScDBData* pData = rDbNames[nAt];
331 
332 			pData->GetArea( nTab, nColStart, nRowStart,
333 								  nColEnd,	 nRowEnd );
334 			bResult = sal_True;
335 		}
336 	}
337 	else
338 	{
339 		DBG_ERROR( "ScRangeUtil::MakeRangeFromName" );
340 	}
341 
342 	if( bResult )
343 	{
344 		rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab );
345 	}
346 
347 	return bResult;
348 }
349 
350 //========================================================================
351 
AssignString(OUString & rString,const OUString & rNewStr,sal_Bool bAppendStr,sal_Unicode cSeperator)352 void ScRangeStringConverter::AssignString(
353 		OUString& rString,
354 		const OUString& rNewStr,
355         sal_Bool bAppendStr,
356         sal_Unicode cSeperator)
357 {
358 	if( bAppendStr )
359 	{
360 		if( rNewStr.getLength() )
361 		{
362 			if( rString.getLength() )
363                 rString += rtl::OUString(cSeperator);
364 			rString += rNewStr;
365 		}
366 	}
367 	else
368 		rString = rNewStr;
369 }
370 
IndexOf(const OUString & rString,sal_Unicode cSearchChar,sal_Int32 nOffset,sal_Unicode cQuote)371 sal_Int32 ScRangeStringConverter::IndexOf(
372 		const OUString& rString,
373 		sal_Unicode cSearchChar,
374 		sal_Int32 nOffset,
375 		sal_Unicode cQuote )
376 {
377 	sal_Int32		nLength		= rString.getLength();
378 	sal_Int32		nIndex		= nOffset;
379 	sal_Bool		bQuoted		= sal_False;
380 	sal_Bool		bExitLoop	= sal_False;
381 
382 	while( !bExitLoop && (nIndex < nLength) )
383 	{
384 		sal_Unicode cCode = rString[ nIndex ];
385 		bExitLoop = (cCode == cSearchChar) && !bQuoted;
386 		bQuoted = (bQuoted != (cCode == cQuote));
387 		if( !bExitLoop )
388 			nIndex++;
389 	}
390 	return (nIndex < nLength) ? nIndex : -1;
391 }
392 
IndexOfDifferent(const OUString & rString,sal_Unicode cSearchChar,sal_Int32 nOffset)393 sal_Int32 ScRangeStringConverter::IndexOfDifferent(
394 		const OUString& rString,
395 		sal_Unicode cSearchChar,
396 		sal_Int32 nOffset )
397 {
398 	sal_Int32		nLength		= rString.getLength();
399 	sal_Int32		nIndex		= nOffset;
400 	sal_Bool		bExitLoop	= sal_False;
401 
402 	while( !bExitLoop && (nIndex < nLength) )
403 	{
404 		bExitLoop = (rString[ nIndex ] != cSearchChar);
405 		if( !bExitLoop )
406 			nIndex++;
407 	}
408 	return (nIndex < nLength) ? nIndex : -1;
409 }
410 
GetTokenByOffset(OUString & rToken,const OUString & rString,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)411 void ScRangeStringConverter::GetTokenByOffset(
412 		OUString& rToken,
413 		const OUString& rString,
414 		sal_Int32& nOffset,
415         sal_Unicode cSeperator,
416 		sal_Unicode cQuote)
417 {
418 	sal_Int32 nLength = rString.getLength();
419 	if( nOffset >= nLength )
420 	{
421 		rToken = OUString();
422 		nOffset = -1;
423 	}
424 	else
425 	{
426 		sal_Int32 nTokenEnd = IndexOf( rString, cSeperator, nOffset, cQuote );
427 		if( nTokenEnd < 0 )
428 			nTokenEnd = nLength;
429 		rToken = rString.copy( nOffset, nTokenEnd - nOffset );
430 
431 		sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeperator, nTokenEnd );
432 		nOffset = (nNextBegin < 0) ? nLength : nNextBegin;
433 	}
434 }
435 
AppendTableName(OUStringBuffer & rBuf,const OUString & rTabName,sal_Unicode)436 void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode /* cQuote */)
437 {
438     // quote character is always "'"
439     String aQuotedTab(rTabName);
440     ScCompiler::CheckTabQuotes(aQuotedTab, ::formula::FormulaGrammar::CONV_OOO);
441     rBuf.append(aQuotedTab);
442 }
443 
GetTokenCount(const OUString & rString,sal_Unicode cSeperator,sal_Unicode cQuote)444 sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote )
445 {
446 	OUString	sToken;
447 	sal_Int32	nCount = 0;
448 	sal_Int32	nOffset = 0;
449 	while( nOffset >= 0 )
450 	{
451 		GetTokenByOffset( sToken, rString, nOffset, cQuote, cSeperator );
452 		if( nOffset >= 0 )
453 			nCount++;
454 	}
455 	return nCount;
456 }
457 
458 //___________________________________________________________________
459 
GetAddressFromString(ScAddress & rAddress,const OUString & rAddressStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)460 sal_Bool ScRangeStringConverter::GetAddressFromString(
461 		ScAddress& rAddress,
462 		const OUString& rAddressStr,
463 		const ScDocument* pDocument,
464         FormulaGrammar::AddressConvention eConv,
465 		sal_Int32& nOffset,
466         sal_Unicode cSeperator,
467         sal_Unicode cQuote )
468 {
469 	OUString sToken;
470 	GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote );
471 	if( nOffset >= 0 )
472     {
473         if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID)
474             return true;
475     }
476 	return sal_False;
477 }
478 
GetRangeFromString(ScRange & rRange,const OUString & rRangeStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)479 sal_Bool ScRangeStringConverter::GetRangeFromString(
480 		ScRange& rRange,
481 		const OUString& rRangeStr,
482 		const ScDocument* pDocument,
483         FormulaGrammar::AddressConvention eConv,
484 		sal_Int32& nOffset,
485         sal_Unicode cSeperator,
486         sal_Unicode cQuote )
487 {
488 	OUString sToken;
489 	sal_Bool bResult(sal_False);
490 	GetTokenByOffset( sToken, rRangeStr, nOffset, cSeperator, cQuote );
491 	if( nOffset >= 0 )
492 	{
493         sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote );
494         String aUIString(sToken);
495 
496         if( nIndex < 0 )
497         {
498             if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
499                 aUIString.Erase( 0, 1 );
500             bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
501             rRange.aEnd = rRange.aStart;
502         }
503         else
504         {
505             if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
506             {
507                 aUIString.Erase( 0, 1 );
508                 --nIndex;
509             }
510 
511             if ( nIndex < aUIString.Len() - 1 &&
512                     aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
513                 aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
514 
515             bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
516 
517             // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
518             // This isn't parsed by ScRange, so try to parse the two Addresses then.
519             if (!bResult)
520             {
521                 bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
522                                 eConv) & SCA_VALID) == SCA_VALID) &&
523                           ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
524                                 eConv) & SCA_VALID) == SCA_VALID);
525             }
526         }
527     }
528 	return bResult;
529 }
530 
GetRangeListFromString(ScRangeList & rRangeList,const OUString & rRangeListStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Unicode cQuote)531 sal_Bool ScRangeStringConverter::GetRangeListFromString(
532 		ScRangeList& rRangeList,
533 		const OUString& rRangeListStr,
534 		const ScDocument* pDocument,
535         FormulaGrammar::AddressConvention eConv,
536         sal_Unicode cSeperator,
537         sal_Unicode cQuote )
538 {
539     sal_Bool bRet = sal_True;
540 	DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
541 	sal_Int32 nOffset = 0;
542 	while( nOffset >= 0 )
543 	{
544 		ScRange* pRange = new ScRange;
545 		if( GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
546 			rRangeList.Insert( pRange, LIST_APPEND );
547         else if (nOffset > -1)
548             bRet = sal_False;
549 	}
550     return bRet;
551 }
552 
553 
554 //___________________________________________________________________
555 
GetAreaFromString(ScArea & rArea,const OUString & rRangeStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)556 sal_Bool ScRangeStringConverter::GetAreaFromString(
557 		ScArea& rArea,
558 		const OUString& rRangeStr,
559 		const ScDocument* pDocument,
560         FormulaGrammar::AddressConvention eConv,
561 		sal_Int32& nOffset,
562         sal_Unicode cSeperator,
563         sal_Unicode cQuote )
564 {
565 	ScRange aScRange;
566 	sal_Bool bResult(sal_False);
567 	if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
568 	{
569 		rArea.nTab = aScRange.aStart.Tab();
570 		rArea.nColStart = aScRange.aStart.Col();
571 		rArea.nRowStart = aScRange.aStart.Row();
572 		rArea.nColEnd = aScRange.aEnd.Col();
573 		rArea.nRowEnd = aScRange.aEnd.Row();
574 		bResult = sal_True;
575 	}
576 	return bResult;
577 }
578 
579 
580 //___________________________________________________________________
581 
GetAddressFromString(table::CellAddress & rAddress,const OUString & rAddressStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)582 sal_Bool ScRangeStringConverter::GetAddressFromString(
583 		table::CellAddress& rAddress,
584 		const OUString& rAddressStr,
585 		const ScDocument* pDocument,
586         FormulaGrammar::AddressConvention eConv,
587 		sal_Int32& nOffset,
588         sal_Unicode cSeperator,
589         sal_Unicode cQuote )
590 {
591 	ScAddress aScAddress;
592 	sal_Bool bResult(sal_False);
593 	if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
594 	{
595 		ScUnoConversion::FillApiAddress( rAddress, aScAddress );
596 		bResult = sal_True;
597 	}
598 	return bResult;
599 }
600 
GetRangeFromString(table::CellRangeAddress & rRange,const OUString & rRangeStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Int32 & nOffset,sal_Unicode cSeperator,sal_Unicode cQuote)601 sal_Bool ScRangeStringConverter::GetRangeFromString(
602 		table::CellRangeAddress& rRange,
603 		const OUString& rRangeStr,
604 		const ScDocument* pDocument,
605         FormulaGrammar::AddressConvention eConv,
606 		sal_Int32& nOffset,
607         sal_Unicode cSeperator,
608         sal_Unicode cQuote )
609 {
610 	ScRange aScRange;
611 	sal_Bool bResult(sal_False);
612 	if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
613 	{
614 		ScUnoConversion::FillApiRange( rRange, aScRange );
615 		bResult = sal_True;
616 	}
617 	return bResult;
618 }
619 
GetRangeListFromString(uno::Sequence<table::CellRangeAddress> & rRangeSeq,const OUString & rRangeListStr,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Unicode cQuote)620 sal_Bool ScRangeStringConverter::GetRangeListFromString(
621 		uno::Sequence< table::CellRangeAddress >& rRangeSeq,
622 		const OUString& rRangeListStr,
623 		const ScDocument* pDocument,
624         FormulaGrammar::AddressConvention eConv,
625         sal_Unicode cSeperator,
626         sal_Unicode cQuote )
627 {
628     sal_Bool bRet = sal_True;
629 	DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
630 	table::CellRangeAddress aRange;
631 	sal_Int32 nOffset = 0;
632 	while( nOffset >= 0 )
633 	{
634 		if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
635 		{
636 			rRangeSeq.realloc( rRangeSeq.getLength() + 1 );
637 			rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange;
638 		}
639         else
640             bRet = sal_False;
641 	}
642     return bRet;
643 }
644 
645 
646 //___________________________________________________________________
647 
GetStringFromAddress(OUString & rString,const ScAddress & rAddress,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Bool bAppendStr,sal_uInt16 nFormatFlags)648 void ScRangeStringConverter::GetStringFromAddress(
649 		OUString& rString,
650 		const ScAddress& rAddress,
651 		const ScDocument* pDocument,
652         FormulaGrammar::AddressConvention eConv,
653         sal_Unicode cSeperator,
654 		sal_Bool bAppendStr,
655 		sal_uInt16 nFormatFlags )
656 {
657 	if (pDocument && pDocument->HasTable(rAddress.Tab()))
658 	{
659 		String sAddress;
660 		rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
661 		AssignString( rString, sAddress, bAppendStr, cSeperator );
662 	}
663 }
664 
GetStringFromRange(OUString & rString,const ScRange & rRange,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Bool bAppendStr,sal_uInt16 nFormatFlags)665 void ScRangeStringConverter::GetStringFromRange(
666 		OUString& rString,
667 		const ScRange& rRange,
668 		const ScDocument* pDocument,
669         FormulaGrammar::AddressConvention eConv,
670         sal_Unicode cSeperator,
671 		sal_Bool bAppendStr,
672 		sal_uInt16 nFormatFlags )
673 {
674 	if (pDocument && pDocument->HasTable(rRange.aStart.Tab()))
675 	{
676 		ScAddress aStartAddress( rRange.aStart );
677 		ScAddress aEndAddress( rRange.aEnd );
678 		String sStartAddress;
679 		String sEndAddress;
680 		aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
681 		aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
682 		OUString sOUStartAddress( sStartAddress );
683         sOUStartAddress += OUString(':');
684 		sOUStartAddress += OUString( sEndAddress );
685 		AssignString( rString, sOUStartAddress, bAppendStr, cSeperator );
686 	}
687 }
688 
GetStringFromRangeList(OUString & rString,const ScRangeList * pRangeList,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_uInt16 nFormatFlags)689 void ScRangeStringConverter::GetStringFromRangeList(
690 		OUString& rString,
691 		const ScRangeList* pRangeList,
692 		const ScDocument* pDocument,
693         FormulaGrammar::AddressConvention eConv,
694         sal_Unicode cSeperator,
695 		sal_uInt16 nFormatFlags )
696 {
697 	OUString sRangeListStr;
698 	if( pRangeList )
699 	{
700 		sal_Int32 nCount = pRangeList->Count();
701 		for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
702 		{
703 			const ScRange* pRange = pRangeList->GetObject( nIndex );
704 			if( pRange )
705 				GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
706 		}
707 	}
708 	rString = sRangeListStr;
709 }
710 
711 
712 //___________________________________________________________________
713 
GetStringFromArea(OUString & rString,const ScArea & rArea,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Bool bAppendStr,sal_uInt16 nFormatFlags)714 void ScRangeStringConverter::GetStringFromArea(
715 		OUString& rString,
716 		const ScArea& rArea,
717 		const ScDocument* pDocument,
718         FormulaGrammar::AddressConvention eConv,
719         sal_Unicode cSeperator,
720 		sal_Bool bAppendStr,
721 		sal_uInt16 nFormatFlags )
722 {
723 	ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
724 	GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
725 }
726 
727 
728 //___________________________________________________________________
729 
GetStringFromAddress(OUString & rString,const table::CellAddress & rAddress,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Bool bAppendStr,sal_uInt16 nFormatFlags)730 void ScRangeStringConverter::GetStringFromAddress(
731 		OUString& rString,
732 		const table::CellAddress& rAddress,
733 		const ScDocument* pDocument,
734         FormulaGrammar::AddressConvention eConv,
735         sal_Unicode cSeperator,
736 		sal_Bool bAppendStr,
737 		sal_uInt16 nFormatFlags )
738 {
739 	ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
740 	GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
741 }
742 
GetStringFromRange(OUString & rString,const table::CellRangeAddress & rRange,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_Bool bAppendStr,sal_uInt16 nFormatFlags)743 void ScRangeStringConverter::GetStringFromRange(
744 		OUString& rString,
745 		const table::CellRangeAddress& rRange,
746 		const ScDocument* pDocument,
747         FormulaGrammar::AddressConvention eConv,
748         sal_Unicode cSeperator,
749 		sal_Bool bAppendStr,
750 		sal_uInt16 nFormatFlags )
751 {
752 	ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
753 		static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
754 	GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
755 }
756 
GetStringFromRangeList(OUString & rString,const uno::Sequence<table::CellRangeAddress> & rRangeSeq,const ScDocument * pDocument,FormulaGrammar::AddressConvention eConv,sal_Unicode cSeperator,sal_uInt16 nFormatFlags)757 void ScRangeStringConverter::GetStringFromRangeList(
758 		OUString& rString,
759 		const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
760 		const ScDocument* pDocument,
761         FormulaGrammar::AddressConvention eConv,
762         sal_Unicode cSeperator,
763 		sal_uInt16 nFormatFlags )
764 {
765 	OUString sRangeListStr;
766 	sal_Int32 nCount = rRangeSeq.getLength();
767 	for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
768 	{
769 		const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ];
770 		GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
771 	}
772 	rString = sRangeListStr;
773 }
774 
lcl_appendCellAddress(rtl::OUStringBuffer & rBuf,ScDocument * pDoc,const ScAddress & rCell,const ScAddress::ExternalInfo & rExtInfo)775 static void lcl_appendCellAddress(
776     rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell,
777     const ScAddress::ExternalInfo& rExtInfo)
778 {
779     if (rExtInfo.mbExternal)
780     {
781         ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
782         const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true);
783         if (!pFilePath)
784             return;
785 
786         sal_Unicode cQuote = '\'';
787         rBuf.append(cQuote);
788         rBuf.append(*pFilePath);
789         rBuf.append(cQuote);
790         rBuf.append(sal_Unicode('#'));
791         rBuf.append(sal_Unicode('$'));
792         ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName);
793         rBuf.append(sal_Unicode('.'));
794 
795         String aAddr;
796         rCell.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
797         rBuf.append(aAddr);
798     }
799     else
800     {
801         String aAddr;
802         rCell.Format(aAddr, SCA_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
803         rBuf.append(aAddr);
804     }
805 }
806 
lcl_appendCellRangeAddress(rtl::OUStringBuffer & rBuf,ScDocument * pDoc,const ScAddress & rCell1,const ScAddress & rCell2,const ScAddress::ExternalInfo & rExtInfo1,const ScAddress::ExternalInfo & rExtInfo2)807 static void lcl_appendCellRangeAddress(
808     rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2,
809     const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
810 {
811     if (rExtInfo1.mbExternal)
812     {
813         DBG_ASSERT(rExtInfo2.mbExternal, "2nd address is not external!?");
814         DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
815 
816         ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
817         const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true);
818         if (!pFilePath)
819             return;
820 
821         sal_Unicode cQuote = '\'';
822         rBuf.append(cQuote);
823         rBuf.append(*pFilePath);
824         rBuf.append(cQuote);
825         rBuf.append(sal_Unicode('#'));
826         rBuf.append(sal_Unicode('$'));
827         ScRangeStringConverter::AppendTableName(rBuf, rExtInfo1.maTabName);
828         rBuf.append(sal_Unicode('.'));
829 
830         String aAddr;
831         rCell1.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
832         rBuf.append(aAddr);
833 
834         rBuf.appendAscii(":");
835 
836         if (rExtInfo1.maTabName != rExtInfo2.maTabName)
837         {
838             rBuf.append(sal_Unicode('$'));
839             ScRangeStringConverter::AppendTableName(rBuf, rExtInfo2.maTabName);
840             rBuf.append(sal_Unicode('.'));
841         }
842 
843         rCell2.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
844         rBuf.append(aAddr);
845     }
846     else
847     {
848         ScRange aRange;
849         aRange.aStart = rCell1;
850         aRange.aEnd   = rCell2;
851         String aAddr;
852         aRange.Format(aAddr, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
853         rBuf.append(aAddr);
854     }
855 }
856 
GetStringFromXMLRangeString(OUString & rString,const OUString & rXMLRange,ScDocument * pDoc)857 void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc )
858 {
859     const sal_Unicode cSep = ' ';
860     const sal_Unicode cQuote = '\'';
861 
862     OUStringBuffer aRetStr;
863     sal_Int32 nOffset = 0;
864     bool bFirst = true;
865 
866     while (nOffset >= 0)
867     {
868         OUString aToken;
869         GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote);
870         if (nOffset < 0)
871             break;
872 
873         sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote);
874         if (nSepPos >= 0)
875         {
876             // Cell range
877             OUString aBeginCell = aToken.copy(0, nSepPos);
878             OUString aEndCell   = aToken.copy(nSepPos+1);
879 
880             if (!aBeginCell.getLength() || !aEndCell.getLength())
881                 // both cell addresses must exist for this to work.
882                 continue;
883 
884             sal_Int32 nEndCellDotPos = aEndCell.indexOf('.');
885             if (nEndCellDotPos <= 0)
886             {
887                 // initialize buffer with table name...
888                 sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote);
889                 OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos);
890 
891                 if (nEndCellDotPos == 0)
892                 {
893                     // workaround for old syntax (probably pre-chart2 age?)
894                     // e.g. Sheet1.A1:.B2
895                     aBuf.append(aEndCell);
896                 }
897                 else if (nEndCellDotPos < 0)
898                 {
899                     // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
900                     aBuf.append(sal_Unicode('.'));
901                     aBuf.append(aEndCell);
902                 }
903                 aEndCell = aBuf.makeStringAndClear();
904             }
905 
906             ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
907             ScAddress aCell1, aCell2;
908             rtl::OUString aBuf;
909             sal_uInt16 nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
910             if ((nRet & SCA_VALID) != SCA_VALID)
911                 // first cell is invalid.
912                 continue;
913 
914             nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
915             if ((nRet & SCA_VALID) != SCA_VALID)
916                 // second cell is invalid.
917                 continue;
918 
919             if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
920                 // external info inconsistency.
921                 continue;
922 
923             // All looks good!
924 
925             if (bFirst)
926                 bFirst = false;
927             else
928                 aRetStr.appendAscii(";");
929 
930             lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
931         }
932         else
933         {
934             // Chart always saves ranges using CONV_OOO convention.
935             ScAddress::ExternalInfo aExtInfo;
936             ScAddress aCell;
937             sal_uInt16 nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
938             if ((nRet & SCA_VALID) != SCA_VALID)
939                 continue;
940 
941             // Looks good!
942 
943             if (bFirst)
944                 bFirst = false;
945             else
946                 aRetStr.appendAscii(";");
947 
948             lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo);
949         }
950     }
951 
952     rString = aRetStr.makeStringAndClear();
953 }
954 
955 //========================================================================
956 
ScArea(SCTAB tab,SCCOL colStart,SCROW rowStart,SCCOL colEnd,SCROW rowEnd)957 ScArea::ScArea( SCTAB tab,
958 				SCCOL colStart, SCROW rowStart,
959 				SCCOL colEnd,   SCROW rowEnd ) :
960 		nTab	 ( tab ),
961 		nColStart( colStart ),	nRowStart( rowStart ),
962 		nColEnd	 ( colEnd ),	nRowEnd  ( rowEnd )
963 {
964 }
965 
966 //------------------------------------------------------------------------
967 
ScArea(const ScArea & r)968 ScArea::ScArea( const ScArea& r ) :
969 		nTab	 ( r.nTab ),
970 		nColStart( r.nColStart ),	nRowStart( r.nRowStart ),
971 		nColEnd  ( r.nColEnd ),		nRowEnd  ( r.nRowEnd )
972 {
973 }
974 
975 //------------------------------------------------------------------------
976 
operator =(const ScArea & r)977 ScArea& ScArea::operator=( const ScArea& r )
978 {
979 	nTab		= r.nTab;
980 	nColStart	= r.nColStart;
981 	nRowStart	= r.nRowStart;
982 	nColEnd		= r.nColEnd;
983 	nRowEnd		= r.nRowEnd;
984 	return *this;
985 }
986 
987 //------------------------------------------------------------------------
988 
operator ==(const ScArea & r) const989 sal_Bool ScArea::operator==( const ScArea& r ) const
990 {
991 	return (   (nTab		== r.nTab)
992 			&& (nColStart	== r.nColStart)
993 			&& (nRowStart	== r.nRowStart)
994 			&& (nColEnd		== r.nColEnd)
995 			&& (nRowEnd		== r.nRowEnd) );
996 }
997 
998 //------------------------------------------------------------------------
999 
ScAreaNameIterator(ScDocument * pDoc)1000 ScAreaNameIterator::ScAreaNameIterator( ScDocument* pDoc )
1001 {
1002 	pRangeName = pDoc->GetRangeName();
1003 	pDBCollection = pDoc->GetDBCollection();
1004 	nPos = 0;
1005 	bFirstPass = sal_True;
1006 }
1007 
Next(String & rName,ScRange & rRange)1008 sal_Bool ScAreaNameIterator::Next( String& rName, ScRange& rRange )
1009 {
1010     for (;;)
1011     {
1012         if ( bFirstPass )									// erst Bereichsnamen
1013         {
1014             if ( pRangeName && nPos < pRangeName->GetCount() )
1015             {
1016                 ScRangeData* pData = (*pRangeName)[nPos++];
1017                 if ( pData && pData->IsValidReference(rRange) )
1018                 {
1019                     rName = pData->GetName();
1020                     return sal_True;							// gefunden
1021                 }
1022             }
1023             else
1024             {
1025                 bFirstPass = sal_False;
1026                 nPos = 0;
1027             }
1028         }
1029         if ( !bFirstPass )									// dann DB-Bereiche
1030         {
1031             if ( pDBCollection && nPos < pDBCollection->GetCount() )
1032             {
1033                 ScDBData* pData = (*pDBCollection)[nPos++];
1034                 if ( pData
1035                      && !pData->IsInternalUnnamed()
1036                      && !pData->IsInternalForAutoFilter() )
1037                 {
1038                     pData->GetArea( rRange );
1039                     rName = pData->GetName();
1040                     return sal_True;							// gefunden
1041                 }
1042             }
1043             else
1044                 return sal_False;								// gibt nichts mehr
1045         }
1046     }
1047 }
1048 
1049 
1050 
1051 
1052