1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: address.cxx,v $
10 * $Revision: 1.11.30.3 $
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"
34 #include "address.hxx"
36 #include "compiler.hxx"
37 #include "document.hxx"
38 #include "externalrefmgr.hxx"
40 #include "globstr.hrc"
41 #include <sal/alloca.h>
43 #include <com/sun/star/frame/XModel.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/sheet/ExternalLinkInfo.hpp>
46 #include <com/sun/star/sheet/ExternalLinkType.hpp>
47 #include <sfx2/objsh.hxx>
48 #include <tools/urlobj.hxx>
49 using namespace ::com::sun::star
;
51 ////////////////////////////////////////////////////////////////////////////
52 const ScAddress::Details
ScAddress::detailsOOOa1( formula::FormulaGrammar::CONV_OOO
, 0, 0 );
54 ScAddress::Details::Details ( const ScDocument
* pDoc
,
55 const ScAddress
& rAddr
) :
56 eConv( pDoc
->GetAddressConvention() ),
62 //UNUSED2009-05 void ScAddress::Details::SetPos ( const ScDocument* pDoc,
63 //UNUSED2009-05 const ScAddress & rAddr )
65 //UNUSED2009-05 nRow = rAddr.Row();
66 //UNUSED2009-05 nCol = rAddr.Col();
67 //UNUSED2009-05 eConv = pDoc->GetAddressConvention();
70 ////////////////////////////////////////////////////////////////////////////
75 * Parse from the opening single quote to the closing single quote. Inside
76 * the quotes, a single quote character is encoded by double single-quote
79 * @param p pointer to the first character to begin parsing.
80 * @param rName (reference) parsed name within the quotes. If the name is
81 * empty, either the parsing failed or it's an empty quote.
83 * @return pointer to the character immediately after the closing single
86 static const sal_Unicode
* lcl_ParseQuotedName( const sal_Unicode
* p
, String
& rName
)
92 const sal_Unicode
* pStart
= p
;
93 sal_Unicode cPrev
= 0;
100 // double single-quote equals one single quote.
106 else if (cPrev
== '\'')
107 // We are past the closing quote. We're done!
118 sal_Unicode_strtol ( const sal_Unicode
* p
,
119 const sal_Unicode
** pEnd
)
121 long int accum
= 0, prev
= 0;
132 while (CharClass::isAsciiDigit( *p
))
134 accum
= accum
* 10 + *p
- '0';
145 return is_neg
? -accum
: accum
;
148 const sal_Unicode
* lcl_eatWhiteSpace( const sal_Unicode
* p
)
158 /** Determines the number of sheets an external reference spans and sets
159 rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding
160 bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in
161 cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName
162 is set to rEndTabName.
163 @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not
164 result in the identical file ID. Else <TRUE/>.
166 static bool lcl_ScRange_External_TabSpan(
169 ScAddress::ExternalInfo
* pExtInfo
,
170 const String
& rExternDocName
,
171 const String
& rStartTabName
,
172 const String
& rEndTabName
,
175 if (!rExternDocName
.Len())
176 return !pExtInfo
|| !pExtInfo
->mbExternal
;
178 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
179 if (pRefMgr
->isOwnDocument( rExternDocName
))
180 return !pExtInfo
|| !pExtInfo
->mbExternal
;
182 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId( rExternDocName
);
186 if (pExtInfo
->mbExternal
)
188 if (pExtInfo
->mnFileId
!= nFileId
)
193 pExtInfo
->mbExternal
= true;
194 pExtInfo
->maTabName
= rStartTabName
;
195 pExtInfo
->mnFileId
= nFileId
;
199 if (!rEndTabName
.Len() || rStartTabName
== rEndTabName
)
201 rRange
.aEnd
.SetTab( rRange
.aStart
.Tab());
205 SCsTAB nSpan
= pRefMgr
->getCachedTabSpan( nFileId
, rStartTabName
, rEndTabName
);
207 rFlags
&= ~(SCA_VALID_TAB
| SCA_VALID_TAB2
);
209 rFlags
&= ~SCA_VALID_TAB2
;
211 rRange
.aEnd
.SetTab( rRange
.aStart
.Tab() + nSpan
- 1);
214 rRange
.aEnd
.SetTab( rRange
.aStart
.Tab() - nSpan
- 1);
216 pExtInfo
->maTabName
= rEndTabName
;
221 /** Returns NULL if the string should be a sheet name, but is invalid.
222 Returns a pointer to the first character after the sheet name, if there was
223 any, else pointer to start.
224 @param pMsoxlQuoteStop
225 Starting _within_ a quoted name, but still may be 3D; quoted name stops
228 static const sal_Unicode
*
229 lcl_XL_ParseSheetRef( const sal_Unicode
* start
,
230 String
& rExternTabName
,
232 const sal_Unicode
* pMsoxlQuoteStop
)
235 const sal_Unicode
*p
= start
;
237 // XL only seems to use single quotes for sheet names.
240 const sal_Unicode
* pCurrentStart
= p
;
241 while (p
< pMsoxlQuoteStop
)
245 // We pre-analyzed the quoting, no checks needed here.
248 aTabName
.Append( pCurrentStart
,
249 sal::static_int_cast
<xub_StrLen
>( p
- pCurrentStart
));
260 if (pCurrentStart
< p
)
261 aTabName
.Append( pCurrentStart
, sal::static_int_cast
<xub_StrLen
>( p
- pCurrentStart
));
264 if (p
== pMsoxlQuoteStop
)
265 ++p
; // position on ! of ...'!...
266 if( *p
!= '!' && ( !allow_3d
|| *p
!= ':' ) )
267 return (!allow_3d
&& *p
== ':') ? p
: start
;
271 p
= lcl_ParseQuotedName(p
, aTabName
);
277 bool only_digits
= TRUE
;
284 * Some names starting with digits are actually valid, but
285 * unparse quoted. Things are quite tricky: most sheet names
286 * starting with a digit are ok, but not those starting with
287 * "[0-9]*\." or "[0-9]+[eE]".
296 const sal_Unicode uc
= *p
;
297 if( CharClass::isAsciiAlpha( uc
) || uc
== '_' )
299 if( only_digits
&& p
!= start
&&
300 (uc
== 'e' || uc
== 'E' ) )
308 else if( CharClass::isAsciiDigit( uc
))
314 if( only_digits
) // Valid, except after only digits.
323 // non ASCII character is allowed.
330 if( *p
!= '!' && ( !allow_3d
|| *p
!= ':' ) )
331 return (!allow_3d
&& *p
== ':') ? p
: start
;
333 aTabName
.Append( start
, sal::static_int_cast
<xub_StrLen
>( p
- start
) );
336 rExternTabName
= aTabName
;
341 const sal_Unicode
* ScRange::Parse_XL_Header(
342 const sal_Unicode
* p
,
343 const ScDocument
* pDoc
,
344 String
& rExternDocName
,
345 String
& rStartTabName
,
348 bool bOnlyAcceptSingle
,
349 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
351 const sal_Unicode
* startTabs
, *start
= p
;
352 USHORT nSaveFlags
= nFlags
;
354 // Is this an external reference ?
355 rStartTabName
.Erase();
357 rExternDocName
.Erase();
358 const sal_Unicode
* pMsoxlQuoteStop
= NULL
;
362 // Only single quotes are correct, and a double single quote escapes a
363 // single quote text inside the quoted text.
366 p
= lcl_ParseQuotedName(p
, rExternDocName
);
367 if (!*p
|| *p
!= ']' || !rExternDocName
.Len())
372 // non-quoted file name.
373 p
= ScGlobal::UnicodeStrChr( start
+1, ']' );
376 rExternDocName
.Append( start
+1, sal::static_int_cast
<xub_StrLen
>( p
-(start
+1) ) );
380 // 1-based, sequence starts with an empty element.
381 if (pExternalLinks
&& pExternalLinks
->getLength() > 1)
383 // A numeric "document name" is an index into the sequence.
384 if (CharClass::isAsciiNumeric( rExternDocName
))
386 sal_Int32 i
= rExternDocName
.ToInt32();
387 if (i
<= 0 || i
>= pExternalLinks
->getLength())
389 const sheet::ExternalLinkInfo
& rInfo
= (*pExternalLinks
)[i
];
392 case sheet::ExternalLinkType::DOCUMENT
:
395 if (!(rInfo
.Data
>>= aStr
))
397 DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i
);
400 rExternDocName
= aStr
;
404 DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d",
410 rExternDocName
= ScGlobal::GetAbsDocName(rExternDocName
, pDoc
->GetDocumentShell());
414 // Sickness in Excel's ODF msoxl namespace:
415 // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7 or
416 // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11
417 // But, 'Sheet1'!B3 would also be a valid!
418 // Excel does not allow [ and ] characters in sheet names though.
419 p
= lcl_ParseQuotedName(p
, rExternDocName
);
420 if (!*p
|| *p
!= '!')
422 if (rExternDocName
.Len())
424 xub_StrLen nOpen
= rExternDocName
.Search( '[');
425 if (nOpen
== STRING_NOTFOUND
)
426 rExternDocName
.Erase();
429 xub_StrLen nClose
= rExternDocName
.Search( ']', nOpen
+1);
430 if (nClose
== STRING_NOTFOUND
)
431 rExternDocName
.Erase();
434 rExternDocName
.Erase( nClose
);
435 rExternDocName
.Erase( nOpen
, 1);
436 pMsoxlQuoteStop
= p
- 1; // the ' quote char
437 // There may be embedded escaped quotes, just matching the
438 // doc name's length may not work.
439 for (p
= start
; *p
!= '['; ++p
)
441 for ( ; *p
!= ']'; ++p
)
447 if (!rExternDocName
.Len())
452 p
= lcl_XL_ParseSheetRef( p
, rStartTabName
, !bOnlyAcceptSingle
, pMsoxlQuoteStop
);
454 return start
; // invalid tab
455 if (bOnlyAcceptSingle
&& *p
== ':')
459 nFlags
|= SCA_VALID_TAB
| SCA_TAB_3D
| SCA_TAB_ABSOLUTE
;
460 if( *p
== ':' ) // 3d ref
462 p
= lcl_XL_ParseSheetRef( p
+1, rEndTabName
, false, pMsoxlQuoteStop
);
466 return start
; // invalid tab
468 nFlags
|= SCA_VALID_TAB2
| SCA_TAB2_3D
| SCA_TAB2_ABSOLUTE
;
472 // If only one sheet is given, the full reference is still valid,
473 // only the second 3D flag is not set.
474 nFlags
|= SCA_VALID_TAB2
| SCA_TAB2_ABSOLUTE
;
475 aEnd
.SetTab( aStart
.Tab() );
481 return start
; // syntax error
484 p
= lcl_eatWhiteSpace( p
);
488 nFlags
|= SCA_VALID_TAB
| SCA_VALID_TAB2
;
489 // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. );
492 if (rExternDocName
.Len())
494 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
495 pRefMgr
->convertToAbsName( rExternDocName
);
499 // Internal reference.
500 if (!rStartTabName
.Len())
507 if (!pDoc
->GetTable(rStartTabName
, nTab
))
509 // invalid table name.
510 nFlags
&= ~SCA_VALID_TAB
;
517 if (rEndTabName
.Len())
519 if (!pDoc
->GetTable(rEndTabName
, nTab
))
521 // invalid table name.
522 nFlags
&= ~SCA_VALID_TAB2
;
533 static const sal_Unicode
*
534 lcl_r1c1_get_col( const sal_Unicode
* p
,
535 const ScAddress::Details
& rDetails
,
536 ScAddress
* pAddr
, USHORT
* nFlags
)
538 const sal_Unicode
*pEnd
;
546 if( (isRelative
= (*p
== '[') ) != false )
548 n
= sal_Unicode_strtol( p
, &pEnd
);
552 if( p
== pEnd
) // C is a relative ref with offset 0
558 else if( isRelative
)
567 *nFlags
|= SCA_COL_ABSOLUTE
;
571 if( n
< 0 || n
>= MAXCOLCOUNT
)
573 pAddr
->SetCol( static_cast<SCCOL
>( n
) );
574 *nFlags
|= SCA_VALID_COL
;
578 static inline const sal_Unicode
*
579 lcl_r1c1_get_row( const sal_Unicode
* p
,
580 const ScAddress::Details
& rDetails
,
581 ScAddress
* pAddr
, USHORT
* nFlags
)
583 const sal_Unicode
*pEnd
;
591 if( (isRelative
= (*p
== '[') ) != false )
593 n
= sal_Unicode_strtol( p
, &pEnd
);
597 if( p
== pEnd
) // R is a relative ref with offset 0
603 else if( isRelative
)
612 *nFlags
|= SCA_ROW_ABSOLUTE
;
616 if( n
< 0 || n
>= MAXROWCOUNT
)
618 pAddr
->SetRow( static_cast<SCROW
>( n
) );
619 *nFlags
|= SCA_VALID_ROW
;
625 lcl_ScRange_Parse_XL_R1C1( ScRange
& r
,
626 const sal_Unicode
* p
,
628 const ScAddress::Details
& rDetails
,
629 bool bOnlyAcceptSingle
,
630 ScAddress::ExternalInfo
* pExtInfo
)
632 const sal_Unicode
* pTmp
= NULL
;
633 String aExternDocName
, aStartTabName
, aEndTabName
;
634 USHORT nFlags
= SCA_VALID
| SCA_VALID_TAB
, nFlags2
= SCA_VALID_TAB2
;
638 ByteString
aStr(p
, RTL_TEXTENCODING_UTF8
);
639 aStr
.Append(static_cast< char >(0));
640 std::cerr
<< "parse::XL::R1C1 \'" << aStr
.GetBuffer() << '\'' << std::endl
;
643 p
= r
.Parse_XL_Header( p
, pDoc
, aExternDocName
, aStartTabName
,
644 aEndTabName
, nFlags
, bOnlyAcceptSingle
, NULL
);
646 if (aExternDocName
.Len() > 0)
647 lcl_ScRange_External_TabSpan( r
, nFlags
, pExtInfo
, aExternDocName
,
648 aStartTabName
, aEndTabName
, pDoc
);
653 if( *p
== 'R' || *p
== 'r' )
655 if( NULL
== (p
= lcl_r1c1_get_row( p
, rDetails
, &r
.aStart
, &nFlags
)) )
658 if( *p
!= 'C' && *p
!= 'c' ) // full row R#
660 if( p
[0] != ':' || (p
[1] != 'R' && p
[1] != 'r' ) ||
661 NULL
== (pTmp
= lcl_r1c1_get_row( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)))
663 // Only the initial row number is given, or the second row
664 // number is invalid. Fallback to just the initial R
665 nFlags
|= (nFlags
<< 4);
666 r
.aEnd
.SetRow( r
.aStart
.Row() );
670 // Full row range successfully parsed.
671 nFlags
|= (nFlags2
<< 4);
677 // any trailing invalid character must invalidate the whole address.
678 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
679 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
684 SCA_VALID_COL
| SCA_VALID_COL2
|
685 SCA_COL_ABSOLUTE
| SCA_COL2_ABSOLUTE
;
686 r
.aStart
.SetCol( 0 );
687 r
.aEnd
.SetCol( MAXCOL
);
689 return bOnlyAcceptSingle
? 0 : nFlags
;
691 else if( NULL
== (p
= lcl_r1c1_get_col( p
, rDetails
, &r
.aStart
, &nFlags
)))
695 (p
[1] != 'R' && p
[1] != 'r') ||
696 NULL
== (pTmp
= lcl_r1c1_get_row( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)) ||
697 (*pTmp
!= 'C' && *pTmp
!= 'c') ||
698 NULL
== (pTmp
= lcl_r1c1_get_col( pTmp
, rDetails
, &r
.aEnd
, &nFlags2
)))
700 // single cell reference
704 // any trailing invalid character must invalidate the whole address.
705 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
709 return bOnlyAcceptSingle
? nFlags
: 0;
717 // any trailing invalid character must invalidate the whole range.
718 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
719 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
723 nFlags
|= (nFlags2
<< 4);
724 return bOnlyAcceptSingle
? 0 : nFlags
;
726 else if( *p
== 'C' || *p
== 'c' ) // full col C#
728 if( NULL
== (p
= lcl_r1c1_get_col( p
, rDetails
, &r
.aStart
, &nFlags
)))
731 if( p
[0] != ':' || (p
[1] != 'C' && p
[1] != 'c') ||
732 NULL
== (pTmp
= lcl_r1c1_get_col( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)))
733 { // Fallback to just the initial C
734 nFlags
|= (nFlags
<< 4);
735 r
.aEnd
.SetCol( r
.aStart
.Col() );
739 nFlags
|= (nFlags2
<< 4);
745 // any trailing invalid character must invalidate the whole address.
746 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
747 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
752 SCA_VALID_ROW
| SCA_VALID_ROW2
|
753 SCA_ROW_ABSOLUTE
| SCA_ROW2_ABSOLUTE
;
754 r
.aStart
.SetRow( 0 );
755 r
.aEnd
.SetRow( MAXROW
);
757 return bOnlyAcceptSingle
? 0 : nFlags
;
764 static inline const sal_Unicode
*
765 lcl_a1_get_col( const sal_Unicode
* p
, ScAddress
* pAddr
, USHORT
* nFlags
)
770 *nFlags
|= SCA_COL_ABSOLUTE
, p
++;
772 if( !CharClass::isAsciiAlpha( *p
) )
775 nCol
= sal::static_int_cast
<SCCOL
>( toupper( char(*p
++) ) - 'A' );
776 while (nCol
<= MAXCOL
&& CharClass::isAsciiAlpha(*p
))
777 nCol
= sal::static_int_cast
<SCCOL
>( ((nCol
+ 1) * 26) + toupper( char(*p
++) ) - 'A' );
778 if( nCol
> MAXCOL
|| CharClass::isAsciiAlpha( *p
) )
781 *nFlags
|= SCA_VALID_COL
;
782 pAddr
->SetCol( nCol
);
787 static inline const sal_Unicode
*
788 lcl_a1_get_row( const sal_Unicode
* p
, ScAddress
* pAddr
, USHORT
* nFlags
)
790 const sal_Unicode
*pEnd
;
794 *nFlags
|= SCA_ROW_ABSOLUTE
, p
++;
796 n
= sal_Unicode_strtol( p
, &pEnd
) - 1;
797 if( NULL
== pEnd
|| p
== pEnd
|| n
< 0 || n
> MAXROW
)
800 *nFlags
|= SCA_VALID_ROW
;
801 pAddr
->SetRow( static_cast<SCROW
>(n
) );
807 lcl_ScRange_Parse_XL_A1( ScRange
& r
,
808 const sal_Unicode
* p
,
810 bool bOnlyAcceptSingle
,
811 ScAddress::ExternalInfo
* pExtInfo
,
812 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
814 const sal_Unicode
* tmp1
, *tmp2
;
815 String aExternDocName
, aStartTabName
, aEndTabName
; // for external link table
816 USHORT nFlags
= SCA_VALID
| SCA_VALID_TAB
, nFlags2
= SCA_VALID_TAB
;
820 ByteString
aStr(p
, RTL_TEXTENCODING_UTF8
);
821 aStr
.Append(static_cast< char >(0));
822 std::cerr
<< "parse::XL::A1 \'" << aStr
.GetBuffer() << '\'' << std::endl
;
825 p
= r
.Parse_XL_Header( p
, pDoc
, aExternDocName
, aStartTabName
,
826 aEndTabName
, nFlags
, bOnlyAcceptSingle
, pExternalLinks
);
828 if (aExternDocName
.Len() > 0)
829 lcl_ScRange_External_TabSpan( r
, nFlags
, pExtInfo
, aExternDocName
,
830 aStartTabName
, aEndTabName
, pDoc
);
835 tmp1
= lcl_a1_get_col( p
, &r
.aStart
, &nFlags
);
836 if( tmp1
== NULL
) // Is it a row only reference 3:5
838 if( bOnlyAcceptSingle
) // by definition full row refs are ranges
841 tmp1
= lcl_a1_get_row( p
, &r
.aStart
, &nFlags
);
843 tmp1
= lcl_eatWhiteSpace( tmp1
);
844 if( !tmp1
|| *tmp1
++ != ':' ) // Even a singleton requires ':' (eg 2:2)
847 tmp1
= lcl_eatWhiteSpace( tmp1
);
848 tmp2
= lcl_a1_get_row( tmp1
, &r
.aEnd
, &nFlags2
);
852 r
.aStart
.SetCol( 0 ); r
.aEnd
.SetCol( MAXCOL
);
854 SCA_VALID_COL
| SCA_VALID_COL2
|
855 SCA_COL_ABSOLUTE
| SCA_COL2_ABSOLUTE
;
856 nFlags
|= (nFlags2
<< 4);
860 tmp2
= lcl_a1_get_row( tmp1
, &r
.aStart
, &nFlags
);
861 if( tmp2
== NULL
) // check for col only reference F:H
863 if( bOnlyAcceptSingle
) // by definition full col refs are ranges
866 tmp1
= lcl_eatWhiteSpace( tmp1
);
867 if( *tmp1
++ != ':' ) // Even a singleton requires ':' (eg F:F)
870 tmp1
= lcl_eatWhiteSpace( tmp1
);
871 tmp2
= lcl_a1_get_col( tmp1
, &r
.aEnd
, &nFlags2
);
875 r
.aStart
.SetRow( 0 ); r
.aEnd
.SetRow( MAXROW
);
877 SCA_VALID_ROW
| SCA_VALID_ROW2
|
878 SCA_ROW_ABSOLUTE
| SCA_ROW2_ABSOLUTE
;
879 nFlags
|= (nFlags2
<< 4);
883 // prepare as if it's a singleton, in case we want to fall back */
884 r
.aEnd
.SetCol( r
.aStart
.Col() );
885 r
.aEnd
.SetRow( r
.aStart
.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header()
887 if ( bOnlyAcceptSingle
)
893 // any trailing invalid character must invalidate the address.
894 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
899 tmp2
= lcl_eatWhiteSpace( tmp2
);
902 // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is
903 // not. Any trailing invalid character invalidates the range.
904 if (*tmp2
== 0 && (nFlags
& SCA_TAB2_3D
))
906 if (nFlags
& SCA_COL_ABSOLUTE
)
907 nFlags
|= SCA_COL2_ABSOLUTE
;
908 if (nFlags
& SCA_ROW_ABSOLUTE
)
909 nFlags
|= SCA_ROW2_ABSOLUTE
;
912 nFlags
&= ~(SCA_VALID
|
913 SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
914 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
919 p
= lcl_eatWhiteSpace( p
+1 );
920 tmp1
= lcl_a1_get_col( p
, &r
.aEnd
, &nFlags2
);
921 if( !tmp1
) // strange, but valid singleton
924 tmp2
= lcl_a1_get_row( tmp1
, &r
.aEnd
, &nFlags2
);
925 if( !tmp2
) // strange, but valid singleton
930 // any trailing invalid character must invalidate the range.
931 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
932 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
936 nFlags
|= (nFlags2
<< 4);
941 @param pRange pointer to range where rAddr effectively is *pRange->aEnd,
942 used in conjunction with pExtInfo to determine the tab span
946 lcl_ScAddress_Parse_OOo( const sal_Unicode
* p
, ScDocument
* pDoc
, ScAddress
& rAddr
,
947 ScAddress::ExternalInfo
* pExtInfo
= NULL
, ScRange
* pRange
= NULL
)
950 String aDocName
; // der pure Dokumentenname
952 bool bExtDoc
= false;
953 bool bExtDocInherited
= false;
954 const ScAddress
aCurPos(rAddr
);
956 // Lets see if this is a reference to something in an external file. A
957 // document name is always quoted and has a trailing #.
960 const sal_Unicode
* pStart
= p
;
961 p
= lcl_ParseQuotedName(p
, aDocName
);
962 if (*p
++ == SC_COMPILER_FILE_TAB_SEP
)
965 // This is not a document name. Perhaps a quoted relative table
969 else if (pExtInfo
&& pExtInfo
->mbExternal
)
971 // This is an external reference.
972 bExtDoc
= bExtDocInherited
= true;
978 USHORT nBits
= SCA_VALID_TAB
;
979 const sal_Unicode
* q
;
980 if ( ScGlobal::FindUnquoted( p
, '.') )
984 nRes
|= SCA_TAB_ABSOLUTE
;
986 nRes
|= SCA_TAB_ABSOLUTE
, p
++;
990 // Tokens that start at ' can have anything in them until a final
991 // ' but '' marks an escaped '. We've earlier guaranteed that a
992 // string containing '' will be surrounded by '.
993 p
= lcl_ParseQuotedName(p
, aTab
);
1012 if (!bExtDoc
&& (!pDoc
|| !pDoc
->GetTable( aTab
, nTab
)))
1017 if (bExtDoc
&& !bExtDocInherited
)
1018 return nRes
; // After a document a sheet must follow.
1026 nBits
= SCA_VALID_COL
;
1028 nBits
|= SCA_COL_ABSOLUTE
, p
++;
1030 if (CharClass::isAsciiAlpha( *p
))
1032 nCol
= sal::static_int_cast
<SCCOL
>( toupper( char(*p
++) ) - 'A' );
1033 while (nCol
< MAXCOL
&& CharClass::isAsciiAlpha(*p
))
1034 nCol
= sal::static_int_cast
<SCCOL
>( ((nCol
+ 1) * 26) + toupper( char(*p
++) ) - 'A' );
1039 if( nCol
> MAXCOL
|| CharClass::isAsciiAlpha( *p
) )
1049 nBits
= SCA_VALID_ROW
;
1051 nBits
|= SCA_ROW_ABSOLUTE
, p
++;
1052 if( !CharClass::isAsciiDigit( *p
) )
1060 long n
= aTmp
.ToInt32() - 1;
1061 while (CharClass::isAsciiDigit( *p
))
1063 if( n
< 0 || n
> MAXROW
)
1065 nRow
= static_cast<SCROW
>(n
);
1072 rAddr
.Set( nCol
, nRow
, nTab
);
1080 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
1082 // Need document name if inherited.
1083 if (bExtDocInherited
)
1085 const String
* pFileName
= pRefMgr
->getExternalFileName( pExtInfo
->mnFileId
);
1087 aDocName
= *pFileName
;
1091 pRefMgr
->convertToAbsName(aDocName
);
1093 if ((!pExtInfo
|| !pExtInfo
->mbExternal
) && pRefMgr
->isOwnDocument(aDocName
))
1095 if (!pDoc
->GetTable( aTab
, nTab
))
1099 rAddr
.SetTab( nTab
);
1100 nRes
|= SCA_VALID_TAB
;
1109 if (!pExtInfo
->mbExternal
)
1111 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(aDocName
);
1113 pExtInfo
->mbExternal
= true;
1114 pExtInfo
->maTabName
= aTab
;
1115 pExtInfo
->mnFileId
= nFileId
;
1117 if (pRefMgr
->getSingleRefToken(nFileId
, aTab
,
1118 ScAddress(nCol
, nRow
, 0), NULL
,
1121 rAddr
.SetTab( nTab
);
1122 nRes
|= SCA_VALID_TAB
;
1129 // This is a call for the second part of the reference,
1130 // we must have the range to adapt tab span.
1135 USHORT nFlags
= nRes
| SCA_VALID_TAB2
;
1136 if (!lcl_ScRange_External_TabSpan( *pRange
, nFlags
,
1138 pExtInfo
->maTabName
, aTab
, pDoc
))
1139 nRes
&= ~SCA_VALID_TAB
;
1142 if (nFlags
& SCA_VALID_TAB2
)
1144 rAddr
.SetTab( pRange
->aEnd
.Tab());
1145 nRes
|= SCA_VALID_TAB
;
1148 nRes
&= ~SCA_VALID_TAB
;
1157 if ( !(nRes
& SCA_VALID_ROW
) && (nRes
& SCA_VALID_COL
)
1158 && !( (nRes
& SCA_TAB_3D
) && (nRes
& SCA_VALID_TAB
)) )
1159 { // no Row, no Tab, but Col => DM (...), B (...) et al
1164 USHORT nMask
= nRes
& ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
);
1165 if( nMask
== ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
) )
1174 lcl_ScAddress_Parse ( const sal_Unicode
* p
, ScDocument
* pDoc
, ScAddress
& rAddr
,
1175 const ScAddress::Details
& rDetails
,
1176 ScAddress::ExternalInfo
* pExtInfo
= NULL
,
1177 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
= NULL
)
1182 switch (rDetails
.eConv
)
1185 case formula::FormulaGrammar::CONV_OOO
:
1187 return lcl_ScAddress_Parse_OOo( p
, pDoc
, rAddr
, pExtInfo
, NULL
);
1190 case formula::FormulaGrammar::CONV_XL_A1
:
1191 case formula::FormulaGrammar::CONV_XL_OOX
:
1194 USHORT nFlags
= lcl_ScRange_Parse_XL_A1( r
, p
, pDoc
, true, pExtInfo
,
1195 (rDetails
.eConv
== formula::FormulaGrammar::CONV_XL_OOX
? pExternalLinks
: NULL
) );
1199 case formula::FormulaGrammar::CONV_XL_R1C1
:
1202 USHORT nFlags
= lcl_ScRange_Parse_XL_R1C1( r
, p
, pDoc
, rDetails
, true, pExtInfo
);
1210 bool ConvertSingleRef( ScDocument
* pDoc
, const String
& rRefString
,
1211 SCTAB nDefTab
, ScRefAddress
& rRefAddress
,
1212 const ScAddress::Details
& rDetails
,
1213 ScAddress::ExternalInfo
* pExtInfo
/* = NULL */ )
1216 if (pExtInfo
|| (ScGlobal::FindUnquoted( rRefString
, SC_COMPILER_FILE_TAB_SEP
) == STRING_NOTFOUND
))
1218 ScAddress
aAddr( 0, 0, nDefTab
);
1219 USHORT nRes
= aAddr
.Parse( rRefString
, pDoc
, rDetails
, pExtInfo
);
1220 if ( nRes
& SCA_VALID
)
1222 rRefAddress
.Set( aAddr
,
1223 ((nRes
& SCA_COL_ABSOLUTE
) == 0),
1224 ((nRes
& SCA_ROW_ABSOLUTE
) == 0),
1225 ((nRes
& SCA_TAB_ABSOLUTE
) == 0));
1233 bool ConvertDoubleRef( ScDocument
* pDoc
, const String
& rRefString
, SCTAB nDefTab
,
1234 ScRefAddress
& rStartRefAddress
, ScRefAddress
& rEndRefAddress
,
1235 const ScAddress::Details
& rDetails
,
1236 ScAddress::ExternalInfo
* pExtInfo
/* = NULL */ )
1239 if (pExtInfo
|| (ScGlobal::FindUnquoted( rRefString
, SC_COMPILER_FILE_TAB_SEP
) == STRING_NOTFOUND
))
1241 ScRange
aRange( ScAddress( 0, 0, nDefTab
));
1242 USHORT nRes
= aRange
.Parse( rRefString
, pDoc
, rDetails
, pExtInfo
);
1243 if ( nRes
& SCA_VALID
)
1245 rStartRefAddress
.Set( aRange
.aStart
,
1246 ((nRes
& SCA_COL_ABSOLUTE
) == 0),
1247 ((nRes
& SCA_ROW_ABSOLUTE
) == 0),
1248 ((nRes
& SCA_TAB_ABSOLUTE
) == 0));
1249 rEndRefAddress
.Set( aRange
.aEnd
,
1250 ((nRes
& SCA_COL2_ABSOLUTE
) == 0),
1251 ((nRes
& SCA_ROW2_ABSOLUTE
) == 0),
1252 ((nRes
& SCA_TAB2_ABSOLUTE
) == 0));
1260 USHORT
ScAddress::Parse( const String
& r
, ScDocument
* pDoc
,
1261 const Details
& rDetails
,
1262 ExternalInfo
* pExtInfo
,
1263 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
1265 return lcl_ScAddress_Parse( r
.GetBuffer(), pDoc
, *this, rDetails
, pExtInfo
, pExternalLinks
);
1269 bool ScRange::Intersects( const ScRange
& r
) const
1272 Min( aEnd
.Col(), r
.aEnd
.Col() ) < Max( aStart
.Col(), r
.aStart
.Col() )
1273 || Min( aEnd
.Row(), r
.aEnd
.Row() ) < Max( aStart
.Row(), r
.aStart
.Row() )
1274 || Min( aEnd
.Tab(), r
.aEnd
.Tab() ) < Max( aStart
.Tab(), r
.aStart
.Tab() )
1279 void ScRange::Justify()
1282 if ( aEnd
.Col() < (nTempCol
= aStart
.Col()) )
1284 aStart
.SetCol(aEnd
.Col()); aEnd
.SetCol(nTempCol
);
1287 if ( aEnd
.Row() < (nTempRow
= aStart
.Row()) )
1289 aStart
.SetRow(aEnd
.Row()); aEnd
.SetRow(nTempRow
);
1292 if ( aEnd
.Tab() < (nTempTab
= aStart
.Tab()) )
1294 aStart
.SetTab(aEnd
.Tab()); aEnd
.SetTab(nTempTab
);
1298 void ScRange::ExtendTo( const ScRange
& rRange
)
1300 DBG_ASSERT( rRange
.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" );
1303 aStart
.SetCol( ::std::min( aStart
.Col(), rRange
.aStart
.Col() ) );
1304 aStart
.SetRow( ::std::min( aStart
.Row(), rRange
.aStart
.Row() ) );
1305 aStart
.SetTab( ::std::min( aStart
.Tab(), rRange
.aStart
.Tab() ) );
1306 aEnd
.SetCol( ::std::max( aEnd
.Col(), rRange
.aEnd
.Col() ) );
1307 aEnd
.SetRow( ::std::max( aEnd
.Row(), rRange
.aEnd
.Row() ) );
1308 aEnd
.SetTab( ::std::max( aEnd
.Tab(), rRange
.aEnd
.Tab() ) );
1315 lcl_ScRange_Parse_OOo( ScRange
&aRange
, const String
& r
, ScDocument
* pDoc
, ScAddress::ExternalInfo
* pExtInfo
= NULL
)
1317 USHORT nRes1
= 0, nRes2
= 0;
1318 xub_StrLen nPos
= ScGlobal::FindUnquoted( r
, ':');
1319 if (nPos
!= STRING_NOTFOUND
)
1322 sal_Unicode
* p
= aTmp
.GetBufferAccess();
1324 if( (nRes1
= lcl_ScAddress_Parse_OOo( p
, pDoc
, aRange
.aStart
, pExtInfo
, NULL
) ) != 0 )
1326 aRange
.aEnd
= aRange
.aStart
; // sheet must be initialized identical to first sheet
1327 if ( (nRes2
= lcl_ScAddress_Parse_OOo( p
+ nPos
+ 1, pDoc
, aRange
.aEnd
, pExtInfo
, &aRange
) ) != 0 )
1329 // PutInOrder / Justify
1330 USHORT nMask
, nBits1
, nBits2
;
1332 if ( aRange
.aEnd
.Col() < (nTempCol
= aRange
.aStart
.Col()) )
1334 aRange
.aStart
.SetCol(aRange
.aEnd
.Col()); aRange
.aEnd
.SetCol(nTempCol
);
1335 nMask
= (SCA_VALID_COL
| SCA_COL_ABSOLUTE
);
1336 nBits1
= nRes1
& nMask
;
1337 nBits2
= nRes2
& nMask
;
1338 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1339 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1342 if ( aRange
.aEnd
.Row() < (nTempRow
= aRange
.aStart
.Row()) )
1344 aRange
.aStart
.SetRow(aRange
.aEnd
.Row()); aRange
.aEnd
.SetRow(nTempRow
);
1345 nMask
= (SCA_VALID_ROW
| SCA_ROW_ABSOLUTE
);
1346 nBits1
= nRes1
& nMask
;
1347 nBits2
= nRes2
& nMask
;
1348 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1349 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1352 if ( aRange
.aEnd
.Tab() < (nTempTab
= aRange
.aStart
.Tab()) )
1354 aRange
.aStart
.SetTab(aRange
.aEnd
.Tab()); aRange
.aEnd
.SetTab(nTempTab
);
1355 nMask
= (SCA_VALID_TAB
| SCA_TAB_ABSOLUTE
| SCA_TAB_3D
);
1356 nBits1
= nRes1
& nMask
;
1357 nBits2
= nRes2
& nMask
;
1358 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1359 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1361 if ( ((nRes1
& ( SCA_TAB_ABSOLUTE
| SCA_TAB_3D
))
1362 == ( SCA_TAB_ABSOLUTE
| SCA_TAB_3D
))
1363 && !(nRes2
& SCA_TAB_3D
) )
1364 nRes2
|= SCA_TAB_ABSOLUTE
;
1367 nRes1
= 0; // #38840# keine Tokens aus halben Sachen
1370 nRes1
= ( ( nRes1
| nRes2
) & SCA_VALID
)
1372 | ( ( nRes2
& SCA_BITS
) << 4 );
1376 USHORT
ScRange::Parse( const String
& r
, ScDocument
* pDoc
,
1377 const ScAddress::Details
& rDetails
,
1378 ScAddress::ExternalInfo
* pExtInfo
,
1379 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
1384 switch (rDetails
.eConv
)
1387 case formula::FormulaGrammar::CONV_OOO
:
1388 return lcl_ScRange_Parse_OOo( *this, r
, pDoc
, pExtInfo
);
1390 case formula::FormulaGrammar::CONV_XL_A1
:
1391 case formula::FormulaGrammar::CONV_XL_OOX
:
1392 return lcl_ScRange_Parse_XL_A1( *this, r
.GetBuffer(), pDoc
, false, pExtInfo
,
1393 (rDetails
.eConv
== formula::FormulaGrammar::CONV_XL_OOX
? pExternalLinks
: NULL
) );
1395 case formula::FormulaGrammar::CONV_XL_R1C1
:
1396 return lcl_ScRange_Parse_XL_R1C1( *this, r
.GetBuffer(), pDoc
, rDetails
, false, pExtInfo
);
1401 // Accept a full range, or an address
1402 USHORT
ScRange::ParseAny( const String
& r
, ScDocument
* pDoc
,
1403 const ScAddress::Details
& rDetails
)
1405 USHORT nRet
= Parse( r
, pDoc
, rDetails
);
1406 const USHORT nValid
= SCA_VALID
| SCA_VALID_COL2
| SCA_VALID_ROW2
|
1409 if ( (nRet
& nValid
) != nValid
)
1412 nRet
= aAdr
.Parse( r
, pDoc
, rDetails
);
1413 if ( nRet
& SCA_VALID
)
1414 aStart
= aEnd
= aAdr
;
1419 // Parse only full row references
1420 USHORT
ScRange::ParseCols( const String
& rStr
, ScDocument
* pDoc
,
1421 const ScAddress::Details
& rDetails
)
1423 const sal_Unicode
* p
= rStr
.GetBuffer();
1424 USHORT nRes
= 0, ignored
= 0;
1429 pDoc
= NULL
; // make compiler shutup we may need this later
1431 switch (rDetails
.eConv
)
1434 case formula::FormulaGrammar::CONV_OOO
: // No full col refs in OOO yet, assume XL notation
1435 case formula::FormulaGrammar::CONV_XL_A1
:
1436 case formula::FormulaGrammar::CONV_XL_OOX
:
1437 if (NULL
!= (p
= lcl_a1_get_col( p
, &aStart
, &ignored
) ) )
1441 if( NULL
!= (p
= lcl_a1_get_col( p
+1, &aEnd
, &ignored
)))
1443 nRes
= SCA_VALID_COL
;
1449 nRes
= SCA_VALID_COL
;
1454 case formula::FormulaGrammar::CONV_XL_R1C1
:
1455 if ((p
[0] == 'C' || p
[0] != 'c') &&
1456 NULL
!= (p
= lcl_r1c1_get_col( p
, rDetails
, &aStart
, &ignored
)))
1460 if( (p
[1] == 'C' || p
[1] == 'c') &&
1461 NULL
!= (p
= lcl_r1c1_get_col( p
+1, rDetails
, &aEnd
, &ignored
)))
1463 nRes
= SCA_VALID_COL
;
1469 nRes
= SCA_VALID_COL
;
1475 return (p
!= NULL
&& *p
== '\0') ? nRes
: 0;
1478 // Parse only full row references
1479 USHORT
ScRange::ParseRows( const String
& rStr
, ScDocument
* pDoc
,
1480 const ScAddress::Details
& rDetails
)
1482 const sal_Unicode
* p
= rStr
.GetBuffer();
1483 USHORT nRes
= 0, ignored
= 0;
1488 pDoc
= NULL
; // make compiler shutup we may need this later
1490 switch (rDetails
.eConv
)
1493 case formula::FormulaGrammar::CONV_OOO
: // No full row refs in OOO yet, assume XL notation
1494 case formula::FormulaGrammar::CONV_XL_A1
:
1495 case formula::FormulaGrammar::CONV_XL_OOX
:
1496 if (NULL
!= (p
= lcl_a1_get_row( p
, &aStart
, &ignored
) ) )
1500 if( NULL
!= (p
= lcl_a1_get_row( p
+1, &aEnd
, &ignored
)))
1502 nRes
= SCA_VALID_COL
;
1508 nRes
= SCA_VALID_COL
;
1513 case formula::FormulaGrammar::CONV_XL_R1C1
:
1514 if ((p
[0] == 'R' || p
[0] != 'r') &&
1515 NULL
!= (p
= lcl_r1c1_get_row( p
, rDetails
, &aStart
, &ignored
)))
1519 if( (p
[1] == 'R' || p
[1] == 'r') &&
1520 NULL
!= (p
= lcl_r1c1_get_row( p
+1, rDetails
, &aEnd
, &ignored
)))
1522 nRes
= SCA_VALID_COL
;
1528 nRes
= SCA_VALID_COL
;
1534 return (p
!= NULL
&& *p
== '\0') ? nRes
: 0;
1538 lcl_a1_append_c ( String
&r
, int nCol
, bool bIsAbs
)
1542 ScColToAlpha( r
, sal::static_int_cast
<SCCOL
>(nCol
) );
1546 lcl_a1_append_r ( String
&r
, int nRow
, bool bIsAbs
)
1550 r
+= String::CreateFromInt32( nRow
+1 );
1554 lcl_r1c1_append_c ( String
&r
, int nCol
, bool bIsAbs
,
1555 const ScAddress::Details
& rDetails
)
1560 r
+= String::CreateFromInt32( nCol
+ 1 );
1564 nCol
-= rDetails
.nCol
;
1567 r
+= String::CreateFromInt32( nCol
);
1573 lcl_r1c1_append_r ( String
&r
, int nRow
, bool bIsAbs
,
1574 const ScAddress::Details
& rDetails
)
1579 r
+= String::CreateFromInt32( nRow
+ 1 );
1583 nRow
-= rDetails
.nRow
;
1586 r
+= String::CreateFromInt32( nRow
);
1593 getFileNameFromDoc( const ScDocument
* pDoc
)
1595 // TODO : er points at ScGlobal::GetAbsDocName()
1596 // as a better template. Look into it
1598 SfxObjectShell
* pShell
;
1601 NULL
!= (pShell
= pDoc
->GetDocumentShell() ) )
1603 uno::Reference
< frame::XModel
> xModel( pShell
->GetModel(), uno::UNO_QUERY
);
1606 if( xModel
->getURL().getLength() )
1608 INetURLObject
aURL( xModel
->getURL() );
1609 sFileName
= aURL
.GetLastName();
1612 sFileName
= pShell
->GetTitle();
1617 ByteString
aStr( sFileName
, RTL_TEXTENCODING_UTF8
);
1618 aStr
.Append(static_cast< char >(0));
1619 std::cerr
<< "docname \'" << aStr
.GetBuffer() << '\'' << std::endl
;
1625 void ScAddress::Format( String
& r
, USHORT nFlags
, ScDocument
* pDoc
,
1626 const Details
& rDetails
) const
1629 if( nFlags
& SCA_VALID
)
1630 nFlags
|= ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
);
1631 if( pDoc
&& (nFlags
& SCA_VALID_TAB
) )
1633 if ( nTab
>= pDoc
->GetTableCount() )
1635 r
= ScGlobal::GetRscString( STR_NOREF_STR
);
1638 // if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) )
1639 if( nFlags
& SCA_TAB_3D
)
1641 String aTabName
, aDocName
;
1642 pDoc
->GetName( nTab
, aTabName
);
1643 // External Reference, same as in ScCompiler::MakeTabStr()
1644 if( aTabName
.GetChar(0) == '\'' )
1646 xub_StrLen nPos
= ScGlobal::FindUnquoted( aTabName
, SC_COMPILER_FILE_TAB_SEP
);
1647 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && aTabName
.GetChar(nPos
-1) == '\'')
1649 aDocName
= aTabName
.Copy( 0, nPos
+ 1 );
1650 aTabName
.Erase( 0, nPos
+ 1 );
1653 else if( nFlags
& SCA_FORCE_DOC
)
1655 // VBA has an 'external' flag that forces the addition of the
1656 // tab name _and_ the doc name. The VBA code would be
1657 // needlessly complicated if it constructed an actual external
1658 // reference so we add this somewhat cheesy kludge to force the
1659 // addition of the document name even for non-external references
1660 aDocName
= getFileNameFromDoc( pDoc
);
1662 ScCompiler::CheckTabQuotes( aTabName
, rDetails
.eConv
);
1664 switch( rDetails
.eConv
)
1667 case formula::FormulaGrammar::CONV_OOO
:
1669 if( nFlags
& SCA_TAB_ABSOLUTE
)
1675 case formula::FormulaGrammar::CONV_XL_A1
:
1676 case formula::FormulaGrammar::CONV_XL_R1C1
:
1677 case formula::FormulaGrammar::CONV_XL_OOX
:
1678 if (aDocName
.Len() > 0)
1690 switch( rDetails
.eConv
)
1693 case formula::FormulaGrammar::CONV_OOO
:
1694 case formula::FormulaGrammar::CONV_XL_A1
:
1695 case formula::FormulaGrammar::CONV_XL_OOX
:
1696 if( nFlags
& SCA_VALID_COL
)
1697 lcl_a1_append_c ( r
, nCol
, nFlags
& SCA_COL_ABSOLUTE
);
1698 if( nFlags
& SCA_VALID_ROW
)
1699 lcl_a1_append_r ( r
, nRow
, nFlags
& SCA_ROW_ABSOLUTE
);
1702 case formula::FormulaGrammar::CONV_XL_R1C1
:
1703 if( nFlags
& SCA_VALID_ROW
)
1704 lcl_r1c1_append_r ( r
, nRow
, nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1705 if( nFlags
& SCA_VALID_COL
)
1706 lcl_r1c1_append_c ( r
, nCol
, nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1712 lcl_Split_DocTab( const ScDocument
* pDoc
, SCTAB nTab
,
1713 const ScAddress::Details
& rDetails
,
1715 String
& rTabName
, String
& rDocName
)
1717 pDoc
->GetName( nTab
, rTabName
);
1721 ByteString
aStr(rTabName
, RTL_TEXTENCODING_UTF8
);
1722 aStr
.Append(static_cast< char >(0));
1723 std::cerr
<< "tabname \'" << aStr
.GetBuffer() << '\'' << std::endl
;
1726 // External reference, same as in ScCompiler::MakeTabStr()
1727 if ( rTabName
.GetChar(0) == '\'' )
1729 xub_StrLen nPos
= ScGlobal::FindUnquoted( rTabName
, SC_COMPILER_FILE_TAB_SEP
);
1730 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && rTabName
.GetChar(nPos
-1) == '\'')
1732 rDocName
= rTabName
.Copy( 0, nPos
+ 1 );
1733 rTabName
.Erase( 0, nPos
+ 1 );
1736 else if( nFlags
& SCA_FORCE_DOC
)
1738 // VBA has an 'external' flag that forces the addition of the
1739 // tab name _and_ the doc name. The VBA code would be
1740 // needlessly complicated if it constructed an actual external
1741 // reference so we add this somewhat cheesy kludge to force the
1742 // addition of the document name even for non-external references
1743 rDocName
= getFileNameFromDoc( pDoc
);
1745 ScCompiler::CheckTabQuotes( rTabName
, rDetails
.eConv
);
1749 lcl_ScRange_Format_XL_Header( String
& r
, const ScRange
& rRange
,
1750 USHORT nFlags
, ScDocument
* pDoc
,
1751 const ScAddress::Details
& rDetails
)
1753 if( nFlags
& SCA_TAB_3D
)
1755 String aTabName
, aDocName
;
1756 lcl_Split_DocTab( pDoc
, rRange
.aStart
.Tab(), rDetails
, nFlags
,
1757 aTabName
, aDocName
);
1758 if( aDocName
.Len() > 0 )
1766 if( nFlags
& SCA_TAB2_3D
)
1768 lcl_Split_DocTab( pDoc
, rRange
.aEnd
.Tab(), rDetails
, nFlags
,
1769 aTabName
, aDocName
);
1777 void ScRange::Format( String
& r
, USHORT nFlags
, ScDocument
* pDoc
,
1778 const ScAddress::Details
& rDetails
) const
1781 if( !( nFlags
& SCA_VALID
) )
1783 r
= ScGlobal::GetRscString( STR_NOREF_STR
);
1787 #define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask)))
1788 switch( rDetails
.eConv
) {
1790 case formula::FormulaGrammar::CONV_OOO
: {
1791 BOOL bOneTab
= (aStart
.Tab() == aEnd
.Tab());
1793 nFlags
|= SCA_TAB_3D
;
1794 aStart
.Format( r
, nFlags
, pDoc
, rDetails
);
1795 if( aStart
!= aEnd
||
1796 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1797 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
))
1800 nFlags
= ( nFlags
& SCA_VALID
) | ( ( nFlags
>> 4 ) & 0x070F );
1804 nFlags
|= SCA_TAB_3D
;
1805 aEnd
.Format( aName
, nFlags
, pDoc
, rDetails
);
1812 case formula::FormulaGrammar::CONV_XL_A1
:
1813 case formula::FormulaGrammar::CONV_XL_OOX
:
1814 lcl_ScRange_Format_XL_Header( r
, *this, nFlags
, pDoc
, rDetails
);
1815 if( aStart
.Col() == 0 && aEnd
.Col() >= MAXCOL
)
1817 // Full col refs always require 2 rows (2:2)
1818 lcl_a1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
);
1820 lcl_a1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
);
1822 else if( aStart
.Row() == 0 && aEnd
.Row() >= MAXROW
)
1824 // Full row refs always require 2 cols (A:A)
1825 lcl_a1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
);
1827 lcl_a1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
);
1831 lcl_a1_append_c ( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
);
1832 lcl_a1_append_r ( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
);
1833 if( aStart
.Col() != aEnd
.Col() ||
1834 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1835 aStart
.Row() != aEnd
.Row() ||
1836 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1838 lcl_a1_append_c ( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
);
1839 lcl_a1_append_r ( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
);
1844 case formula::FormulaGrammar::CONV_XL_R1C1
:
1845 lcl_ScRange_Format_XL_Header( r
, *this, nFlags
, pDoc
, rDetails
);
1846 if( aStart
.Col() == 0 && aEnd
.Col() >= MAXCOL
)
1848 lcl_r1c1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1849 if( aStart
.Row() != aEnd
.Row() ||
1850 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1852 lcl_r1c1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
, rDetails
);
1855 else if( aStart
.Row() == 0 && aEnd
.Row() >= MAXROW
)
1857 lcl_r1c1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1858 if( aStart
.Col() != aEnd
.Col() ||
1859 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
)) {
1861 lcl_r1c1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
, rDetails
);
1866 lcl_r1c1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1867 lcl_r1c1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1868 if( aStart
.Col() != aEnd
.Col() ||
1869 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1870 aStart
.Row() != aEnd
.Row() ||
1871 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1873 lcl_r1c1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
, rDetails
);
1874 lcl_r1c1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
, rDetails
);
1878 #undef absrel_differ
1881 bool ScAddress::Move( SCsCOL dx
, SCsROW dy
, SCsTAB dz
, ScDocument
* pDoc
)
1883 SCsTAB nMaxTab
= pDoc
? pDoc
->GetTableCount() : MAXTAB
+1;
1889 dx
= 0, bValid
= FALSE
;
1890 else if( dx
> MAXCOL
)
1891 dx
= MAXCOL
, bValid
=FALSE
;
1893 dy
= 0, bValid
= FALSE
;
1894 else if( dy
> MAXROW
)
1895 dy
= MAXROW
, bValid
=FALSE
;
1897 dz
= 0, bValid
= FALSE
;
1898 else if( dz
>= nMaxTab
)
1899 dz
= nMaxTab
-1, bValid
=FALSE
;
1905 bool ScRange::Move( SCsCOL dx
, SCsROW dy
, SCsTAB dz
, ScDocument
* pDoc
)
1907 // Einfahces &, damit beides ausgefuehrt wird!!
1908 return aStart
.Move( dx
, dy
, dz
, pDoc
) & aEnd
.Move( dx
, dy
, dz
, pDoc
);
1912 String
ScAddress::GetColRowString( bool bAbsolute
,
1913 const Details
& rDetails
) const
1917 switch( rDetails
.eConv
)
1920 case formula::FormulaGrammar::CONV_OOO
:
1921 case formula::FormulaGrammar::CONV_XL_A1
:
1922 case formula::FormulaGrammar::CONV_XL_OOX
:
1924 aString
.Append( '$' );
1926 ScColToAlpha( aString
, nCol
);
1929 aString
.Append( '$' );
1931 aString
+= String::CreateFromInt32(nRow
+1);
1934 case formula::FormulaGrammar::CONV_XL_R1C1
:
1935 lcl_r1c1_append_r ( aString
, nRow
, bAbsolute
, rDetails
);
1936 lcl_r1c1_append_c ( aString
, nCol
, bAbsolute
, rDetails
);
1944 String
ScRefAddress::GetRefString( ScDocument
* pDoc
, SCTAB nActTab
,
1945 const ScAddress::Details
& rDetails
) const
1948 return EMPTY_STRING
;
1949 if ( Tab()+1 > pDoc
->GetTableCount() )
1950 return ScGlobal::GetRscString( STR_NOREF_STR
);
1953 USHORT nFlags
= SCA_VALID
;
1954 if ( nActTab
!= Tab() )
1956 nFlags
|= SCA_TAB_3D
;
1958 nFlags
|= SCA_TAB_ABSOLUTE
;
1961 nFlags
|= SCA_COL_ABSOLUTE
;
1963 nFlags
|= SCA_ROW_ABSOLUTE
;
1965 aAdr
.Format( aString
, nFlags
, pDoc
, rDetails
);
1970 //------------------------------------------------------------------------
1972 void ScColToAlpha( rtl::OUStringBuffer
& rBuf
, SCCOL nCol
)
1977 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1978 static_cast<sal_uInt16
>(nCol
)));
1981 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1982 (static_cast<sal_uInt16
>(nCol
) / 26) - 1));
1983 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1984 (static_cast<sal_uInt16
>(nCol
) % 26)));
1992 SCCOL nC
= nCol
% 26;
1993 aStr
+= static_cast<sal_Unicode
>( 'A' +
1994 static_cast<sal_uInt16
>(nC
));
1995 nCol
= sal::static_int_cast
<SCCOL
>( nCol
- nC
);
1996 nCol
= nCol
/ 26 - 1;
1998 aStr
+= static_cast<sal_Unicode
>( 'A' +
1999 static_cast<sal_uInt16
>(nCol
));
2006 bool AlphaToCol( SCCOL
& rCol
, const String
& rStr
)
2009 xub_StrLen nStop
= rStr
.Len();
2010 xub_StrLen nPos
= 0;
2012 while (nResult
<= MAXCOL
&& nPos
< nStop
&& (c
= rStr
.GetChar( nPos
)) != 0 &&
2013 CharClass::isAsciiAlpha(c
))
2016 nResult
= (nResult
+ 1) * 26;
2017 nResult
+= ScGlobal::ToUpperAlpha(c
) - 'A';
2020 bool bOk
= (ValidCol(nResult
) && nPos
> 0);