xref: /aoo42x/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