1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <osl/diagnose.h>
22 #include <unotools/charclass.hxx>
23 #include <rangeutl.hxx>
24 #include <document.hxx>
27 #include <rangenam.hxx>
28 #include <convuno.hxx>
29 #include <externalrefmgr.hxx>
30 #include <compiler.hxx>
31 #include <refupdatecontext.hxx>
33 using ::formula::FormulaGrammar
;
34 using namespace ::com::sun::star
;
36 bool ScRangeUtil::MakeArea( const OUString
& rAreaStr
,
38 const ScDocument
& rDoc
,
40 ScAddress::Details
const & rDetails
)
42 // Input in rAreaStr: "$Tabelle1.$A1:$D17"
44 // BROKEN BROKEN BROKEN
45 // but it is only used in the consolidate dialog. Ignore for now.
47 bool bSuccess
= false;
48 sal_Int32 nPointPos
= rAreaStr
.indexOf('.');
49 sal_Int32 nColonPos
= rAreaStr
.indexOf(':');
50 OUString
aStrArea( rAreaStr
);
51 ScRefAddress startPos
;
54 if ( nColonPos
== -1 && nPointPos
!= -1 )
56 aStrArea
+= OUString::Concat(":") + rAreaStr
.subView( nPointPos
+1 ); // do not include '.' in copy
59 bSuccess
= ConvertDoubleRef( rDoc
, aStrArea
, nTab
, startPos
, endPos
, rDetails
);
62 rArea
= ScArea( startPos
.Tab(),
63 startPos
.Col(), startPos
.Row(),
64 endPos
.Col(), endPos
.Row() );
69 void ScRangeUtil::CutPosString( const OUString
& theAreaStr
,
73 // BROKEN BROKEN BROKEN
74 // but it is only used in the consolidate dialog. Ignore for now.
76 sal_Int32 nColonPos
= theAreaStr
.indexOf(':');
78 if ( nColonPos
!= -1 )
79 aPosStr
= theAreaStr
.copy( 0, nColonPos
); // do not include ':' in copy
86 bool ScRangeUtil::IsAbsTabArea( const OUString
& rAreaStr
,
87 const ScDocument
* pDoc
,
88 std::unique_ptr
<ScArea
[]>* ppAreas
,
89 sal_uInt16
* pAreaCount
,
90 bool /* bAcceptCellRef */,
91 ScAddress::Details
const & rDetails
)
93 OSL_ENSURE( pDoc
, "No document given!" );
97 // BROKEN BROKEN BROKEN
98 // but it is only used in the consolidate dialog. Ignore for now.
101 * Expects strings like:
102 * "$Tabelle1.$A$1:$Tabelle3.$D$17"
103 * If bAcceptCellRef == sal_True then also accept strings like:
106 * as result a ScArea-Array is created,
107 * which is published via ppAreas and also has to be deleted this route.
111 OUString
aTempAreaStr(rAreaStr
);
113 if ( -1 == aTempAreaStr
.indexOf(':') )
115 aTempAreaStr
+= ":" + rAreaStr
;
118 sal_Int32 nColonPos
= aTempAreaStr
.indexOf(':');
121 && -1 != aTempAreaStr
.indexOf('.') )
123 ScRefAddress aStartPos
;
125 OUString aStartPosStr
= aTempAreaStr
.copy( 0, nColonPos
);
126 OUString aEndPosStr
= aTempAreaStr
.copy( nColonPos
+1 );
128 if ( ConvertSingleRef( *pDoc
, aStartPosStr
, 0, aStartPos
, rDetails
) )
130 ScRefAddress aEndPos
;
131 if ( ConvertSingleRef( *pDoc
, aEndPosStr
, aStartPos
.Tab(), aEndPos
, rDetails
) )
133 aStartPos
.SetRelCol( false );
134 aStartPos
.SetRelRow( false );
135 aStartPos
.SetRelTab( false );
136 aEndPos
.SetRelCol( false );
137 aEndPos
.SetRelRow( false );
138 aEndPos
.SetRelTab( false );
142 if ( ppAreas
&& pAreaCount
) // Array returned ?
144 SCTAB nStartTab
= aStartPos
.Tab();
145 SCTAB nEndTab
= aEndPos
.Tab();
146 sal_uInt16 nTabCount
= static_cast<sal_uInt16
>(nEndTab
-nStartTab
+1);
147 ppAreas
->reset(new ScArea
[nTabCount
]);
150 ScArea
theArea( 0, aStartPos
.Col(), aStartPos
.Row(),
151 aEndPos
.Col(), aEndPos
.Row() );
154 for ( i
=0; i
<nTabCount
; i
++ )
156 (*ppAreas
)[i
] = theArea
;
157 (*ppAreas
)[i
].nTab
= nTab
;
160 *pAreaCount
= nTabCount
;
169 bool ScRangeUtil::IsAbsArea( const OUString
& rAreaStr
,
170 const ScDocument
& rDoc
,
172 OUString
* pCompleteStr
,
173 ScRefAddress
* pStartPos
,
174 ScRefAddress
* pEndPos
,
175 ScAddress::Details
const & rDetails
)
177 ScRefAddress startPos
;
180 bool bIsAbsArea
= ConvertDoubleRef( rDoc
, rAreaStr
, nTab
, startPos
, endPos
, rDetails
);
184 startPos
.SetRelCol( false );
185 startPos
.SetRelRow( false );
186 startPos
.SetRelTab( false );
187 endPos
.SetRelCol( false );
188 endPos
.SetRelRow( false );
189 endPos
.SetRelTab( false );
193 *pCompleteStr
= startPos
.GetRefString( rDoc
, MAXTAB
+1, rDetails
);
194 *pCompleteStr
+= ":";
195 *pCompleteStr
+= endPos
.GetRefString( rDoc
, nTab
, rDetails
);
198 if ( pStartPos
&& pEndPos
)
200 *pStartPos
= startPos
;
208 bool ScRangeUtil::IsAbsPos( const OUString
& rPosStr
,
209 const ScDocument
& rDoc
,
211 OUString
* pCompleteStr
,
212 ScRefAddress
* pPosTripel
,
213 ScAddress::Details
const & rDetails
)
217 bool bIsAbsPos
= ConvertSingleRef( rDoc
, rPosStr
, nTab
, thePos
, rDetails
);
218 thePos
.SetRelCol( false );
219 thePos
.SetRelRow( false );
220 thePos
.SetRelTab( false );
225 *pPosTripel
= thePos
;
227 *pCompleteStr
= thePos
.GetRefString( rDoc
, MAXTAB
+1, rDetails
);
233 bool ScRangeUtil::MakeRangeFromName (
234 const OUString
& rName
,
235 const ScDocument
& rDoc
,
238 RutlNameScope eScope
,
239 ScAddress::Details
const & rDetails
,
240 bool bUseDetailsPos
)
242 bool bResult
= false;
252 if (eScope
== RUTL_NAMES
|| eScope
== RUTL_NAMES_LOCAL
|| eScope
== RUTL_NAMES_GLOBAL
)
254 OUString
aName(rName
);
255 SCTAB nTable
= nCurTab
;
257 if (eScope
!= RUTL_NAMES_GLOBAL
)
259 // First handle UI names like "local1 (Sheet1)", which point to a
261 const sal_Int32 nEndPos
= aName
.getLength() - 1;
262 if (rName
[nEndPos
] == ')')
264 const sal_Int32 nStartPos
= aName
.indexOf(" (");
267 OUString aSheetName
= aName
.copy(nStartPos
+2, nEndPos
-nStartPos
-2);
268 if (rDoc
.GetTable(aSheetName
, nTable
))
270 aName
= aName
.copy(0, nStartPos
);
271 eScope
= RUTL_NAMES_LOCAL
;
279 aName
= ScGlobal::getCharClass().uppercase(aName
);
280 ScRangeData
* pData
= nullptr;
281 if (eScope
!= RUTL_NAMES_GLOBAL
)
283 // Check for local range names.
284 ScRangeName
* pRangeNames
= rDoc
.GetRangeName( nTable
);
286 pData
= pRangeNames
->findByUpperName(aName
);
288 if (!pData
&& eScope
!= RUTL_NAMES_LOCAL
)
289 pData
= rDoc
.GetRangeName()->findByUpperName(aName
);
293 ScRefAddress aStartPos
;
294 ScRefAddress aEndPos
;
296 // tdf#138646: use the current grammar of the document and passed
297 // address convention.
298 // tdf#145077: create range string according to current cell cursor
299 // position if expression has relative references and details say so.
301 aStrArea
= pData
->GetSymbol( ScAddress( rDetails
.nCol
, rDetails
.nRow
, nCurTab
),
302 FormulaGrammar::mergeToGrammar(rDoc
.GetGrammar(), rDetails
.eConv
));
304 aStrArea
= pData
->GetSymbol(
305 FormulaGrammar::mergeToGrammar(rDoc
.GetGrammar(), rDetails
.eConv
));
307 if ( IsAbsArea( aStrArea
, rDoc
, nTable
,
308 nullptr, &aStartPos
, &aEndPos
, rDetails
) )
310 nTab
= aStartPos
.Tab();
311 nColStart
= aStartPos
.Col();
312 nRowStart
= aStartPos
.Row();
313 nColEnd
= aEndPos
.Col();
314 nRowEnd
= aEndPos
.Row();
319 CutPosString( aStrArea
, aStrArea
);
321 if ( IsAbsPos( aStrArea
, rDoc
, nTable
,
322 nullptr, &aStartPos
, rDetails
) )
324 nTab
= aStartPos
.Tab();
325 nColStart
= nColEnd
= aStartPos
.Col();
326 nRowStart
= nRowEnd
= aStartPos
.Row();
332 else if( eScope
==RUTL_DBASE
)
334 ScDBCollection::NamedDBs
& rDbNames
= rDoc
.GetDBCollection()->getNamedDBs();
335 ScDBData
* pData
= rDbNames
.findByUpperName(ScGlobal::getCharClass().uppercase(rName
));
338 pData
->GetArea(nTab
, nColStart
, nRowStart
, nColEnd
, nRowEnd
);
344 OSL_FAIL( "ScRangeUtil::MakeRangeFromName" );
349 rRange
= ScRange( nColStart
, nRowStart
, nTab
, nColEnd
, nRowEnd
, nTab
);
355 void ScRangeStringConverter::AssignString(
357 const OUString
& rNewStr
,
359 sal_Unicode cSeparator
)
363 if( !rNewStr
.isEmpty() )
365 if( !rString
.isEmpty() )
366 rString
+= OUStringChar(cSeparator
);
374 sal_Int32
ScRangeStringConverter::IndexOf(
375 std::u16string_view rString
,
376 sal_Unicode cSearchChar
,
380 sal_Int32 nLength
= rString
.size();
381 sal_Int32 nIndex
= nOffset
;
382 bool bQuoted
= false;
383 bool bExitLoop
= false;
385 while( !bExitLoop
&& (nIndex
>= 0 && nIndex
< nLength
) )
387 sal_Unicode cCode
= rString
[ nIndex
];
388 bExitLoop
= (cCode
== cSearchChar
) && !bQuoted
;
389 bQuoted
= (bQuoted
!= (cCode
== cQuote
));
393 return (nIndex
< nLength
) ? nIndex
: -1;
396 sal_Int32
ScRangeStringConverter::IndexOfDifferent(
397 std::u16string_view rString
,
398 sal_Unicode cSearchChar
,
401 sal_Int32 nLength
= rString
.size();
402 sal_Int32 nIndex
= nOffset
;
403 bool bExitLoop
= false;
405 while( !bExitLoop
&& (nIndex
>= 0 && nIndex
< nLength
) )
407 bExitLoop
= (rString
[ nIndex
] != cSearchChar
);
411 return (nIndex
< nLength
) ? nIndex
: -1;
414 void ScRangeStringConverter::GetTokenByOffset(
416 std::u16string_view rString
,
418 sal_Unicode cSeparator
,
421 sal_Int32 nLength
= rString
.size();
422 if( nOffset
== -1 || nOffset
>= nLength
)
429 sal_Int32 nTokenEnd
= IndexOf( rString
, cSeparator
, nOffset
, cQuote
);
432 rToken
= rString
.substr( nOffset
, nTokenEnd
- nOffset
);
434 sal_Int32 nNextBegin
= IndexOfDifferent( rString
, cSeparator
, nTokenEnd
);
435 nOffset
= (nNextBegin
< 0) ? nLength
: nNextBegin
;
439 void ScRangeStringConverter::AppendTableName(OUStringBuffer
& rBuf
, const OUString
& rTabName
)
441 // quote character is always "'"
442 OUString
aQuotedTab(rTabName
);
443 ScCompiler::CheckTabQuotes(aQuotedTab
);
444 rBuf
.append(aQuotedTab
);
447 sal_Int32
ScRangeStringConverter::GetTokenCount( std::u16string_view rString
, sal_Unicode cSeparator
)
450 sal_Int32 nCount
= 0;
451 sal_Int32 nOffset
= 0;
452 while( nOffset
>= 0 )
454 GetTokenByOffset( sToken
, rString
, nOffset
, '\'', cSeparator
);
461 bool ScRangeStringConverter::GetAddressFromString(
463 std::u16string_view rAddressStr
,
464 const ScDocument
& rDocument
,
465 FormulaGrammar::AddressConvention eConv
,
467 sal_Unicode cSeparator
,
471 GetTokenByOffset( sToken
, rAddressStr
, nOffset
, cSeparator
, cQuote
);
474 if ((rAddress
.Parse( sToken
, rDocument
, eConv
) & ScRefFlags::VALID
) == ScRefFlags::VALID
)
476 ::formula::FormulaGrammar::AddressConvention eConvUI
= rDocument
.GetAddressConvention();
477 if (eConv
!= eConvUI
)
478 return ((rAddress
.Parse(sToken
, rDocument
, eConvUI
) & ScRefFlags::VALID
) == ScRefFlags::VALID
);
483 bool ScRangeStringConverter::GetRangeFromString(
485 std::u16string_view rRangeStr
,
486 const ScDocument
& rDocument
,
487 FormulaGrammar::AddressConvention eConv
,
489 sal_Unicode cSeparator
,
494 GetTokenByOffset( sToken
, rRangeStr
, nOffset
, cSeparator
, cQuote
);
497 sal_Int32 nIndex
= IndexOf( sToken
, ':', 0, cQuote
);
498 OUString
aUIString(sToken
);
502 if ( aUIString
[0] == '.' )
503 aUIString
= aUIString
.copy( 1 );
504 bResult
= (rRange
.aStart
.Parse( aUIString
, rDocument
, eConv
) & ScRefFlags::VALID
) ==
506 ::formula::FormulaGrammar::AddressConvention eConvUI
= rDocument
.GetAddressConvention();
507 if (!bResult
&& eConv
!= eConvUI
)
508 bResult
= (rRange
.aStart
.Parse(aUIString
, rDocument
, eConvUI
) & ScRefFlags::VALID
) ==
510 rRange
.aEnd
= rRange
.aStart
;
514 if ( aUIString
[0] == '.' )
516 aUIString
= aUIString
.copy( 1 );
520 if ( nIndex
< aUIString
.getLength() - 1 &&
521 aUIString
[ nIndex
+ 1 ] == '.' )
522 aUIString
= aUIString
.replaceAt( nIndex
+ 1, 1, u
"" );
524 bResult
= ((rRange
.Parse(aUIString
, rDocument
, eConv
) & ScRefFlags::VALID
) ==
527 // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
528 // This isn't parsed by ScRange, so try to parse the two Addresses then.
531 bResult
= ((rRange
.aStart
.Parse( aUIString
.copy(0, nIndex
), rDocument
, eConv
)
532 & ScRefFlags::VALID
) == ScRefFlags::VALID
)
534 ((rRange
.aEnd
.Parse( aUIString
.copy(nIndex
+1), rDocument
, eConv
)
535 & ScRefFlags::VALID
) == ScRefFlags::VALID
);
537 ::formula::FormulaGrammar::AddressConvention eConvUI
= rDocument
.GetAddressConvention();
538 if (!bResult
&& eConv
!= eConvUI
)
540 bResult
= ((rRange
.aStart
.Parse( aUIString
.copy(0, nIndex
), rDocument
, eConvUI
)
541 & ScRefFlags::VALID
) == ScRefFlags::VALID
)
543 ((rRange
.aEnd
.Parse( aUIString
.copy(nIndex
+1), rDocument
, eConvUI
)
544 & ScRefFlags::VALID
) == ScRefFlags::VALID
);
552 bool ScRangeStringConverter::GetRangeListFromString(
553 ScRangeList
& rRangeList
,
554 std::u16string_view rRangeListStr
,
555 const ScDocument
& rDocument
,
556 FormulaGrammar::AddressConvention eConv
,
557 sal_Unicode cSeparator
,
561 OSL_ENSURE( !rRangeListStr
.empty(), "ScXMLConverter::GetRangeListFromString - empty string!" );
562 sal_Int32 nOffset
= 0;
563 while( nOffset
>= 0 )
567 GetRangeFromString( aRange
, rRangeListStr
, rDocument
, eConv
, nOffset
, cSeparator
, cQuote
) &&
571 rRangeList
.push_back( aRange
);
573 else if (nOffset
> -1)
579 bool ScRangeStringConverter::GetAreaFromString(
581 std::u16string_view rRangeStr
,
582 const ScDocument
& rDocument
,
583 FormulaGrammar::AddressConvention eConv
,
585 sal_Unicode cSeparator
)
589 if( GetRangeFromString( aScRange
, rRangeStr
, rDocument
, eConv
, nOffset
, cSeparator
) && (nOffset
>= 0) )
591 rArea
.nTab
= aScRange
.aStart
.Tab();
592 rArea
.nColStart
= aScRange
.aStart
.Col();
593 rArea
.nRowStart
= aScRange
.aStart
.Row();
594 rArea
.nColEnd
= aScRange
.aEnd
.Col();
595 rArea
.nRowEnd
= aScRange
.aEnd
.Row();
601 bool ScRangeStringConverter::GetRangeFromString(
602 table::CellRangeAddress
& rRange
,
603 std::u16string_view rRangeStr
,
604 const ScDocument
& rDocument
,
605 FormulaGrammar::AddressConvention eConv
,
607 sal_Unicode cSeparator
)
611 if( GetRangeFromString( aScRange
, rRangeStr
, rDocument
, eConv
, nOffset
, cSeparator
) && (nOffset
>= 0) )
613 ScUnoConversion::FillApiRange( rRange
, aScRange
);
619 void ScRangeStringConverter::GetStringFromAddress(
621 const ScAddress
& rAddress
,
622 const ScDocument
* pDocument
,
623 FormulaGrammar::AddressConvention eConv
,
624 sal_Unicode cSeparator
,
626 ScRefFlags nFormatFlags
)
628 if (pDocument
&& pDocument
->HasTable(rAddress
.Tab()))
630 OUString
sAddress(rAddress
.Format(nFormatFlags
, pDocument
, eConv
));
631 AssignString( rString
, sAddress
, bAppendStr
, cSeparator
);
635 void ScRangeStringConverter::GetStringFromRange(
637 const ScRange
& rRange
,
638 const ScDocument
* pDocument
,
639 FormulaGrammar::AddressConvention eConv
,
640 sal_Unicode cSeparator
,
642 ScRefFlags nFormatFlags
)
644 if (pDocument
&& pDocument
->HasTable(rRange
.aStart
.Tab()))
646 ScAddress
aStartAddress( rRange
.aStart
);
647 ScAddress
aEndAddress( rRange
.aEnd
);
648 OUString
sStartAddress(aStartAddress
.Format(nFormatFlags
, pDocument
, eConv
));
649 OUString
sEndAddress(aEndAddress
.Format(nFormatFlags
, pDocument
, eConv
));
651 rString
, sStartAddress
+ ":" + sEndAddress
, bAppendStr
, cSeparator
);
655 void ScRangeStringConverter::GetStringFromRangeList(
657 const ScRangeList
* pRangeList
,
658 const ScDocument
* pDocument
,
659 FormulaGrammar::AddressConvention eConv
,
660 sal_Unicode cSeparator
)
662 OUString sRangeListStr
;
665 for( size_t nIndex
= 0, nCount
= pRangeList
->size(); nIndex
< nCount
; nIndex
++ )
667 const ScRange
& rRange
= (*pRangeList
)[nIndex
];
668 GetStringFromRange( sRangeListStr
, rRange
, pDocument
, eConv
, cSeparator
, true );
671 rString
= sRangeListStr
;
674 void ScRangeStringConverter::GetStringFromArea(
677 const ScDocument
* pDocument
,
678 FormulaGrammar::AddressConvention eConv
,
679 sal_Unicode cSeparator
,
681 ScRefFlags nFormatFlags
)
683 ScRange
aRange( rArea
.nColStart
, rArea
.nRowStart
, rArea
.nTab
, rArea
.nColEnd
, rArea
.nRowEnd
, rArea
.nTab
);
684 GetStringFromRange( rString
, aRange
, pDocument
, eConv
, cSeparator
, bAppendStr
, nFormatFlags
);
687 void ScRangeStringConverter::GetStringFromAddress(
689 const table::CellAddress
& rAddress
,
690 const ScDocument
* pDocument
,
691 FormulaGrammar::AddressConvention eConv
,
692 sal_Unicode cSeparator
,
695 ScAddress
aScAddress( static_cast<SCCOL
>(rAddress
.Column
), static_cast<SCROW
>(rAddress
.Row
), rAddress
.Sheet
);
696 GetStringFromAddress( rString
, aScAddress
, pDocument
, eConv
, cSeparator
, bAppendStr
);
699 void ScRangeStringConverter::GetStringFromRange(
701 const table::CellRangeAddress
& rRange
,
702 const ScDocument
* pDocument
,
703 FormulaGrammar::AddressConvention eConv
,
704 sal_Unicode cSeparator
,
706 ScRefFlags nFormatFlags
)
708 ScRange
aScRange( static_cast<SCCOL
>(rRange
.StartColumn
), static_cast<SCROW
>(rRange
.StartRow
), rRange
.Sheet
,
709 static_cast<SCCOL
>(rRange
.EndColumn
), static_cast<SCROW
>(rRange
.EndRow
), rRange
.Sheet
);
710 GetStringFromRange( rString
, aScRange
, pDocument
, eConv
, cSeparator
, bAppendStr
, nFormatFlags
);
713 void ScRangeStringConverter::GetStringFromRangeList(
715 const uno::Sequence
< table::CellRangeAddress
>& rRangeSeq
,
716 const ScDocument
* pDocument
,
717 FormulaGrammar::AddressConvention eConv
,
718 sal_Unicode cSeparator
)
720 OUString sRangeListStr
;
721 for( const table::CellRangeAddress
& rRange
: rRangeSeq
)
723 GetStringFromRange( sRangeListStr
, rRange
, pDocument
, eConv
, cSeparator
, true );
725 rString
= sRangeListStr
;
728 static void lcl_appendCellAddress(
729 OUStringBuffer
& rBuf
, const ScDocument
& rDoc
, const ScAddress
& rCell
,
730 const ScAddress::ExternalInfo
& rExtInfo
)
732 if (rExtInfo
.mbExternal
)
734 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
735 const OUString
* pFilePath
= pRefMgr
->getExternalFileName(rExtInfo
.mnFileId
, true);
739 sal_Unicode cQuote
= '\'';
741 rBuf
.append(*pFilePath
);
745 ScRangeStringConverter::AppendTableName(rBuf
, rExtInfo
.maTabName
);
748 OUString
aAddr(rCell
.Format(ScRefFlags::ADDR_ABS
, nullptr, rDoc
.GetAddressConvention()));
753 OUString
aAddr(rCell
.Format(ScRefFlags::ADDR_ABS_3D
, &rDoc
, rDoc
.GetAddressConvention()));
758 static void lcl_appendCellRangeAddress(
759 OUStringBuffer
& rBuf
, const ScDocument
& rDoc
, const ScAddress
& rCell1
, const ScAddress
& rCell2
,
760 const ScAddress::ExternalInfo
& rExtInfo1
, const ScAddress::ExternalInfo
& rExtInfo2
)
762 if (rExtInfo1
.mbExternal
)
764 OSL_ENSURE(rExtInfo2
.mbExternal
, "2nd address is not external!?");
765 OSL_ENSURE(rExtInfo1
.mnFileId
== rExtInfo2
.mnFileId
, "File IDs do not match between 1st and 2nd addresses.");
767 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
768 const OUString
* pFilePath
= pRefMgr
->getExternalFileName(rExtInfo1
.mnFileId
, true);
772 sal_Unicode cQuote
= '\'';
774 rBuf
.append(*pFilePath
);
778 ScRangeStringConverter::AppendTableName(rBuf
, rExtInfo1
.maTabName
);
781 OUString
aAddr(rCell1
.Format(ScRefFlags::ADDR_ABS
, nullptr, rDoc
.GetAddressConvention()));
786 if (rExtInfo1
.maTabName
!= rExtInfo2
.maTabName
)
789 ScRangeStringConverter::AppendTableName(rBuf
, rExtInfo2
.maTabName
);
793 aAddr
= rCell2
.Format(ScRefFlags::ADDR_ABS
, nullptr, rDoc
.GetAddressConvention());
799 aRange
.aStart
= rCell1
;
800 aRange
.aEnd
= rCell2
;
801 OUString
aAddr(aRange
.Format(rDoc
, ScRefFlags::RANGE_ABS_3D
, rDoc
.GetAddressConvention()));
806 void ScRangeStringConverter::GetStringFromXMLRangeString( OUString
& rString
, std::u16string_view rXMLRange
, const ScDocument
& rDoc
)
808 FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
809 const sal_Unicode cSepNew
= ScCompiler::GetNativeSymbolChar(ocSep
);
811 OUStringBuffer aRetStr
;
812 sal_Int32 nOffset
= 0;
818 GetTokenByOffset(aToken
, rXMLRange
, nOffset
);
822 sal_Int32 nSepPos
= IndexOf(aToken
, ':', 0);
826 OUString aBeginCell
= aToken
.copy(0, nSepPos
);
827 OUString aEndCell
= aToken
.copy(nSepPos
+1);
829 if (aBeginCell
.isEmpty() || aEndCell
.isEmpty())
830 // both cell addresses must exist for this to work.
833 sal_Int32 nEndCellDotPos
= aEndCell
.indexOf('.');
834 if (nEndCellDotPos
<= 0)
836 // initialize buffer with table name...
837 sal_Int32 nDotPos
= IndexOf(aBeginCell
, '.', 0);
838 OUStringBuffer
aBuf(aBeginCell
.subView(0, nDotPos
));
840 if (nEndCellDotPos
== 0)
842 // workaround for old syntax (probably pre-chart2 age?)
843 // e.g. Sheet1.A1:.B2
844 aBuf
.append(aEndCell
);
846 else if (nEndCellDotPos
< 0)
848 // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
849 aBuf
.append("." + aEndCell
);
851 aEndCell
= aBuf
.makeStringAndClear();
854 ScAddress::ExternalInfo aExtInfo1
, aExtInfo2
;
855 ScAddress aCell1
, aCell2
;
856 ScRefFlags nRet
= aCell1
.Parse(aBeginCell
, rDoc
, FormulaGrammar::CONV_OOO
, &aExtInfo1
);
857 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
859 // first cell is invalid.
860 if (eConv
== FormulaGrammar::CONV_OOO
)
863 nRet
= aCell1
.Parse(aBeginCell
, rDoc
, eConv
, &aExtInfo1
);
864 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
865 // first cell is really invalid.
869 nRet
= aCell2
.Parse(aEndCell
, rDoc
, FormulaGrammar::CONV_OOO
, &aExtInfo2
);
870 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
872 // second cell is invalid.
873 if (eConv
== FormulaGrammar::CONV_OOO
)
876 nRet
= aCell2
.Parse(aEndCell
, rDoc
, eConv
, &aExtInfo2
);
877 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
878 // second cell is really invalid.
882 if (aExtInfo1
.mnFileId
!= aExtInfo2
.mnFileId
|| aExtInfo1
.mbExternal
!= aExtInfo2
.mbExternal
)
883 // external info inconsistency.
891 aRetStr
.append(cSepNew
);
893 lcl_appendCellRangeAddress(aRetStr
, rDoc
, aCell1
, aCell2
, aExtInfo1
, aExtInfo2
);
897 // Chart always saves ranges using CONV_OOO convention.
898 ScAddress::ExternalInfo aExtInfo
;
900 ScRefFlags nRet
= aCell
.Parse(aToken
, rDoc
, ::formula::FormulaGrammar::CONV_OOO
, &aExtInfo
);
901 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
903 nRet
= aCell
.Parse(aToken
, rDoc
, eConv
, &aExtInfo
);
904 if ((nRet
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
913 aRetStr
.append(cSepNew
);
915 lcl_appendCellAddress(aRetStr
, rDoc
, aCell
, aExtInfo
);
919 rString
= aRetStr
.makeStringAndClear();
922 ScRangeData
* ScRangeStringConverter::GetRangeDataFromString( const OUString
& rString
, const SCTAB nTab
,
923 const ScDocument
& rDoc
, formula::FormulaGrammar::AddressConvention eConv
)
925 // This may be called with an external 'doc'#name but wouldn't find any.
927 // Dot '.' is not allowed in range names, if present only lookup if it's a
928 // sheet-local name. Same for '!' Excel syntax.
929 // If eConv == FormulaGrammar::CONV_A1_XL_A1 then try both, first our own.
930 sal_Int32 nIndex
= -1;
931 if (eConv
== FormulaGrammar::CONV_OOO
|| eConv
== FormulaGrammar::CONV_A1_XL_A1
)
932 nIndex
= ScGlobal::FindUnquoted( rString
, '.');
933 if (nIndex
< 0 && (eConv
== FormulaGrammar::CONV_A1_XL_A1
934 || eConv
== FormulaGrammar::CONV_XL_A1
935 || eConv
== FormulaGrammar::CONV_XL_R1C1
936 || eConv
== FormulaGrammar::CONV_XL_OOX
))
937 nIndex
= ScGlobal::FindUnquoted( rString
, '!');
942 return nullptr; // Can't be a name.
944 OUString
aTab( rString
.copy( 0, nIndex
));
945 ScGlobal::EraseQuotes( aTab
, '\'');
947 if (!rDoc
.GetTable( aTab
, nLocalTab
))
950 ScRangeName
* pLocalRangeName
= rDoc
.GetRangeName(nLocalTab
);
951 if (!pLocalRangeName
)
954 const OUString
aName( rString
.copy( nIndex
+1));
955 return pLocalRangeName
->findByUpperName( ScGlobal::getCharClass().uppercase( aName
));
958 ScRangeName
* pLocalRangeName
= rDoc
.GetRangeName(nTab
);
959 ScRangeData
* pData
= nullptr;
960 OUString aUpperName
= ScGlobal::getCharClass().uppercase(rString
);
963 pData
= pLocalRangeName
->findByUpperName(aUpperName
);
967 ScRangeName
* pGlobalRangeName
= rDoc
.GetRangeName();
968 if (pGlobalRangeName
)
970 pData
= pGlobalRangeName
->findByUpperName(aUpperName
);
976 ScArea::ScArea( SCTAB tab
,
977 SCCOL colStart
, SCROW rowStart
,
978 SCCOL colEnd
, SCROW rowEnd
) :
980 nColStart( colStart
), nRowStart( rowStart
),
981 nColEnd ( colEnd
), nRowEnd ( rowEnd
)
985 bool ScArea::operator==( const ScArea
& r
) const
987 return ( (nTab
== r
.nTab
)
988 && (nColStart
== r
.nColStart
)
989 && (nRowStart
== r
.nRowStart
)
990 && (nColEnd
== r
.nColEnd
)
991 && (nRowEnd
== r
.nRowEnd
) );
994 ScAreaNameIterator::ScAreaNameIterator( const ScDocument
& rDoc
) :
995 pRangeName(rDoc
.GetRangeName()),
996 pDBCollection(rDoc
.GetDBCollection()),
1001 maRNPos
= pRangeName
->begin();
1002 maRNEnd
= pRangeName
->end();
1006 bool ScAreaNameIterator::Next( OUString
& rName
, ScRange
& rRange
)
1010 if ( bFirstPass
) // first the area names
1012 if ( pRangeName
&& maRNPos
!= maRNEnd
)
1014 const ScRangeData
& rData
= *maRNPos
->second
;
1016 bool bValid
= rData
.IsValidReference(rRange
);
1019 rName
= rData
.GetName();
1020 return true; // found
1028 const ScDBCollection::NamedDBs
& rDBs
= pDBCollection
->getNamedDBs();
1029 maDBPos
= rDBs
.begin();
1030 maDBEnd
= rDBs
.end();
1035 if ( !bFirstPass
) // then the DB areas
1037 if (pDBCollection
&& maDBPos
!= maDBEnd
)
1039 const ScDBData
& rData
= **maDBPos
;
1041 rData
.GetArea(rRange
);
1042 rName
= rData
.GetName();
1043 return true; // found
1046 return false; // nothing left
1051 void ScRangeUpdater::UpdateInsertTab(ScAddress
& rAddr
, const sc::RefUpdateInsertTabContext
& rCxt
)
1053 if (rCxt
.mnInsertPos
<= rAddr
.Tab())
1055 rAddr
.IncTab(rCxt
.mnSheets
);
1059 void ScRangeUpdater::UpdateDeleteTab(ScAddress
& rAddr
, const sc::RefUpdateDeleteTabContext
& rCxt
)
1061 if (rCxt
.mnDeletePos
<= rAddr
.Tab())
1063 rAddr
.SetTab( std::max
<SCTAB
>(0, rAddr
.Tab() - rCxt
.mnSheets
));
1067 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */