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 static const sal_Unicode
*
225 lcl_XL_ParseSheetRef( const sal_Unicode
* start
,
226 String
& rExternTabName
,
230 const sal_Unicode
*p
= start
;
232 if( *p
== '\'' ) // XL only seems to use single quotes for sheet names
234 p
= lcl_ParseQuotedName(p
, aTabName
);
240 bool only_digits
= TRUE
;
247 * Some names starting with digits are actually valid, but
248 * unparse quoted. Things are quite tricky: most sheet names
249 * starting with a digit are ok, but not those starting with
250 * "[0-9]*\." or "[0-9]+[eE]".
259 const sal_Unicode uc
= *p
;
260 if( CharClass::isAsciiAlpha( uc
) || uc
== '_' )
262 if( only_digits
&& p
!= start
&&
263 (uc
== 'e' || uc
== 'E' ) )
271 else if( CharClass::isAsciiDigit( uc
))
277 if( only_digits
) // Valid, except after only digits.
286 // non ASCII character is allowed.
293 if( *p
!= '!' &&( !allow_3d
|| *p
!= ':' ) )
296 aTabName
.Append( start
, sal::static_int_cast
<xub_StrLen
>( p
- start
) );
299 rExternTabName
= aTabName
;
304 const sal_Unicode
* ScRange::Parse_XL_Header(
305 const sal_Unicode
* p
,
306 const ScDocument
* pDoc
,
307 String
& rExternDocName
,
308 String
& rStartTabName
,
311 bool bOnlyAcceptSingle
,
312 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
314 const sal_Unicode
* startTabs
, *start
= p
;
315 USHORT nSaveFlags
= nFlags
;
317 // Is this an external reference ?
318 rStartTabName
.Erase();
320 rExternDocName
.Erase();
324 // Only single quotes are correct, and a double single quote escapes a
325 // single quote text inside the quoted text.
328 p
= lcl_ParseQuotedName(p
, rExternDocName
);
329 if (!*p
|| *p
!= ']' || !rExternDocName
.Len())
334 // non-quoted file name.
335 p
= ScGlobal::UnicodeStrChr( start
+1, ']' );
338 rExternDocName
.Append( start
+1, sal::static_int_cast
<xub_StrLen
>( p
-(start
+1) ) );
342 // 1-based, sequence starts with an empty element.
343 if (pExternalLinks
&& pExternalLinks
->getLength() > 1)
345 // A numeric "document name" is an index into the sequence.
346 if (CharClass::isAsciiNumeric( rExternDocName
))
348 sal_Int32 i
= rExternDocName
.ToInt32();
349 if (i
<= 0 || i
>= pExternalLinks
->getLength())
351 const sheet::ExternalLinkInfo
& rInfo
= (*pExternalLinks
)[i
];
354 case sheet::ExternalLinkType::DOCUMENT
:
357 if (!(rInfo
.Data
>>= aStr
))
359 DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i
);
362 rExternDocName
= aStr
;
366 DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d",
372 rExternDocName
= ScGlobal::GetAbsDocName(rExternDocName
, pDoc
->GetDocumentShell());
376 p
= lcl_XL_ParseSheetRef( p
, rStartTabName
, !bOnlyAcceptSingle
);
378 return start
; // invalid tab
379 if (bOnlyAcceptSingle
&& *p
== ':')
383 nFlags
|= SCA_VALID_TAB
| SCA_TAB_3D
| SCA_TAB_ABSOLUTE
;
384 if( *p
== ':' ) // 3d ref
386 p
= lcl_XL_ParseSheetRef( p
+1, rEndTabName
, false );
390 return start
; // invalid tab
392 nFlags
|= SCA_VALID_TAB2
| SCA_TAB2_3D
| SCA_TAB2_ABSOLUTE
;
396 // If only one sheet is given, the full reference is still valid,
397 // only the second 3D flag is not set.
398 nFlags
|= SCA_VALID_TAB2
| SCA_TAB2_ABSOLUTE
;
399 aEnd
.SetTab( aStart
.Tab() );
405 return start
; // syntax error
408 p
= lcl_eatWhiteSpace( p
);
412 nFlags
|= SCA_VALID_TAB
| SCA_VALID_TAB2
;
413 // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. );
416 if (!rExternDocName
.Len())
418 // Internal reference.
419 if (!rStartTabName
.Len())
426 if (!pDoc
->GetTable(rStartTabName
, nTab
))
428 // invalid table name.
429 nFlags
&= ~SCA_VALID_TAB
;
436 if (rEndTabName
.Len())
438 if (!pDoc
->GetTable(rEndTabName
, nTab
))
440 // invalid table name.
441 nFlags
&= ~SCA_VALID_TAB2
;
452 static const sal_Unicode
*
453 lcl_r1c1_get_col( const sal_Unicode
* p
,
454 const ScAddress::Details
& rDetails
,
455 ScAddress
* pAddr
, USHORT
* nFlags
)
457 const sal_Unicode
*pEnd
;
465 if( (isRelative
= (*p
== '[') ) != false )
467 n
= sal_Unicode_strtol( p
, &pEnd
);
471 if( p
== pEnd
) // C is a relative ref with offset 0
477 else if( isRelative
)
486 *nFlags
|= SCA_COL_ABSOLUTE
;
490 if( n
< 0 || n
>= MAXCOLCOUNT
)
492 pAddr
->SetCol( static_cast<SCCOL
>( n
) );
493 *nFlags
|= SCA_VALID_COL
;
497 static inline const sal_Unicode
*
498 lcl_r1c1_get_row( const sal_Unicode
* p
,
499 const ScAddress::Details
& rDetails
,
500 ScAddress
* pAddr
, USHORT
* nFlags
)
502 const sal_Unicode
*pEnd
;
510 if( (isRelative
= (*p
== '[') ) != false )
512 n
= sal_Unicode_strtol( p
, &pEnd
);
516 if( p
== pEnd
) // R is a relative ref with offset 0
522 else if( isRelative
)
531 *nFlags
|= SCA_ROW_ABSOLUTE
;
535 if( n
< 0 || n
>= MAXROWCOUNT
)
537 pAddr
->SetRow( static_cast<SCROW
>( n
) );
538 *nFlags
|= SCA_VALID_ROW
;
544 lcl_ScRange_Parse_XL_R1C1( ScRange
& r
,
545 const sal_Unicode
* p
,
547 const ScAddress::Details
& rDetails
,
548 bool bOnlyAcceptSingle
,
549 ScAddress::ExternalInfo
* pExtInfo
)
551 const sal_Unicode
* pTmp
= NULL
;
552 String aExternDocName
, aStartTabName
, aEndTabName
;
553 USHORT nFlags
= SCA_VALID
| SCA_VALID_TAB
, nFlags2
= SCA_VALID_TAB2
;
557 ByteString
aStr(p
, RTL_TEXTENCODING_UTF8
);
558 aStr
.Append(static_cast< char >(0));
559 std::cerr
<< "parse::XL::R1C1 \'" << aStr
.GetBuffer() << '\'' << std::endl
;
562 p
= r
.Parse_XL_Header( p
, pDoc
, aExternDocName
, aStartTabName
,
563 aEndTabName
, nFlags
, bOnlyAcceptSingle
, NULL
);
565 if (aExternDocName
.Len() > 0)
566 lcl_ScRange_External_TabSpan( r
, nFlags
, pExtInfo
, aExternDocName
,
567 aStartTabName
, aEndTabName
, pDoc
);
572 if( *p
== 'R' || *p
== 'r' )
574 if( NULL
== (p
= lcl_r1c1_get_row( p
, rDetails
, &r
.aStart
, &nFlags
)) )
577 if( *p
!= 'C' && *p
!= 'c' ) // full row R#
579 if( p
[0] != ':' || (p
[1] != 'R' && p
[1] != 'r' ) ||
580 NULL
== (pTmp
= lcl_r1c1_get_row( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)))
582 // Only the initial row number is given, or the second row
583 // number is invalid. Fallback to just the initial R
584 nFlags
|= (nFlags
<< 4);
585 r
.aEnd
.SetRow( r
.aStart
.Row() );
589 // Full row range successfully parsed.
590 nFlags
|= (nFlags2
<< 4);
596 // any trailing invalid character must invalidate the whole address.
597 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
602 SCA_VALID_COL
| SCA_VALID_COL2
|
603 SCA_COL_ABSOLUTE
| SCA_COL2_ABSOLUTE
;
604 r
.aStart
.SetCol( 0 );
605 r
.aEnd
.SetCol( MAXCOL
);
607 return bOnlyAcceptSingle
? 0 : nFlags
;
609 else if( NULL
== (p
= lcl_r1c1_get_col( p
, rDetails
, &r
.aStart
, &nFlags
)))
613 (p
[1] != 'R' && p
[1] != 'r') ||
614 NULL
== (pTmp
= lcl_r1c1_get_row( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)) ||
615 (*pTmp
!= 'C' && *pTmp
!= 'c') ||
616 NULL
== (pTmp
= lcl_r1c1_get_col( pTmp
, rDetails
, &r
.aEnd
, &nFlags2
)))
618 // single cell reference
622 // any trailing invalid character must invalidate the whole address.
623 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
627 return bOnlyAcceptSingle
? nFlags
: 0;
635 // any trailing invalid character must invalidate the whole range.
636 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
637 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
641 nFlags
|= (nFlags2
<< 4);
642 return bOnlyAcceptSingle
? 0 : nFlags
;
644 else if( *p
== 'C' || *p
== 'c' ) // full col C#
646 if( NULL
== (p
= lcl_r1c1_get_col( p
, rDetails
, &r
.aStart
, &nFlags
)))
649 if( p
[0] != ':' || (p
[1] != 'C' && p
[1] != 'c') ||
650 NULL
== (pTmp
= lcl_r1c1_get_col( p
+1, rDetails
, &r
.aEnd
, &nFlags2
)))
651 { // Fallback to just the initial C
652 nFlags
|= (nFlags
<< 4);
653 r
.aEnd
.SetCol( r
.aStart
.Col() );
657 nFlags
|= (nFlags2
<< 4);
663 // any trailing invalid character must invalidate the whole address.
664 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
669 SCA_VALID_ROW
| SCA_VALID_ROW2
|
670 SCA_ROW_ABSOLUTE
| SCA_ROW2_ABSOLUTE
;
671 r
.aStart
.SetRow( 0 );
672 r
.aEnd
.SetRow( MAXROW
);
674 return bOnlyAcceptSingle
? 0 : nFlags
;
681 static inline const sal_Unicode
*
682 lcl_a1_get_col( const sal_Unicode
* p
, ScAddress
* pAddr
, USHORT
* nFlags
)
687 *nFlags
|= SCA_COL_ABSOLUTE
, p
++;
689 if( !CharClass::isAsciiAlpha( *p
) )
692 nCol
= sal::static_int_cast
<SCCOL
>( toupper( char(*p
++) ) - 'A' );
693 while (nCol
<= MAXCOL
&& CharClass::isAsciiAlpha(*p
))
694 nCol
= sal::static_int_cast
<SCCOL
>( ((nCol
+ 1) * 26) + toupper( char(*p
++) ) - 'A' );
695 if( nCol
> MAXCOL
|| CharClass::isAsciiAlpha( *p
) )
698 *nFlags
|= SCA_VALID_COL
;
699 pAddr
->SetCol( nCol
);
704 static inline const sal_Unicode
*
705 lcl_a1_get_row( const sal_Unicode
* p
, ScAddress
* pAddr
, USHORT
* nFlags
)
707 const sal_Unicode
*pEnd
;
711 *nFlags
|= SCA_ROW_ABSOLUTE
, p
++;
713 n
= sal_Unicode_strtol( p
, &pEnd
) - 1;
714 if( NULL
== pEnd
|| p
== pEnd
|| n
< 0 || n
> MAXROW
)
717 *nFlags
|= SCA_VALID_ROW
;
718 pAddr
->SetRow( static_cast<SCROW
>(n
) );
724 lcl_ScRange_Parse_XL_A1( ScRange
& r
,
725 const sal_Unicode
* p
,
727 bool bOnlyAcceptSingle
,
728 ScAddress::ExternalInfo
* pExtInfo
,
729 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
731 const sal_Unicode
* tmp1
, *tmp2
;
732 String aExternDocName
, aStartTabName
, aEndTabName
; // for external link table
733 USHORT nFlags
= SCA_VALID
| SCA_VALID_TAB
, nFlags2
= SCA_VALID_TAB
;
737 ByteString
aStr(p
, RTL_TEXTENCODING_UTF8
);
738 aStr
.Append(static_cast< char >(0));
739 std::cerr
<< "parse::XL::A1 \'" << aStr
.GetBuffer() << '\'' << std::endl
;
742 p
= r
.Parse_XL_Header( p
, pDoc
, aExternDocName
, aStartTabName
,
743 aEndTabName
, nFlags
, bOnlyAcceptSingle
, pExternalLinks
);
745 if (aExternDocName
.Len() > 0)
746 lcl_ScRange_External_TabSpan( r
, nFlags
, pExtInfo
, aExternDocName
,
747 aStartTabName
, aEndTabName
, pDoc
);
752 tmp1
= lcl_a1_get_col( p
, &r
.aStart
, &nFlags
);
753 if( tmp1
== NULL
) // Is it a row only reference 3:5
755 if( bOnlyAcceptSingle
) // by definition full row refs are ranges
758 tmp1
= lcl_a1_get_row( p
, &r
.aStart
, &nFlags
);
760 tmp1
= lcl_eatWhiteSpace( tmp1
);
761 if( !tmp1
|| *tmp1
++ != ':' ) // Even a singleton requires ':' (eg 2:2)
764 tmp1
= lcl_eatWhiteSpace( tmp1
);
765 tmp2
= lcl_a1_get_row( tmp1
, &r
.aEnd
, &nFlags2
);
769 r
.aStart
.SetCol( 0 ); r
.aEnd
.SetCol( MAXCOL
);
771 SCA_VALID_COL
| SCA_VALID_COL2
|
772 SCA_COL_ABSOLUTE
| SCA_COL2_ABSOLUTE
;
773 nFlags
|= (nFlags2
<< 4);
777 tmp2
= lcl_a1_get_row( tmp1
, &r
.aStart
, &nFlags
);
778 if( tmp2
== NULL
) // check for col only reference F:H
780 if( bOnlyAcceptSingle
) // by definition full col refs are ranges
783 tmp1
= lcl_eatWhiteSpace( tmp1
);
784 if( *tmp1
++ != ':' ) // Even a singleton requires ':' (eg F:F)
787 tmp1
= lcl_eatWhiteSpace( tmp1
);
788 tmp2
= lcl_a1_get_col( tmp1
, &r
.aEnd
, &nFlags2
);
792 r
.aStart
.SetRow( 0 ); r
.aEnd
.SetRow( MAXROW
);
794 SCA_VALID_ROW
| SCA_VALID_ROW2
|
795 SCA_ROW_ABSOLUTE
| SCA_ROW2_ABSOLUTE
;
796 nFlags
|= (nFlags2
<< 4);
800 // prepare as if it's a singleton, in case we want to fall back */
801 r
.aEnd
.SetCol( r
.aStart
.Col() );
802 r
.aEnd
.SetRow( r
.aStart
.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header()
804 if ( bOnlyAcceptSingle
)
810 // any trailing invalid character must invalidate the address.
811 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
);
816 tmp2
= lcl_eatWhiteSpace( tmp2
);
819 // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is
820 // not. Any trailing invalid character invalidates the range.
821 if (*tmp2
== 0 && (nFlags
& SCA_TAB2_3D
))
823 if (nFlags
& SCA_COL_ABSOLUTE
)
824 nFlags
|= SCA_COL2_ABSOLUTE
;
825 if (nFlags
& SCA_ROW_ABSOLUTE
)
826 nFlags
|= SCA_ROW2_ABSOLUTE
;
829 nFlags
&= ~(SCA_VALID
|
830 SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
831 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
836 p
= lcl_eatWhiteSpace( p
+1 );
837 tmp1
= lcl_a1_get_col( p
, &r
.aEnd
, &nFlags2
);
838 if( !tmp1
) // strange, but valid singleton
841 tmp2
= lcl_a1_get_row( tmp1
, &r
.aEnd
, &nFlags2
);
842 if( !tmp2
) // strange, but valid singleton
847 // any trailing invalid character must invalidate the range.
848 nFlags
&= ~(SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
| SCA_VALID_TAB
|
849 SCA_VALID_COL2
| SCA_VALID_ROW2
| SCA_VALID_TAB2
);
853 nFlags
|= (nFlags2
<< 4);
858 @param pRange pointer to range where rAddr effectively is *pRange->aEnd,
859 used in conjunction with pExtInfo to determine the tab span
863 lcl_ScAddress_Parse_OOo( const sal_Unicode
* p
, ScDocument
* pDoc
, ScAddress
& rAddr
,
864 ScAddress::ExternalInfo
* pExtInfo
= NULL
, ScRange
* pRange
= NULL
)
867 String aDocName
; // der pure Dokumentenname
869 bool bExtDoc
= false;
870 bool bExtDocInherited
= false;
871 const ScAddress
aCurPos(rAddr
);
873 // Lets see if this is a reference to something in an external file. A
874 // document name is always quoted and has a trailing #.
877 const sal_Unicode
* pStart
= p
;
878 p
= lcl_ParseQuotedName(p
, aDocName
);
879 if (*p
++ == SC_COMPILER_FILE_TAB_SEP
)
882 // This is not a document name. Perhaps a quoted relative table
886 else if (pExtInfo
&& pExtInfo
->mbExternal
)
888 // This is an external reference.
889 bExtDoc
= bExtDocInherited
= true;
895 USHORT nBits
= SCA_VALID_TAB
;
896 const sal_Unicode
* q
;
897 if ( ScGlobal::FindUnquoted( p
, '.') )
901 nRes
|= SCA_TAB_ABSOLUTE
;
903 nRes
|= SCA_TAB_ABSOLUTE
, p
++;
907 // Tokens that start at ' can have anything in them until a final
908 // ' but '' marks an escaped '. We've earlier guaranteed that a
909 // string containing '' will be surrounded by '.
910 p
= lcl_ParseQuotedName(p
, aTab
);
929 if (!bExtDoc
&& (!pDoc
|| !pDoc
->GetTable( aTab
, nTab
)))
934 if (bExtDoc
&& !bExtDocInherited
)
935 return nRes
; // After a document a sheet must follow.
943 nBits
= SCA_VALID_COL
;
945 nBits
|= SCA_COL_ABSOLUTE
, p
++;
947 if (CharClass::isAsciiAlpha( *p
))
949 nCol
= sal::static_int_cast
<SCCOL
>( toupper( char(*p
++) ) - 'A' );
950 while (nCol
< MAXCOL
&& CharClass::isAsciiAlpha(*p
))
951 nCol
= sal::static_int_cast
<SCCOL
>( ((nCol
+ 1) * 26) + toupper( char(*p
++) ) - 'A' );
956 if( nCol
> MAXCOL
|| CharClass::isAsciiAlpha( *p
) )
966 nBits
= SCA_VALID_ROW
;
968 nBits
|= SCA_ROW_ABSOLUTE
, p
++;
969 if( !CharClass::isAsciiDigit( *p
) )
977 long n
= aTmp
.ToInt32() - 1;
978 while (CharClass::isAsciiDigit( *p
))
980 if( n
< 0 || n
> MAXROW
)
982 nRow
= static_cast<SCROW
>(n
);
989 rAddr
.Set( nCol
, nRow
, nTab
);
997 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
999 // Need document name if inherited.
1000 if (bExtDocInherited
)
1002 const String
* pFileName
= pRefMgr
->getExternalFileName( pExtInfo
->mnFileId
);
1004 aDocName
= *pFileName
;
1008 pRefMgr
->convertToAbsName(aDocName
);
1010 if ((!pExtInfo
|| !pExtInfo
->mbExternal
) && pRefMgr
->isOwnDocument(aDocName
))
1012 if (!pDoc
->GetTable( aTab
, nTab
))
1016 rAddr
.SetTab( nTab
);
1017 nRes
|= SCA_VALID_TAB
;
1026 if (!pExtInfo
->mbExternal
)
1028 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(aDocName
);
1030 pExtInfo
->mbExternal
= true;
1031 pExtInfo
->maTabName
= aTab
;
1032 pExtInfo
->mnFileId
= nFileId
;
1034 if (pRefMgr
->getSingleRefToken(nFileId
, aTab
,
1035 ScAddress(nCol
, nRow
, 0), NULL
,
1038 rAddr
.SetTab( nTab
);
1039 nRes
|= SCA_VALID_TAB
;
1046 // This is a call for the second part of the reference,
1047 // we must have the range to adapt tab span.
1052 USHORT nFlags
= nRes
| SCA_VALID_TAB2
;
1053 if (!lcl_ScRange_External_TabSpan( *pRange
, nFlags
,
1055 pExtInfo
->maTabName
, aTab
, pDoc
))
1056 nRes
&= ~SCA_VALID_TAB
;
1059 if (nFlags
& SCA_VALID_TAB2
)
1061 rAddr
.SetTab( pRange
->aEnd
.Tab());
1062 nRes
|= SCA_VALID_TAB
;
1065 nRes
&= ~SCA_VALID_TAB
;
1074 if ( !(nRes
& SCA_VALID_ROW
) && (nRes
& SCA_VALID_COL
)
1075 && !( (nRes
& SCA_TAB_3D
) && (nRes
& SCA_VALID_TAB
)) )
1076 { // no Row, no Tab, but Col => DM (...), B (...) et al
1081 USHORT nMask
= nRes
& ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
);
1082 if( nMask
== ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
) )
1091 lcl_ScAddress_Parse ( const sal_Unicode
* p
, ScDocument
* pDoc
, ScAddress
& rAddr
,
1092 const ScAddress::Details
& rDetails
,
1093 ScAddress::ExternalInfo
* pExtInfo
= NULL
,
1094 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
= NULL
)
1099 switch (rDetails
.eConv
)
1102 case formula::FormulaGrammar::CONV_OOO
:
1104 return lcl_ScAddress_Parse_OOo( p
, pDoc
, rAddr
, pExtInfo
, NULL
);
1107 case formula::FormulaGrammar::CONV_XL_A1
:
1108 case formula::FormulaGrammar::CONV_XL_OOX
:
1111 USHORT nFlags
= lcl_ScRange_Parse_XL_A1( r
, p
, pDoc
, true, pExtInfo
,
1112 (rDetails
.eConv
== formula::FormulaGrammar::CONV_XL_OOX
? pExternalLinks
: NULL
) );
1116 case formula::FormulaGrammar::CONV_XL_R1C1
:
1119 USHORT nFlags
= lcl_ScRange_Parse_XL_R1C1( r
, p
, pDoc
, rDetails
, true, pExtInfo
);
1127 bool ConvertSingleRef( ScDocument
* pDoc
, const String
& rRefString
,
1128 SCTAB nDefTab
, ScRefAddress
& rRefAddress
,
1129 const ScAddress::Details
& rDetails
,
1130 ScAddress::ExternalInfo
* pExtInfo
/* = NULL */ )
1133 if (pExtInfo
|| (ScGlobal::FindUnquoted( rRefString
, SC_COMPILER_FILE_TAB_SEP
) == STRING_NOTFOUND
))
1135 ScAddress
aAddr( 0, 0, nDefTab
);
1136 USHORT nRes
= aAddr
.Parse( rRefString
, pDoc
, rDetails
, pExtInfo
);
1137 if ( nRes
& SCA_VALID
)
1139 rRefAddress
.Set( aAddr
,
1140 ((nRes
& SCA_COL_ABSOLUTE
) == 0),
1141 ((nRes
& SCA_ROW_ABSOLUTE
) == 0),
1142 ((nRes
& SCA_TAB_ABSOLUTE
) == 0));
1150 bool ConvertDoubleRef( ScDocument
* pDoc
, const String
& rRefString
, SCTAB nDefTab
,
1151 ScRefAddress
& rStartRefAddress
, ScRefAddress
& rEndRefAddress
,
1152 const ScAddress::Details
& rDetails
,
1153 ScAddress::ExternalInfo
* pExtInfo
/* = NULL */ )
1156 if (pExtInfo
|| (ScGlobal::FindUnquoted( rRefString
, SC_COMPILER_FILE_TAB_SEP
) == STRING_NOTFOUND
))
1158 ScRange
aRange( ScAddress( 0, 0, nDefTab
));
1159 USHORT nRes
= aRange
.Parse( rRefString
, pDoc
, rDetails
, pExtInfo
);
1160 if ( nRes
& SCA_VALID
)
1162 rStartRefAddress
.Set( aRange
.aStart
,
1163 ((nRes
& SCA_COL_ABSOLUTE
) == 0),
1164 ((nRes
& SCA_ROW_ABSOLUTE
) == 0),
1165 ((nRes
& SCA_TAB_ABSOLUTE
) == 0));
1166 rEndRefAddress
.Set( aRange
.aEnd
,
1167 ((nRes
& SCA_COL2_ABSOLUTE
) == 0),
1168 ((nRes
& SCA_ROW2_ABSOLUTE
) == 0),
1169 ((nRes
& SCA_TAB2_ABSOLUTE
) == 0));
1177 USHORT
ScAddress::Parse( const String
& r
, ScDocument
* pDoc
,
1178 const Details
& rDetails
,
1179 ExternalInfo
* pExtInfo
,
1180 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
1182 return lcl_ScAddress_Parse( r
.GetBuffer(), pDoc
, *this, rDetails
, pExtInfo
, pExternalLinks
);
1186 bool ScRange::Intersects( const ScRange
& r
) const
1189 Min( aEnd
.Col(), r
.aEnd
.Col() ) < Max( aStart
.Col(), r
.aStart
.Col() )
1190 || Min( aEnd
.Row(), r
.aEnd
.Row() ) < Max( aStart
.Row(), r
.aStart
.Row() )
1191 || Min( aEnd
.Tab(), r
.aEnd
.Tab() ) < Max( aStart
.Tab(), r
.aStart
.Tab() )
1196 void ScRange::Justify()
1199 if ( aEnd
.Col() < (nTempCol
= aStart
.Col()) )
1201 aStart
.SetCol(aEnd
.Col()); aEnd
.SetCol(nTempCol
);
1204 if ( aEnd
.Row() < (nTempRow
= aStart
.Row()) )
1206 aStart
.SetRow(aEnd
.Row()); aEnd
.SetRow(nTempRow
);
1209 if ( aEnd
.Tab() < (nTempTab
= aStart
.Tab()) )
1211 aStart
.SetTab(aEnd
.Tab()); aEnd
.SetTab(nTempTab
);
1215 void ScRange::ExtendTo( const ScRange
& rRange
)
1217 DBG_ASSERT( rRange
.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" );
1220 aStart
.SetCol( ::std::min( aStart
.Col(), rRange
.aStart
.Col() ) );
1221 aStart
.SetRow( ::std::min( aStart
.Row(), rRange
.aStart
.Row() ) );
1222 aStart
.SetTab( ::std::min( aStart
.Tab(), rRange
.aStart
.Tab() ) );
1223 aEnd
.SetCol( ::std::max( aEnd
.Col(), rRange
.aEnd
.Col() ) );
1224 aEnd
.SetRow( ::std::max( aEnd
.Row(), rRange
.aEnd
.Row() ) );
1225 aEnd
.SetTab( ::std::max( aEnd
.Tab(), rRange
.aEnd
.Tab() ) );
1232 lcl_ScRange_Parse_OOo( ScRange
&aRange
, const String
& r
, ScDocument
* pDoc
, ScAddress::ExternalInfo
* pExtInfo
= NULL
)
1234 USHORT nRes1
= 0, nRes2
= 0;
1235 xub_StrLen nPos
= ScGlobal::FindUnquoted( r
, ':');
1236 if (nPos
!= STRING_NOTFOUND
)
1239 sal_Unicode
* p
= aTmp
.GetBufferAccess();
1241 if( (nRes1
= lcl_ScAddress_Parse_OOo( p
, pDoc
, aRange
.aStart
, pExtInfo
, NULL
) ) != 0 )
1243 aRange
.aEnd
= aRange
.aStart
; // sheet must be initialized identical to first sheet
1244 if ( (nRes2
= lcl_ScAddress_Parse_OOo( p
+ nPos
+ 1, pDoc
, aRange
.aEnd
, pExtInfo
, &aRange
) ) != 0 )
1246 // PutInOrder / Justify
1247 USHORT nMask
, nBits1
, nBits2
;
1249 if ( aRange
.aEnd
.Col() < (nTempCol
= aRange
.aStart
.Col()) )
1251 aRange
.aStart
.SetCol(aRange
.aEnd
.Col()); aRange
.aEnd
.SetCol(nTempCol
);
1252 nMask
= (SCA_VALID_COL
| SCA_COL_ABSOLUTE
);
1253 nBits1
= nRes1
& nMask
;
1254 nBits2
= nRes2
& nMask
;
1255 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1256 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1259 if ( aRange
.aEnd
.Row() < (nTempRow
= aRange
.aStart
.Row()) )
1261 aRange
.aStart
.SetRow(aRange
.aEnd
.Row()); aRange
.aEnd
.SetRow(nTempRow
);
1262 nMask
= (SCA_VALID_ROW
| SCA_ROW_ABSOLUTE
);
1263 nBits1
= nRes1
& nMask
;
1264 nBits2
= nRes2
& nMask
;
1265 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1266 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1269 if ( aRange
.aEnd
.Tab() < (nTempTab
= aRange
.aStart
.Tab()) )
1271 aRange
.aStart
.SetTab(aRange
.aEnd
.Tab()); aRange
.aEnd
.SetTab(nTempTab
);
1272 nMask
= (SCA_VALID_TAB
| SCA_TAB_ABSOLUTE
| SCA_TAB_3D
);
1273 nBits1
= nRes1
& nMask
;
1274 nBits2
= nRes2
& nMask
;
1275 nRes1
= (nRes1
& ~nMask
) | nBits2
;
1276 nRes2
= (nRes2
& ~nMask
) | nBits1
;
1278 if ( ((nRes1
& ( SCA_TAB_ABSOLUTE
| SCA_TAB_3D
))
1279 == ( SCA_TAB_ABSOLUTE
| SCA_TAB_3D
))
1280 && !(nRes2
& SCA_TAB_3D
) )
1281 nRes2
|= SCA_TAB_ABSOLUTE
;
1284 nRes1
= 0; // #38840# keine Tokens aus halben Sachen
1287 nRes1
= ( ( nRes1
| nRes2
) & SCA_VALID
)
1289 | ( ( nRes2
& SCA_BITS
) << 4 );
1293 USHORT
ScRange::Parse( const String
& r
, ScDocument
* pDoc
,
1294 const ScAddress::Details
& rDetails
,
1295 ScAddress::ExternalInfo
* pExtInfo
,
1296 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
)
1301 switch (rDetails
.eConv
)
1304 case formula::FormulaGrammar::CONV_OOO
:
1305 return lcl_ScRange_Parse_OOo( *this, r
, pDoc
, pExtInfo
);
1307 case formula::FormulaGrammar::CONV_XL_A1
:
1308 case formula::FormulaGrammar::CONV_XL_OOX
:
1309 return lcl_ScRange_Parse_XL_A1( *this, r
.GetBuffer(), pDoc
, false, pExtInfo
,
1310 (rDetails
.eConv
== formula::FormulaGrammar::CONV_XL_OOX
? pExternalLinks
: NULL
) );
1312 case formula::FormulaGrammar::CONV_XL_R1C1
:
1313 return lcl_ScRange_Parse_XL_R1C1( *this, r
.GetBuffer(), pDoc
, rDetails
, false, pExtInfo
);
1318 // Accept a full range, or an address
1319 USHORT
ScRange::ParseAny( const String
& r
, ScDocument
* pDoc
,
1320 const ScAddress::Details
& rDetails
)
1322 USHORT nRet
= Parse( r
, pDoc
, rDetails
);
1323 const USHORT nValid
= SCA_VALID
| SCA_VALID_COL2
| SCA_VALID_ROW2
|
1326 if ( (nRet
& nValid
) != nValid
)
1329 nRet
= aAdr
.Parse( r
, pDoc
, rDetails
);
1330 if ( nRet
& SCA_VALID
)
1331 aStart
= aEnd
= aAdr
;
1336 // Parse only full row references
1337 USHORT
ScRange::ParseCols( const String
& rStr
, ScDocument
* pDoc
,
1338 const ScAddress::Details
& rDetails
)
1340 const sal_Unicode
* p
= rStr
.GetBuffer();
1341 USHORT nRes
= 0, ignored
= 0;
1346 pDoc
= NULL
; // make compiler shutup we may need this later
1348 switch (rDetails
.eConv
)
1351 case formula::FormulaGrammar::CONV_OOO
: // No full col refs in OOO yet, assume XL notation
1352 case formula::FormulaGrammar::CONV_XL_A1
:
1353 case formula::FormulaGrammar::CONV_XL_OOX
:
1354 if (NULL
!= (p
= lcl_a1_get_col( p
, &aStart
, &ignored
) ) )
1358 if( NULL
!= (p
= lcl_a1_get_col( p
+1, &aEnd
, &ignored
)))
1360 nRes
= SCA_VALID_COL
;
1366 nRes
= SCA_VALID_COL
;
1371 case formula::FormulaGrammar::CONV_XL_R1C1
:
1372 if ((p
[0] == 'C' || p
[0] != 'c') &&
1373 NULL
!= (p
= lcl_r1c1_get_col( p
, rDetails
, &aStart
, &ignored
)))
1377 if( (p
[1] == 'C' || p
[1] == 'c') &&
1378 NULL
!= (p
= lcl_r1c1_get_col( p
+1, rDetails
, &aEnd
, &ignored
)))
1380 nRes
= SCA_VALID_COL
;
1386 nRes
= SCA_VALID_COL
;
1392 return (p
!= NULL
&& *p
== '\0') ? nRes
: 0;
1395 // Parse only full row references
1396 USHORT
ScRange::ParseRows( const String
& rStr
, ScDocument
* pDoc
,
1397 const ScAddress::Details
& rDetails
)
1399 const sal_Unicode
* p
= rStr
.GetBuffer();
1400 USHORT nRes
= 0, ignored
= 0;
1405 pDoc
= NULL
; // make compiler shutup we may need this later
1407 switch (rDetails
.eConv
)
1410 case formula::FormulaGrammar::CONV_OOO
: // No full row refs in OOO yet, assume XL notation
1411 case formula::FormulaGrammar::CONV_XL_A1
:
1412 case formula::FormulaGrammar::CONV_XL_OOX
:
1413 if (NULL
!= (p
= lcl_a1_get_row( p
, &aStart
, &ignored
) ) )
1417 if( NULL
!= (p
= lcl_a1_get_row( p
+1, &aEnd
, &ignored
)))
1419 nRes
= SCA_VALID_COL
;
1425 nRes
= SCA_VALID_COL
;
1430 case formula::FormulaGrammar::CONV_XL_R1C1
:
1431 if ((p
[0] == 'R' || p
[0] != 'r') &&
1432 NULL
!= (p
= lcl_r1c1_get_row( p
, rDetails
, &aStart
, &ignored
)))
1436 if( (p
[1] == 'R' || p
[1] == 'r') &&
1437 NULL
!= (p
= lcl_r1c1_get_row( p
+1, rDetails
, &aEnd
, &ignored
)))
1439 nRes
= SCA_VALID_COL
;
1445 nRes
= SCA_VALID_COL
;
1451 return (p
!= NULL
&& *p
== '\0') ? nRes
: 0;
1455 lcl_a1_append_c ( String
&r
, int nCol
, bool bIsAbs
)
1459 ScColToAlpha( r
, sal::static_int_cast
<SCCOL
>(nCol
) );
1463 lcl_a1_append_r ( String
&r
, int nRow
, bool bIsAbs
)
1467 r
+= String::CreateFromInt32( nRow
+1 );
1471 lcl_r1c1_append_c ( String
&r
, int nCol
, bool bIsAbs
,
1472 const ScAddress::Details
& rDetails
)
1477 r
+= String::CreateFromInt32( nCol
+ 1 );
1481 nCol
-= rDetails
.nCol
;
1484 r
+= String::CreateFromInt32( nCol
);
1490 lcl_r1c1_append_r ( String
&r
, int nRow
, bool bIsAbs
,
1491 const ScAddress::Details
& rDetails
)
1496 r
+= String::CreateFromInt32( nRow
+ 1 );
1500 nRow
-= rDetails
.nRow
;
1503 r
+= String::CreateFromInt32( nRow
);
1510 getFileNameFromDoc( const ScDocument
* pDoc
)
1512 // TODO : er points at ScGlobal::GetAbsDocName()
1513 // as a better template. Look into it
1515 SfxObjectShell
* pShell
;
1518 NULL
!= (pShell
= pDoc
->GetDocumentShell() ) )
1520 uno::Reference
< frame::XModel
> xModel( pShell
->GetModel(), uno::UNO_QUERY
);
1523 if( xModel
->getURL().getLength() )
1525 INetURLObject
aURL( xModel
->getURL() );
1526 sFileName
= aURL
.GetLastName();
1529 sFileName
= pShell
->GetTitle();
1534 ByteString
aStr( sFileName
, RTL_TEXTENCODING_UTF8
);
1535 aStr
.Append(static_cast< char >(0));
1536 std::cerr
<< "docname \'" << aStr
.GetBuffer() << '\'' << std::endl
;
1542 void ScAddress::Format( String
& r
, USHORT nFlags
, ScDocument
* pDoc
,
1543 const Details
& rDetails
) const
1546 if( nFlags
& SCA_VALID
)
1547 nFlags
|= ( SCA_VALID_ROW
| SCA_VALID_COL
| SCA_VALID_TAB
);
1548 if( pDoc
&& (nFlags
& SCA_VALID_TAB
) )
1550 if ( nTab
>= pDoc
->GetTableCount() )
1552 r
= ScGlobal::GetRscString( STR_NOREF_STR
);
1555 // if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) )
1556 if( nFlags
& SCA_TAB_3D
)
1558 String aTabName
, aDocName
;
1559 pDoc
->GetName( nTab
, aTabName
);
1560 // External Reference, same as in ScCompiler::MakeTabStr()
1561 if( aTabName
.GetChar(0) == '\'' )
1563 xub_StrLen nPos
= ScGlobal::FindUnquoted( aTabName
, SC_COMPILER_FILE_TAB_SEP
);
1564 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && aTabName
.GetChar(nPos
-1) == '\'')
1566 aDocName
= aTabName
.Copy( 0, nPos
+ 1 );
1567 aTabName
.Erase( 0, nPos
+ 1 );
1570 else if( nFlags
& SCA_FORCE_DOC
)
1572 // VBA has an 'external' flag that forces the addition of the
1573 // tab name _and_ the doc name. The VBA code would be
1574 // needlessly complicated if it constructed an actual external
1575 // reference so we add this somewhat cheesy kludge to force the
1576 // addition of the document name even for non-external references
1577 aDocName
= getFileNameFromDoc( pDoc
);
1579 ScCompiler::CheckTabQuotes( aTabName
, rDetails
.eConv
);
1581 switch( rDetails
.eConv
)
1584 case formula::FormulaGrammar::CONV_OOO
:
1586 if( nFlags
& SCA_TAB_ABSOLUTE
)
1592 case formula::FormulaGrammar::CONV_XL_A1
:
1593 case formula::FormulaGrammar::CONV_XL_R1C1
:
1594 case formula::FormulaGrammar::CONV_XL_OOX
:
1595 if (aDocName
.Len() > 0)
1607 switch( rDetails
.eConv
)
1610 case formula::FormulaGrammar::CONV_OOO
:
1611 case formula::FormulaGrammar::CONV_XL_A1
:
1612 case formula::FormulaGrammar::CONV_XL_OOX
:
1613 if( nFlags
& SCA_VALID_COL
)
1614 lcl_a1_append_c ( r
, nCol
, nFlags
& SCA_COL_ABSOLUTE
);
1615 if( nFlags
& SCA_VALID_ROW
)
1616 lcl_a1_append_r ( r
, nRow
, nFlags
& SCA_ROW_ABSOLUTE
);
1619 case formula::FormulaGrammar::CONV_XL_R1C1
:
1620 if( nFlags
& SCA_VALID_ROW
)
1621 lcl_r1c1_append_r ( r
, nRow
, nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1622 if( nFlags
& SCA_VALID_COL
)
1623 lcl_r1c1_append_c ( r
, nCol
, nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1629 lcl_Split_DocTab( const ScDocument
* pDoc
, SCTAB nTab
,
1630 const ScAddress::Details
& rDetails
,
1632 String
& rTabName
, String
& rDocName
)
1634 pDoc
->GetName( nTab
, rTabName
);
1638 ByteString
aStr(rTabName
, RTL_TEXTENCODING_UTF8
);
1639 aStr
.Append(static_cast< char >(0));
1640 std::cerr
<< "tabname \'" << aStr
.GetBuffer() << '\'' << std::endl
;
1643 // External reference, same as in ScCompiler::MakeTabStr()
1644 if ( rTabName
.GetChar(0) == '\'' )
1646 xub_StrLen nPos
= ScGlobal::FindUnquoted( rTabName
, SC_COMPILER_FILE_TAB_SEP
);
1647 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && rTabName
.GetChar(nPos
-1) == '\'')
1649 rDocName
= rTabName
.Copy( 0, nPos
+ 1 );
1650 rTabName
.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 rDocName
= getFileNameFromDoc( pDoc
);
1662 ScCompiler::CheckTabQuotes( rTabName
, rDetails
.eConv
);
1666 lcl_ScRange_Format_XL_Header( String
& r
, const ScRange
& rRange
,
1667 USHORT nFlags
, ScDocument
* pDoc
,
1668 const ScAddress::Details
& rDetails
)
1670 if( nFlags
& SCA_TAB_3D
)
1672 String aTabName
, aDocName
;
1673 lcl_Split_DocTab( pDoc
, rRange
.aStart
.Tab(), rDetails
, nFlags
,
1674 aTabName
, aDocName
);
1675 if( aDocName
.Len() > 0 )
1683 if( nFlags
& SCA_TAB2_3D
)
1685 lcl_Split_DocTab( pDoc
, rRange
.aEnd
.Tab(), rDetails
, nFlags
,
1686 aTabName
, aDocName
);
1694 void ScRange::Format( String
& r
, USHORT nFlags
, ScDocument
* pDoc
,
1695 const ScAddress::Details
& rDetails
) const
1698 if( !( nFlags
& SCA_VALID
) )
1700 r
= ScGlobal::GetRscString( STR_NOREF_STR
);
1704 #define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask)))
1705 switch( rDetails
.eConv
) {
1707 case formula::FormulaGrammar::CONV_OOO
: {
1708 BOOL bOneTab
= (aStart
.Tab() == aEnd
.Tab());
1710 nFlags
|= SCA_TAB_3D
;
1711 aStart
.Format( r
, nFlags
, pDoc
, rDetails
);
1712 if( aStart
!= aEnd
||
1713 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1714 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
))
1717 nFlags
= ( nFlags
& SCA_VALID
) | ( ( nFlags
>> 4 ) & 0x070F );
1721 nFlags
|= SCA_TAB_3D
;
1722 aEnd
.Format( aName
, nFlags
, pDoc
, rDetails
);
1729 case formula::FormulaGrammar::CONV_XL_A1
:
1730 case formula::FormulaGrammar::CONV_XL_OOX
:
1731 lcl_ScRange_Format_XL_Header( r
, *this, nFlags
, pDoc
, rDetails
);
1732 if( aStart
.Col() == 0 && aEnd
.Col() >= MAXCOL
)
1734 // Full col refs always require 2 rows (2:2)
1735 lcl_a1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
);
1737 lcl_a1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
);
1739 else if( aStart
.Row() == 0 && aEnd
.Row() >= MAXROW
)
1741 // Full row refs always require 2 cols (A:A)
1742 lcl_a1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
);
1744 lcl_a1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
);
1748 lcl_a1_append_c ( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
);
1749 lcl_a1_append_r ( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
);
1750 if( aStart
.Col() != aEnd
.Col() ||
1751 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1752 aStart
.Row() != aEnd
.Row() ||
1753 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1755 lcl_a1_append_c ( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
);
1756 lcl_a1_append_r ( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
);
1761 case formula::FormulaGrammar::CONV_XL_R1C1
:
1762 lcl_ScRange_Format_XL_Header( r
, *this, nFlags
, pDoc
, rDetails
);
1763 if( aStart
.Col() == 0 && aEnd
.Col() >= MAXCOL
)
1765 lcl_r1c1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1766 if( aStart
.Row() != aEnd
.Row() ||
1767 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1769 lcl_r1c1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
, rDetails
);
1772 else if( aStart
.Row() == 0 && aEnd
.Row() >= MAXROW
)
1774 lcl_r1c1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1775 if( aStart
.Col() != aEnd
.Col() ||
1776 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
)) {
1778 lcl_r1c1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
, rDetails
);
1783 lcl_r1c1_append_r( r
, aStart
.Row(), nFlags
& SCA_ROW_ABSOLUTE
, rDetails
);
1784 lcl_r1c1_append_c( r
, aStart
.Col(), nFlags
& SCA_COL_ABSOLUTE
, rDetails
);
1785 if( aStart
.Col() != aEnd
.Col() ||
1786 absrel_differ( nFlags
, SCA_COL_ABSOLUTE
) ||
1787 aStart
.Row() != aEnd
.Row() ||
1788 absrel_differ( nFlags
, SCA_ROW_ABSOLUTE
)) {
1790 lcl_r1c1_append_r( r
, aEnd
.Row(), nFlags
& SCA_ROW2_ABSOLUTE
, rDetails
);
1791 lcl_r1c1_append_c( r
, aEnd
.Col(), nFlags
& SCA_COL2_ABSOLUTE
, rDetails
);
1795 #undef absrel_differ
1798 bool ScAddress::Move( SCsCOL dx
, SCsROW dy
, SCsTAB dz
, ScDocument
* pDoc
)
1800 SCsTAB nMaxTab
= pDoc
? pDoc
->GetTableCount() : MAXTAB
+1;
1806 dx
= 0, bValid
= FALSE
;
1807 else if( dx
> MAXCOL
)
1808 dx
= MAXCOL
, bValid
=FALSE
;
1810 dy
= 0, bValid
= FALSE
;
1811 else if( dy
> MAXROW
)
1812 dy
= MAXROW
, bValid
=FALSE
;
1814 dz
= 0, bValid
= FALSE
;
1815 else if( dz
>= nMaxTab
)
1816 dz
= nMaxTab
-1, bValid
=FALSE
;
1822 bool ScRange::Move( SCsCOL dx
, SCsROW dy
, SCsTAB dz
, ScDocument
* pDoc
)
1824 // Einfahces &, damit beides ausgefuehrt wird!!
1825 return aStart
.Move( dx
, dy
, dz
, pDoc
) & aEnd
.Move( dx
, dy
, dz
, pDoc
);
1829 String
ScAddress::GetColRowString( bool bAbsolute
,
1830 const Details
& rDetails
) const
1834 switch( rDetails
.eConv
)
1837 case formula::FormulaGrammar::CONV_OOO
:
1838 case formula::FormulaGrammar::CONV_XL_A1
:
1839 case formula::FormulaGrammar::CONV_XL_OOX
:
1841 aString
.Append( '$' );
1843 ScColToAlpha( aString
, nCol
);
1846 aString
.Append( '$' );
1848 aString
+= String::CreateFromInt32(nRow
+1);
1851 case formula::FormulaGrammar::CONV_XL_R1C1
:
1852 lcl_r1c1_append_r ( aString
, nRow
, bAbsolute
, rDetails
);
1853 lcl_r1c1_append_c ( aString
, nCol
, bAbsolute
, rDetails
);
1861 String
ScRefAddress::GetRefString( ScDocument
* pDoc
, SCTAB nActTab
,
1862 const ScAddress::Details
& rDetails
) const
1865 return EMPTY_STRING
;
1866 if ( Tab()+1 > pDoc
->GetTableCount() )
1867 return ScGlobal::GetRscString( STR_NOREF_STR
);
1870 USHORT nFlags
= SCA_VALID
;
1871 if ( nActTab
!= Tab() )
1873 nFlags
|= SCA_TAB_3D
;
1875 nFlags
|= SCA_TAB_ABSOLUTE
;
1878 nFlags
|= SCA_COL_ABSOLUTE
;
1880 nFlags
|= SCA_ROW_ABSOLUTE
;
1882 aAdr
.Format( aString
, nFlags
, pDoc
, rDetails
);
1887 //------------------------------------------------------------------------
1889 void ScColToAlpha( rtl::OUStringBuffer
& rBuf
, SCCOL nCol
)
1894 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1895 static_cast<sal_uInt16
>(nCol
)));
1898 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1899 (static_cast<sal_uInt16
>(nCol
) / 26) - 1));
1900 rBuf
.append( static_cast<sal_Unicode
>( 'A' +
1901 (static_cast<sal_uInt16
>(nCol
) % 26)));
1909 SCCOL nC
= nCol
% 26;
1910 aStr
+= static_cast<sal_Unicode
>( 'A' +
1911 static_cast<sal_uInt16
>(nC
));
1912 nCol
= sal::static_int_cast
<SCCOL
>( nCol
- nC
);
1913 nCol
= nCol
/ 26 - 1;
1915 aStr
+= static_cast<sal_Unicode
>( 'A' +
1916 static_cast<sal_uInt16
>(nCol
));
1923 bool AlphaToCol( SCCOL
& rCol
, const String
& rStr
)
1926 xub_StrLen nStop
= rStr
.Len();
1927 xub_StrLen nPos
= 0;
1929 while (nResult
<= MAXCOL
&& nPos
< nStop
&& (c
= rStr
.GetChar( nPos
)) != 0 &&
1930 CharClass::isAsciiAlpha(c
))
1933 nResult
= (nResult
+ 1) * 26;
1934 nResult
+= ScGlobal::ToUpperAlpha(c
) - 'A';
1937 bool bOk
= (ValidCol(nResult
) && nPos
> 0);