update dev300-m57
[ooovba.git] / sc / source / core / tool / rangeutl.cxx
blobb5bdfda0cb74276c4f3664f5173fc469b036c993
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rangeutl.cxx,v $
10 * $Revision: 1.12.30.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include <tools/debug.hxx>
40 #include "rangeutl.hxx"
41 #include "document.hxx"
42 #include "global.hxx"
43 #include "dbcolect.hxx"
44 #include "rangenam.hxx"
45 #include "scresid.hxx"
46 #include "globstr.hrc"
47 #include "convuno.hxx"
48 #include "externalrefmgr.hxx"
49 #include "compiler.hxx"
51 using ::rtl::OUString;
52 using ::rtl::OUStringBuffer;
53 using ::formula::FormulaGrammar;
54 using namespace ::com::sun::star;
56 //------------------------------------------------------------------------
58 BOOL ScRangeUtil::MakeArea( const String& rAreaStr,
59 ScArea& rArea,
60 ScDocument* pDoc,
61 SCTAB nTab,
62 ScAddress::Details const & rDetails ) const
64 // Eingabe in rAreaStr: "$Tabelle1.$A1:$D17"
66 // BROKEN BROKEN BROKEN
67 // but it is only used in the consolidate dialog. Ignore for now.
69 BOOL nSuccess = FALSE;
70 USHORT nPointPos = rAreaStr.Search('.');
71 USHORT nColonPos = rAreaStr.Search(':');
72 String aStrArea( rAreaStr );
73 ScRefAddress startPos;
74 ScRefAddress endPos;
76 if ( nColonPos == STRING_NOTFOUND )
77 if ( nPointPos != STRING_NOTFOUND )
79 aStrArea += ':';
80 aStrArea += rAreaStr.Copy( nPointPos+1 ); // '.' nicht mitkopieren
83 nSuccess = ConvertDoubleRef( pDoc, aStrArea, nTab, startPos, endPos, rDetails );
85 if ( nSuccess )
86 rArea = ScArea( startPos.Tab(),
87 startPos.Col(), startPos.Row(),
88 endPos.Col(), endPos.Row() );
90 return nSuccess;
93 //------------------------------------------------------------------------
95 void ScRangeUtil::CutPosString( const String& theAreaStr,
96 String& thePosStr ) const
98 String aPosStr;
99 // BROKEN BROKEN BROKEN
100 // but it is only used in the consolidate dialog. Ignore for now.
102 USHORT nColonPos = theAreaStr.Search(':');
104 if ( nColonPos != STRING_NOTFOUND )
105 aPosStr = theAreaStr.Copy( 0, nColonPos ); // ':' nicht mitkopieren
106 else
107 aPosStr = theAreaStr;
109 thePosStr = aPosStr;
112 //------------------------------------------------------------------------
114 BOOL ScRangeUtil::IsAbsTabArea( const String& rAreaStr,
115 ScDocument* pDoc,
116 ScArea*** pppAreas,
117 USHORT* pAreaCount,
118 BOOL /* bAcceptCellRef */,
119 ScAddress::Details const & rDetails ) const
121 DBG_ASSERT( pDoc, "Kein Dokument uebergeben!" );
122 if ( !pDoc )
123 return FALSE;
125 // BROKEN BROKEN BROKEN
126 // but it is only used in the consolidate dialog. Ignore for now.
129 * Erwartet wird ein String der Form
130 * "$Tabelle1.$A$1:$Tabelle3.$D$17"
131 * Wenn bAcceptCellRef == TRUE ist, wird auch ein String der Form
132 * "$Tabelle1.$A$1"
133 * akzeptiert.
135 * als Ergebnis wird ein ScArea-Array angelegt,
136 * welches ueber ppAreas bekannt gegeben wird und auch
137 * wieder geloescht werden muss!
140 BOOL bStrOk = FALSE;
141 String aTempAreaStr(rAreaStr);
142 String aStartPosStr;
143 String aEndPosStr;
145 if ( STRING_NOTFOUND == aTempAreaStr.Search(':') )
147 aTempAreaStr.Append(':');
148 aTempAreaStr.Append(rAreaStr);
151 USHORT nColonPos = aTempAreaStr.Search(':');
153 if ( STRING_NOTFOUND != nColonPos
154 && STRING_NOTFOUND != aTempAreaStr.Search('.') )
156 ScRefAddress aStartPos;
157 ScRefAddress aEndPos;
159 aStartPosStr = aTempAreaStr.Copy( 0, nColonPos );
160 aEndPosStr = aTempAreaStr.Copy( nColonPos+1, STRING_LEN );
162 if ( ConvertSingleRef( pDoc, aStartPosStr, 0, aStartPos, rDetails ) )
164 if ( ConvertSingleRef( pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) )
166 aStartPos.SetRelCol( FALSE );
167 aStartPos.SetRelRow( FALSE );
168 aStartPos.SetRelTab( FALSE );
169 aEndPos.SetRelCol( FALSE );
170 aEndPos.SetRelRow( FALSE );
171 aEndPos.SetRelTab( FALSE );
173 bStrOk = TRUE;
175 if ( pppAreas && pAreaCount ) // Array zurueckgegeben?
177 SCTAB nStartTab = aStartPos.Tab();
178 SCTAB nEndTab = aEndPos.Tab();
179 USHORT nTabCount = static_cast<USHORT>(nEndTab-nStartTab+1);
180 ScArea** theAreas = new ScArea*[nTabCount];
181 SCTAB nTab = 0;
182 USHORT i = 0;
183 ScArea theArea( 0, aStartPos.Col(), aStartPos.Row(),
184 aEndPos.Col(), aEndPos.Row() );
186 nTab = nStartTab;
187 for ( i=0; i<nTabCount; i++ )
189 theAreas[i] = new ScArea( theArea );
190 theAreas[i]->nTab = nTab;
191 nTab++;
193 *pppAreas = theAreas;
194 *pAreaCount = nTabCount;
200 return bStrOk;
203 //------------------------------------------------------------------------
205 BOOL ScRangeUtil::IsAbsArea( const String& rAreaStr,
206 ScDocument* pDoc,
207 SCTAB nTab,
208 String* pCompleteStr,
209 ScRefAddress* pStartPos,
210 ScRefAddress* pEndPos,
211 ScAddress::Details const & rDetails ) const
213 BOOL bIsAbsArea = FALSE;
214 ScRefAddress startPos;
215 ScRefAddress endPos;
217 bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails );
219 if ( bIsAbsArea )
221 startPos.SetRelCol( FALSE );
222 startPos.SetRelRow( FALSE );
223 startPos.SetRelTab( FALSE );
224 endPos .SetRelCol( FALSE );
225 endPos .SetRelRow( FALSE );
226 endPos .SetRelTab( FALSE );
228 if ( pCompleteStr )
230 *pCompleteStr = startPos.GetRefString( pDoc, MAXTAB+1, rDetails );
231 *pCompleteStr += ':';
232 *pCompleteStr += endPos .GetRefString( pDoc, nTab, rDetails );
235 if ( pStartPos && pEndPos )
237 *pStartPos = startPos;
238 *pEndPos = endPos;
242 return bIsAbsArea;
245 //------------------------------------------------------------------------
247 BOOL ScRangeUtil::IsAbsPos( const String& rPosStr,
248 ScDocument* pDoc,
249 SCTAB nTab,
250 String* pCompleteStr,
251 ScRefAddress* pPosTripel,
252 ScAddress::Details const & rDetails ) const
254 BOOL bIsAbsPos = FALSE;
255 ScRefAddress thePos;
257 bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails );
258 thePos.SetRelCol( FALSE );
259 thePos.SetRelRow( FALSE );
260 thePos.SetRelTab( FALSE );
262 if ( bIsAbsPos )
264 if ( pPosTripel )
265 *pPosTripel = thePos;
266 if ( pCompleteStr )
267 *pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails );
270 return bIsAbsPos;
273 //------------------------------------------------------------------------
275 BOOL ScRangeUtil::MakeRangeFromName (
276 const String& rName,
277 ScDocument* pDoc,
278 SCTAB nCurTab,
279 ScRange& rRange,
280 RutlNameScope eScope,
281 ScAddress::Details const & rDetails ) const
283 BOOL bResult=FALSE;
284 ScRangeUtil aRangeUtil;
285 SCTAB nTab = 0;
286 SCCOL nColStart = 0;
287 SCCOL nColEnd = 0;
288 SCROW nRowStart = 0;
289 SCROW nRowEnd = 0;
291 if( eScope==RUTL_NAMES )
293 ScRangeName& rRangeNames = *(pDoc->GetRangeName());
294 USHORT nAt = 0;
296 if ( rRangeNames.SearchName( rName, nAt ) )
298 ScRangeData* pData = rRangeNames[nAt];
299 String aStrArea;
300 ScRefAddress aStartPos;
301 ScRefAddress aEndPos;
303 pData->GetSymbol( aStrArea );
305 if ( IsAbsArea( aStrArea, pDoc, nCurTab,
306 NULL, &aStartPos, &aEndPos, rDetails ) )
308 nTab = aStartPos.Tab();
309 nColStart = aStartPos.Col();
310 nRowStart = aStartPos.Row();
311 nColEnd = aEndPos.Col();
312 nRowEnd = aEndPos.Row();
313 bResult = TRUE;
315 else
317 CutPosString( aStrArea, aStrArea );
319 if ( IsAbsPos( aStrArea, pDoc, nCurTab,
320 NULL, &aStartPos, rDetails ) )
322 nTab = aStartPos.Tab();
323 nColStart = nColEnd = aStartPos.Col();
324 nRowStart = nRowEnd = aStartPos.Row();
325 bResult = TRUE;
330 else if( eScope==RUTL_DBASE )
332 ScDBCollection& rDbNames = *(pDoc->GetDBCollection());
333 USHORT nAt = 0;
335 if ( rDbNames.SearchName( rName, nAt ) )
337 ScDBData* pData = rDbNames[nAt];
339 pData->GetArea( nTab, nColStart, nRowStart,
340 nColEnd, nRowEnd );
341 bResult = TRUE;
344 else
346 DBG_ERROR( "ScRangeUtil::MakeRangeFromName" );
349 if( bResult )
351 rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab );
354 return bResult;
357 //========================================================================
359 void ScRangeStringConverter::AssignString(
360 OUString& rString,
361 const OUString& rNewStr,
362 sal_Bool bAppendStr,
363 sal_Unicode cSeperator)
365 if( bAppendStr )
367 if( rNewStr.getLength() )
369 if( rString.getLength() )
370 rString += rtl::OUString(cSeperator);
371 rString += rNewStr;
374 else
375 rString = rNewStr;
378 sal_Int32 ScRangeStringConverter::IndexOf(
379 const OUString& rString,
380 sal_Unicode cSearchChar,
381 sal_Int32 nOffset,
382 sal_Unicode cQuote )
384 sal_Int32 nLength = rString.getLength();
385 sal_Int32 nIndex = nOffset;
386 sal_Bool bQuoted = sal_False;
387 sal_Bool bExitLoop = sal_False;
389 while( !bExitLoop && (nIndex < nLength) )
391 sal_Unicode cCode = rString[ nIndex ];
392 bExitLoop = (cCode == cSearchChar) && !bQuoted;
393 bQuoted = (bQuoted != (cCode == cQuote));
394 if( !bExitLoop )
395 nIndex++;
397 return (nIndex < nLength) ? nIndex : -1;
400 sal_Int32 ScRangeStringConverter::IndexOfDifferent(
401 const OUString& rString,
402 sal_Unicode cSearchChar,
403 sal_Int32 nOffset )
405 sal_Int32 nLength = rString.getLength();
406 sal_Int32 nIndex = nOffset;
407 sal_Bool bExitLoop = sal_False;
409 while( !bExitLoop && (nIndex < nLength) )
411 bExitLoop = (rString[ nIndex ] != cSearchChar);
412 if( !bExitLoop )
413 nIndex++;
415 return (nIndex < nLength) ? nIndex : -1;
418 void ScRangeStringConverter::GetTokenByOffset(
419 OUString& rToken,
420 const OUString& rString,
421 sal_Int32& nOffset,
422 sal_Unicode cSeperator,
423 sal_Unicode cQuote)
425 sal_Int32 nLength = rString.getLength();
426 if( nOffset >= nLength )
428 rToken = OUString();
429 nOffset = -1;
431 else
433 sal_Int32 nTokenEnd = IndexOf( rString, cSeperator, nOffset, cQuote );
434 if( nTokenEnd < 0 )
435 nTokenEnd = nLength;
436 rToken = rString.copy( nOffset, nTokenEnd - nOffset );
438 sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeperator, nTokenEnd );
439 nOffset = (nNextBegin < 0) ? nLength : nNextBegin;
443 void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode /* cQuote */)
445 // quote character is always "'"
446 String aQuotedTab(rTabName);
447 ScCompiler::CheckTabQuotes(aQuotedTab, ::formula::FormulaGrammar::CONV_OOO);
448 rBuf.append(aQuotedTab);
451 sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote )
453 OUString sToken;
454 sal_Int32 nCount = 0;
455 sal_Int32 nOffset = 0;
456 while( nOffset >= 0 )
458 GetTokenByOffset( sToken, rString, nOffset, cQuote, cSeperator );
459 if( nOffset >= 0 )
460 nCount++;
462 return nCount;
465 //___________________________________________________________________
467 sal_Bool ScRangeStringConverter::GetAddressFromString(
468 ScAddress& rAddress,
469 const OUString& rAddressStr,
470 const ScDocument* pDocument,
471 FormulaGrammar::AddressConvention eConv,
472 sal_Int32& nOffset,
473 sal_Unicode cSeperator,
474 sal_Unicode cQuote )
476 OUString sToken;
477 GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote );
478 if( nOffset >= 0 )
480 if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID)
481 return true;
482 #if CHART_ADDRESS_CONV_WORKAROUND
483 ::formula::FormulaGrammar::AddressConvention eConvUI = pDocument->GetAddressConvention();
484 if (eConv != eConvUI)
485 return ((rAddress.Parse(sToken, const_cast<ScDocument*>(pDocument), eConvUI) & SCA_VALID) == SCA_VALID);
486 #endif
488 return sal_False;
491 sal_Bool ScRangeStringConverter::GetRangeFromString(
492 ScRange& rRange,
493 const OUString& rRangeStr,
494 const ScDocument* pDocument,
495 FormulaGrammar::AddressConvention eConv,
496 sal_Int32& nOffset,
497 sal_Unicode cSeperator,
498 sal_Unicode cQuote )
500 OUString sToken;
501 sal_Bool bResult(sal_False);
502 GetTokenByOffset( sToken, rRangeStr, nOffset, cSeperator, cQuote );
503 if( nOffset >= 0 )
505 sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote );
506 String aUIString(sToken);
508 if( nIndex < 0 )
510 if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
511 aUIString.Erase( 0, 1 );
512 bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
513 #if CHART_ADDRESS_CONV_WORKAROUND
514 if (!bResult && eConv != eConv)
515 bResult = ((rRange.aStart.Parse(
516 aUIString, const_cast<ScDocument*>(pDocument), eConv) & SCA_VALID) == SCA_VALID);
517 #endif
518 rRange.aEnd = rRange.aStart;
520 else
522 if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
524 aUIString.Erase( 0, 1 );
525 --nIndex;
528 if ( nIndex < aUIString.Len() - 1 &&
529 aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
530 aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
532 bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
534 // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
535 // This isn't parsed by ScRange, so try to parse the two Addresses then.
536 if (!bResult)
538 bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
539 eConv) & SCA_VALID) == SCA_VALID) &&
540 ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
541 eConv) & SCA_VALID) == SCA_VALID);
542 #if CHART_ADDRESS_CONV_WORKAROUND
543 if (!bResult && eConv != eConv)
545 bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
546 eConv) & SCA_VALID) == SCA_VALID) &&
547 ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
548 eConv) & SCA_VALID) == SCA_VALID);
550 #endif
554 return bResult;
557 sal_Bool ScRangeStringConverter::GetRangeListFromString(
558 ScRangeList& rRangeList,
559 const OUString& rRangeListStr,
560 const ScDocument* pDocument,
561 FormulaGrammar::AddressConvention eConv,
562 sal_Unicode cSeperator,
563 sal_Unicode cQuote )
565 sal_Bool bRet = sal_True;
566 DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
567 sal_Int32 nOffset = 0;
568 while( nOffset >= 0 )
570 ScRange* pRange = new ScRange;
571 if( GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
572 rRangeList.Insert( pRange, LIST_APPEND );
573 else if (nOffset > -1)
574 bRet = sal_False;
576 return bRet;
580 //___________________________________________________________________
582 sal_Bool ScRangeStringConverter::GetAreaFromString(
583 ScArea& rArea,
584 const OUString& rRangeStr,
585 const ScDocument* pDocument,
586 FormulaGrammar::AddressConvention eConv,
587 sal_Int32& nOffset,
588 sal_Unicode cSeperator,
589 sal_Unicode cQuote )
591 ScRange aScRange;
592 sal_Bool bResult(sal_False);
593 if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
595 rArea.nTab = aScRange.aStart.Tab();
596 rArea.nColStart = aScRange.aStart.Col();
597 rArea.nRowStart = aScRange.aStart.Row();
598 rArea.nColEnd = aScRange.aEnd.Col();
599 rArea.nRowEnd = aScRange.aEnd.Row();
600 bResult = sal_True;
602 return bResult;
606 //___________________________________________________________________
608 sal_Bool ScRangeStringConverter::GetAddressFromString(
609 table::CellAddress& rAddress,
610 const OUString& rAddressStr,
611 const ScDocument* pDocument,
612 FormulaGrammar::AddressConvention eConv,
613 sal_Int32& nOffset,
614 sal_Unicode cSeperator,
615 sal_Unicode cQuote )
617 ScAddress aScAddress;
618 sal_Bool bResult(sal_False);
619 if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
621 ScUnoConversion::FillApiAddress( rAddress, aScAddress );
622 bResult = sal_True;
624 return bResult;
627 sal_Bool ScRangeStringConverter::GetRangeFromString(
628 table::CellRangeAddress& rRange,
629 const OUString& rRangeStr,
630 const ScDocument* pDocument,
631 FormulaGrammar::AddressConvention eConv,
632 sal_Int32& nOffset,
633 sal_Unicode cSeperator,
634 sal_Unicode cQuote )
636 ScRange aScRange;
637 sal_Bool bResult(sal_False);
638 if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
640 ScUnoConversion::FillApiRange( rRange, aScRange );
641 bResult = sal_True;
643 return bResult;
646 sal_Bool ScRangeStringConverter::GetRangeListFromString(
647 uno::Sequence< table::CellRangeAddress >& rRangeSeq,
648 const OUString& rRangeListStr,
649 const ScDocument* pDocument,
650 FormulaGrammar::AddressConvention eConv,
651 sal_Unicode cSeperator,
652 sal_Unicode cQuote )
654 sal_Bool bRet = sal_True;
655 DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" );
656 table::CellRangeAddress aRange;
657 sal_Int32 nOffset = 0;
658 while( nOffset >= 0 )
660 if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
662 rRangeSeq.realloc( rRangeSeq.getLength() + 1 );
663 rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange;
665 else
666 bRet = sal_False;
668 return bRet;
672 //___________________________________________________________________
674 void ScRangeStringConverter::GetStringFromAddress(
675 OUString& rString,
676 const ScAddress& rAddress,
677 const ScDocument* pDocument,
678 FormulaGrammar::AddressConvention eConv,
679 sal_Unicode cSeperator,
680 sal_Bool bAppendStr,
681 sal_uInt16 nFormatFlags )
683 if (pDocument && pDocument->HasTable(rAddress.Tab()))
685 String sAddress;
686 rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
687 AssignString( rString, sAddress, bAppendStr, cSeperator );
691 void ScRangeStringConverter::GetStringFromRange(
692 OUString& rString,
693 const ScRange& rRange,
694 const ScDocument* pDocument,
695 FormulaGrammar::AddressConvention eConv,
696 sal_Unicode cSeperator,
697 sal_Bool bAppendStr,
698 sal_uInt16 nFormatFlags )
700 if (pDocument && pDocument->HasTable(rRange.aStart.Tab()))
702 ScAddress aStartAddress( rRange.aStart );
703 ScAddress aEndAddress( rRange.aEnd );
704 String sStartAddress;
705 String sEndAddress;
706 aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
707 aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
708 OUString sOUStartAddress( sStartAddress );
709 sOUStartAddress += OUString(':');
710 sOUStartAddress += OUString( sEndAddress );
711 AssignString( rString, sOUStartAddress, bAppendStr, cSeperator );
715 void ScRangeStringConverter::GetStringFromRangeList(
716 OUString& rString,
717 const ScRangeList* pRangeList,
718 const ScDocument* pDocument,
719 FormulaGrammar::AddressConvention eConv,
720 sal_Unicode cSeperator,
721 sal_uInt16 nFormatFlags )
723 OUString sRangeListStr;
724 if( pRangeList )
726 sal_Int32 nCount = pRangeList->Count();
727 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
729 const ScRange* pRange = pRangeList->GetObject( nIndex );
730 if( pRange )
731 GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
734 rString = sRangeListStr;
738 //___________________________________________________________________
740 void ScRangeStringConverter::GetStringFromArea(
741 OUString& rString,
742 const ScArea& rArea,
743 const ScDocument* pDocument,
744 FormulaGrammar::AddressConvention eConv,
745 sal_Unicode cSeperator,
746 sal_Bool bAppendStr,
747 sal_uInt16 nFormatFlags )
749 ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
750 GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
754 //___________________________________________________________________
756 void ScRangeStringConverter::GetStringFromAddress(
757 OUString& rString,
758 const table::CellAddress& rAddress,
759 const ScDocument* pDocument,
760 FormulaGrammar::AddressConvention eConv,
761 sal_Unicode cSeperator,
762 sal_Bool bAppendStr,
763 sal_uInt16 nFormatFlags )
765 ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
766 GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
769 void ScRangeStringConverter::GetStringFromRange(
770 OUString& rString,
771 const table::CellRangeAddress& rRange,
772 const ScDocument* pDocument,
773 FormulaGrammar::AddressConvention eConv,
774 sal_Unicode cSeperator,
775 sal_Bool bAppendStr,
776 sal_uInt16 nFormatFlags )
778 ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
779 static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
780 GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
783 void ScRangeStringConverter::GetStringFromRangeList(
784 OUString& rString,
785 const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
786 const ScDocument* pDocument,
787 FormulaGrammar::AddressConvention eConv,
788 sal_Unicode cSeperator,
789 sal_uInt16 nFormatFlags )
791 OUString sRangeListStr;
792 sal_Int32 nCount = rRangeSeq.getLength();
793 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
795 const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ];
796 GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
798 rString = sRangeListStr;
801 static void lcl_appendCellAddress(
802 rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell,
803 const ScAddress::ExternalInfo& rExtInfo)
805 if (rExtInfo.mbExternal)
807 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
808 const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId);
809 if (!pFilePath)
810 return;
812 sal_Unicode cQuote = '\'';
813 rBuf.append(cQuote);
814 rBuf.append(*pFilePath);
815 rBuf.append(cQuote);
816 rBuf.append(sal_Unicode('#'));
817 rBuf.append(sal_Unicode('$'));
818 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName);
819 rBuf.append(sal_Unicode('.'));
821 String aAddr;
822 rCell.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
823 rBuf.append(aAddr);
825 else
827 String aAddr;
828 rCell.Format(aAddr, SCA_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
829 rBuf.append(aAddr);
833 static void lcl_appendCellRangeAddress(
834 rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2,
835 const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
837 if (rExtInfo1.mbExternal)
839 DBG_ASSERT(rExtInfo2.mbExternal, "2nd address is not external!?");
840 DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
842 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
843 const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId);
844 if (!pFilePath)
845 return;
847 sal_Unicode cQuote = '\'';
848 rBuf.append(cQuote);
849 rBuf.append(*pFilePath);
850 rBuf.append(cQuote);
851 rBuf.append(sal_Unicode('#'));
852 rBuf.append(sal_Unicode('$'));
853 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo1.maTabName);
854 rBuf.append(sal_Unicode('.'));
856 String aAddr;
857 rCell1.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
858 rBuf.append(aAddr);
860 rBuf.appendAscii(":");
862 if (rExtInfo1.maTabName != rExtInfo2.maTabName)
864 rBuf.append(sal_Unicode('$'));
865 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo2.maTabName);
866 rBuf.append(sal_Unicode('.'));
869 rCell2.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
870 rBuf.append(aAddr);
872 else
874 ScRange aRange;
875 aRange.aStart = rCell1;
876 aRange.aEnd = rCell2;
877 String aAddr;
878 aRange.Format(aAddr, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
879 rBuf.append(aAddr);
883 void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc )
885 FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
886 const OUString aRangeSep = GetScCompilerNativeSymbol(ocSep);
887 const sal_Unicode cSep = ' ';
888 const sal_Unicode cQuote = '\'';
890 OUStringBuffer aRetStr;
891 sal_Int32 nOffset = 0;
892 bool bFirst = true;
894 while (nOffset >= 0)
896 OUString aToken;
897 GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote);
898 if (nOffset < 0)
899 break;
901 sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote);
902 if (nSepPos >= 0)
904 // Cell range
905 OUString aBeginCell = aToken.copy(0, nSepPos);
906 OUString aEndCell = aToken.copy(nSepPos+1);
908 if (!aBeginCell.getLength() || !aEndCell.getLength())
909 // both cell addresses must exist for this to work.
910 continue;
912 sal_Int32 nEndCellDotPos = aEndCell.indexOf('.');
913 if (nEndCellDotPos <= 0)
915 // initialize buffer with table name...
916 sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote);
917 OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos);
919 if (nEndCellDotPos == 0)
921 // workaround for old syntax (probably pre-chart2 age?)
922 // e.g. Sheet1.A1:.B2
923 aBuf.append(aEndCell);
925 else if (nEndCellDotPos < 0)
927 // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
928 aBuf.append(sal_Unicode('.'));
929 aBuf.append(aEndCell);
931 aEndCell = aBuf.makeStringAndClear();
934 ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
935 ScAddress aCell1, aCell2;
936 rtl::OUString aBuf;
937 USHORT nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
938 if ((nRet & SCA_VALID) != SCA_VALID)
940 // first cell is invalid.
941 #if CHART_ADDRESS_CONV_WORKAROUND
942 if (eConv == FormulaGrammar::CONV_OOO)
943 continue;
945 nRet = aCell1.Parse(aBeginCell, pDoc, eConv, &aExtInfo1);
946 if ((nRet & SCA_VALID) != SCA_VALID)
947 // first cell is really invalid.
948 continue;
949 #else
950 continue;
951 #endif
954 nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
955 if ((nRet & SCA_VALID) != SCA_VALID)
957 // second cell is invalid.
958 #if CHART_ADDRESS_CONV_WORKAROUND
959 if (eConv == FormulaGrammar::CONV_OOO)
960 continue;
962 nRet = aCell2.Parse(aEndCell, pDoc, eConv, &aExtInfo2);
963 if ((nRet & SCA_VALID) != SCA_VALID)
964 // second cell is really invalid.
965 continue;
966 #else
967 continue;
968 #endif
971 if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
972 // external info inconsistency.
973 continue;
975 // All looks good!
977 if (bFirst)
978 bFirst = false;
979 else
980 aRetStr.append(aRangeSep);
982 lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
984 else
986 // Chart always saves ranges using CONV_OOO convention.
987 ScAddress::ExternalInfo aExtInfo;
988 ScAddress aCell;
989 USHORT nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
990 if ((nRet & SCA_VALID) != SCA_VALID)
992 #if CHART_ADDRESS_CONV_WORKAROUND
993 nRet = aCell.Parse(aToken, pDoc, eConv, &aExtInfo);
994 if ((nRet & SCA_VALID) != SCA_VALID)
995 continue;
996 #else
997 continue;
998 #endif
1001 // Looks good!
1003 if (bFirst)
1004 bFirst = false;
1005 else
1006 aRetStr.append(aRangeSep);
1008 lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo);
1012 rString = aRetStr.makeStringAndClear();
1015 //========================================================================
1017 ScArea::ScArea( SCTAB tab,
1018 SCCOL colStart, SCROW rowStart,
1019 SCCOL colEnd, SCROW rowEnd ) :
1020 nTab ( tab ),
1021 nColStart( colStart ), nRowStart( rowStart ),
1022 nColEnd ( colEnd ), nRowEnd ( rowEnd )
1026 //------------------------------------------------------------------------
1028 ScArea::ScArea( const ScArea& r ) :
1029 nTab ( r.nTab ),
1030 nColStart( r.nColStart ), nRowStart( r.nRowStart ),
1031 nColEnd ( r.nColEnd ), nRowEnd ( r.nRowEnd )
1035 //------------------------------------------------------------------------
1037 ScArea& ScArea::operator=( const ScArea& r )
1039 nTab = r.nTab;
1040 nColStart = r.nColStart;
1041 nRowStart = r.nRowStart;
1042 nColEnd = r.nColEnd;
1043 nRowEnd = r.nRowEnd;
1044 return *this;
1047 //------------------------------------------------------------------------
1049 BOOL ScArea::operator==( const ScArea& r ) const
1051 return ( (nTab == r.nTab)
1052 && (nColStart == r.nColStart)
1053 && (nRowStart == r.nRowStart)
1054 && (nColEnd == r.nColEnd)
1055 && (nRowEnd == r.nRowEnd) );
1058 //------------------------------------------------------------------------
1060 ScAreaNameIterator::ScAreaNameIterator( ScDocument* pDoc ) :
1061 aStrNoName( ScGlobal::GetRscString(STR_DB_NONAME) )
1063 pRangeName = pDoc->GetRangeName();
1064 pDBCollection = pDoc->GetDBCollection();
1065 nPos = 0;
1066 bFirstPass = TRUE;
1069 BOOL ScAreaNameIterator::Next( String& rName, ScRange& rRange )
1071 for (;;)
1073 if ( bFirstPass ) // erst Bereichsnamen
1075 if ( pRangeName && nPos < pRangeName->GetCount() )
1077 ScRangeData* pData = (*pRangeName)[nPos++];
1078 if ( pData && pData->IsValidReference(rRange) )
1080 rName = pData->GetName();
1081 return TRUE; // gefunden
1084 else
1086 bFirstPass = FALSE;
1087 nPos = 0;
1090 if ( !bFirstPass ) // dann DB-Bereiche
1092 if ( pDBCollection && nPos < pDBCollection->GetCount() )
1094 ScDBData* pData = (*pDBCollection)[nPos++];
1095 if (pData && pData->GetName() != aStrNoName)
1097 pData->GetArea( rRange );
1098 rName = pData->GetName();
1099 return TRUE; // gefunden
1102 else
1103 return FALSE; // gibt nichts mehr