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