LibreOffice Module sc (master)  1
rangeutl.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <osl/diagnose.h>
22 #include <unotools/charclass.hxx>
23 #include <rangeutl.hxx>
24 #include <document.hxx>
25 #include <global.hxx>
26 #include <dbdata.hxx>
27 #include <rangenam.hxx>
28 #include <convuno.hxx>
29 #include <externalrefmgr.hxx>
30 #include <compiler.hxx>
31 #include <refupdatecontext.hxx>
32 
33 using ::formula::FormulaGrammar;
34 using namespace ::com::sun::star;
35 
36 bool ScRangeUtil::MakeArea( const OUString& rAreaStr,
37  ScArea& rArea,
38  const ScDocument& rDoc,
39  SCTAB nTab,
40  ScAddress::Details const & rDetails )
41 {
42  // Input in rAreaStr: "$Tabelle1.$A1:$D17"
43 
44  // BROKEN BROKEN BROKEN
45  // but it is only used in the consolidate dialog. Ignore for now.
46 
47  bool bSuccess = false;
48  sal_Int32 nPointPos = rAreaStr.indexOf('.');
49  sal_Int32 nColonPos = rAreaStr.indexOf(':');
50  OUString aStrArea( rAreaStr );
51  ScRefAddress startPos;
52  ScRefAddress endPos;
53 
54  if ( nColonPos == -1 && nPointPos != -1 )
55  {
56  aStrArea += ":" + rAreaStr.copy( nPointPos+1 ); // do not include '.' in copy
57  }
58 
59  bSuccess = ConvertDoubleRef( rDoc, aStrArea, nTab, startPos, endPos, rDetails );
60 
61  if ( bSuccess )
62  rArea = ScArea( startPos.Tab(),
63  startPos.Col(), startPos.Row(),
64  endPos.Col(), endPos.Row() );
65 
66  return bSuccess;
67 }
68 
69 void ScRangeUtil::CutPosString( const OUString& theAreaStr,
70  OUString& thePosStr )
71 {
72  OUString aPosStr;
73  // BROKEN BROKEN BROKEN
74  // but it is only used in the consolidate dialog. Ignore for now.
75 
76  sal_Int32 nColonPos = theAreaStr.indexOf(':');
77 
78  if ( nColonPos != -1 )
79  aPosStr = theAreaStr.copy( 0, nColonPos ); // do not include ':' in copy
80  else
81  aPosStr = theAreaStr;
82 
83  thePosStr = aPosStr;
84 }
85 
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 )
92 {
93  OSL_ENSURE( pDoc, "No document given!" );
94  if ( !pDoc )
95  return false;
96 
97  // BROKEN BROKEN BROKEN
98  // but it is only used in the consolidate dialog. Ignore for now.
99 
100  /*
101  * Expects strings like:
102  * "$Tabelle1.$A$1:$Tabelle3.$D$17"
103  * If bAcceptCellRef == sal_True then also accept strings like:
104  * "$Tabelle1.$A$1"
105  *
106  * as result a ScArea-Array is created,
107  * which is published via ppAreas and also has to be deleted this route.
108  */
109 
110  bool bStrOk = false;
111  OUString aTempAreaStr(rAreaStr);
112 
113  if ( -1 == aTempAreaStr.indexOf(':') )
114  {
115  aTempAreaStr += ":" + rAreaStr;
116  }
117 
118  sal_Int32 nColonPos = aTempAreaStr.indexOf(':');
119 
120  if ( -1 != nColonPos
121  && -1 != aTempAreaStr.indexOf('.') )
122  {
123  ScRefAddress aStartPos;
124 
125  OUString aStartPosStr = aTempAreaStr.copy( 0, nColonPos );
126  OUString aEndPosStr = aTempAreaStr.copy( nColonPos+1 );
127 
128  if ( ConvertSingleRef( *pDoc, aStartPosStr, 0, aStartPos, rDetails ) )
129  {
130  ScRefAddress aEndPos;
131  if ( ConvertSingleRef( *pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) )
132  {
133  aStartPos.SetRelCol( false );
134  aStartPos.SetRelRow( false );
135  aStartPos.SetRelTab( false );
136  aEndPos.SetRelCol( false );
137  aEndPos.SetRelRow( false );
138  aEndPos.SetRelTab( false );
139 
140  bStrOk = true;
141 
142  if ( ppAreas && pAreaCount ) // Array returned ?
143  {
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]);
148  SCTAB nTab = 0;
149  sal_uInt16 i = 0;
150  ScArea theArea( 0, aStartPos.Col(), aStartPos.Row(),
151  aEndPos.Col(), aEndPos.Row() );
152 
153  nTab = nStartTab;
154  for ( i=0; i<nTabCount; i++ )
155  {
156  (*ppAreas)[i] = theArea;
157  (*ppAreas)[i].nTab = nTab;
158  nTab++;
159  }
160  *pAreaCount = nTabCount;
161  }
162  }
163  }
164  }
165 
166  return bStrOk;
167 }
168 
169 bool ScRangeUtil::IsAbsArea( const OUString& rAreaStr,
170  const ScDocument& rDoc,
171  SCTAB nTab,
172  OUString* pCompleteStr,
173  ScRefAddress* pStartPos,
174  ScRefAddress* pEndPos,
175  ScAddress::Details const & rDetails )
176 {
177  ScRefAddress startPos;
178  ScRefAddress endPos;
179 
180  bool bIsAbsArea = ConvertDoubleRef( rDoc, rAreaStr, nTab, startPos, endPos, rDetails );
181 
182  if ( bIsAbsArea )
183  {
184  startPos.SetRelCol( false );
185  startPos.SetRelRow( false );
186  startPos.SetRelTab( false );
187  endPos .SetRelCol( false );
188  endPos .SetRelRow( false );
189  endPos .SetRelTab( false );
190 
191  if ( pCompleteStr )
192  {
193  *pCompleteStr = startPos.GetRefString( rDoc, MAXTAB+1, rDetails );
194  *pCompleteStr += ":";
195  *pCompleteStr += endPos.GetRefString( rDoc, nTab, rDetails );
196  }
197 
198  if ( pStartPos && pEndPos )
199  {
200  *pStartPos = startPos;
201  *pEndPos = endPos;
202  }
203  }
204 
205  return bIsAbsArea;
206 }
207 
208 bool ScRangeUtil::IsAbsPos( const OUString& rPosStr,
209  const ScDocument& rDoc,
210  SCTAB nTab,
211  OUString* pCompleteStr,
212  ScRefAddress* pPosTripel,
213  ScAddress::Details const & rDetails )
214 {
215  ScRefAddress thePos;
216 
217  bool bIsAbsPos = ConvertSingleRef( rDoc, rPosStr, nTab, thePos, rDetails );
218  thePos.SetRelCol( false );
219  thePos.SetRelRow( false );
220  thePos.SetRelTab( false );
221 
222  if ( bIsAbsPos )
223  {
224  if ( pPosTripel )
225  *pPosTripel = thePos;
226  if ( pCompleteStr )
227  *pCompleteStr = thePos.GetRefString( rDoc, MAXTAB+1, rDetails );
228  }
229 
230  return bIsAbsPos;
231 }
232 
234  const OUString& rName,
235  const ScDocument& rDoc,
236  SCTAB nCurTab,
237  ScRange& rRange,
238  RutlNameScope eScope,
239  ScAddress::Details const & rDetails )
240 {
241  bool bResult = false;
242  SCTAB nTab = 0;
243  SCCOL nColStart = 0;
244  SCCOL nColEnd = 0;
245  SCROW nRowStart = 0;
246  SCROW nRowEnd = 0;
247 
248  if( eScope==RUTL_NAMES )
249  {
250  //first handle ui names like local1 (Sheet1), which point to a local range name
251  OUString aName(rName);
252  sal_Int32 nEndPos = aName.lastIndexOf(')');
253  sal_Int32 nStartPos = aName.lastIndexOf(" (");
254  SCTAB nTable = nCurTab;
255  if (nEndPos != -1 && nStartPos != -1)
256  {
257  OUString aSheetName = aName.copy(nStartPos+2, nEndPos-nStartPos-2);
258  if (rDoc.GetTable(aSheetName, nTable))
259  {
260  aName = aName.copy(0, nStartPos);
261  }
262  else
263  nTable = nCurTab;
264  }
265  //then check for local range names
266  ScRangeName* pRangeNames = rDoc.GetRangeName( nTable );
267  ScRangeData* pData = nullptr;
268  aName = ScGlobal::getCharClassPtr()->uppercase(aName);
269  if ( pRangeNames )
270  pData = pRangeNames->findByUpperName(aName);
271  if (!pData)
272  pData = rDoc.GetRangeName()->findByUpperName(aName);
273  if (pData)
274  {
275  OUString aStrArea;
276  ScRefAddress aStartPos;
277  ScRefAddress aEndPos;
278 
279  pData->GetSymbol( aStrArea );
280 
281  if ( IsAbsArea( aStrArea, rDoc, nTable,
282  nullptr, &aStartPos, &aEndPos, rDetails ) )
283  {
284  nTab = aStartPos.Tab();
285  nColStart = aStartPos.Col();
286  nRowStart = aStartPos.Row();
287  nColEnd = aEndPos.Col();
288  nRowEnd = aEndPos.Row();
289  bResult = true;
290  }
291  else
292  {
293  CutPosString( aStrArea, aStrArea );
294 
295  if ( IsAbsPos( aStrArea, rDoc, nTable,
296  nullptr, &aStartPos, rDetails ) )
297  {
298  nTab = aStartPos.Tab();
299  nColStart = nColEnd = aStartPos.Col();
300  nRowStart = nRowEnd = aStartPos.Row();
301  bResult = true;
302  }
303  }
304  }
305  }
306  else if( eScope==RUTL_DBASE )
307  {
309  ScDBData* pData = rDbNames.findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rName));
310  if (pData)
311  {
312  pData->GetArea(nTab, nColStart, nRowStart, nColEnd, nRowEnd);
313  bResult = true;
314  }
315  }
316  else
317  {
318  OSL_FAIL( "ScRangeUtil::MakeRangeFromName" );
319  }
320 
321  if( bResult )
322  {
323  rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab );
324  }
325 
326  return bResult;
327 }
328 
330  OUString& rString,
331  const OUString& rNewStr,
332  bool bAppendStr,
333  sal_Unicode cSeparator)
334 {
335  if( bAppendStr )
336  {
337  if( !rNewStr.isEmpty() )
338  {
339  if( !rString.isEmpty() )
340  rString += OUStringChar(cSeparator);
341  rString += rNewStr;
342  }
343  }
344  else
345  rString = rNewStr;
346 }
347 
349  const OUString& rString,
350  sal_Unicode cSearchChar,
351  sal_Int32 nOffset,
352  sal_Unicode cQuote )
353 {
354  sal_Int32 nLength = rString.getLength();
355  sal_Int32 nIndex = nOffset;
356  bool bQuoted = false;
357  bool bExitLoop = false;
358 
359  while( !bExitLoop && (nIndex >= 0 && nIndex < nLength) )
360  {
361  sal_Unicode cCode = rString[ nIndex ];
362  bExitLoop = (cCode == cSearchChar) && !bQuoted;
363  bQuoted = (bQuoted != (cCode == cQuote));
364  if( !bExitLoop )
365  nIndex++;
366  }
367  return (nIndex < nLength) ? nIndex : -1;
368 }
369 
371  const OUString& rString,
372  sal_Unicode cSearchChar,
373  sal_Int32 nOffset )
374 {
375  sal_Int32 nLength = rString.getLength();
376  sal_Int32 nIndex = nOffset;
377  bool bExitLoop = false;
378 
379  while( !bExitLoop && (nIndex >= 0 && nIndex < nLength) )
380  {
381  bExitLoop = (rString[ nIndex ] != cSearchChar);
382  if( !bExitLoop )
383  nIndex++;
384  }
385  return (nIndex < nLength) ? nIndex : -1;
386 }
387 
389  OUString& rToken,
390  const OUString& rString,
391  sal_Int32& nOffset,
392  sal_Unicode cSeparator,
393  sal_Unicode cQuote)
394 {
395  sal_Int32 nLength = rString.getLength();
396  if( nOffset == -1 || nOffset >= nLength )
397  {
398  rToken.clear();
399  nOffset = -1;
400  }
401  else
402  {
403  sal_Int32 nTokenEnd = IndexOf( rString, cSeparator, nOffset, cQuote );
404  if( nTokenEnd < 0 )
405  nTokenEnd = nLength;
406  rToken = rString.copy( nOffset, nTokenEnd - nOffset );
407 
408  sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeparator, nTokenEnd );
409  nOffset = (nNextBegin < 0) ? nLength : nNextBegin;
410  }
411 }
412 
413 void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName)
414 {
415  // quote character is always "'"
416  OUString aQuotedTab(rTabName);
417  ScCompiler::CheckTabQuotes(aQuotedTab);
418  rBuf.append(aQuotedTab);
419 }
420 
421 sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeparator )
422 {
423  OUString sToken;
424  sal_Int32 nCount = 0;
425  sal_Int32 nOffset = 0;
426  while( nOffset >= 0 )
427  {
428  GetTokenByOffset( sToken, rString, nOffset, '\'', cSeparator );
429  if( nOffset >= 0 )
430  nCount++;
431  }
432  return nCount;
433 }
434 
436  ScAddress& rAddress,
437  const OUString& rAddressStr,
438  const ScDocument& rDocument,
439  FormulaGrammar::AddressConvention eConv,
440  sal_Int32& nOffset,
441  sal_Unicode cSeparator,
442  sal_Unicode cQuote )
443 {
444  OUString sToken;
445  GetTokenByOffset( sToken, rAddressStr, nOffset, cSeparator, cQuote );
446  if( nOffset >= 0 )
447  {
448  if ((rAddress.Parse( sToken, rDocument, eConv ) & ScRefFlags::VALID) == ScRefFlags::VALID)
449  return true;
451  if (eConv != eConvUI)
452  return ((rAddress.Parse(sToken, rDocument, eConvUI) & ScRefFlags::VALID) == ScRefFlags::VALID);
453  }
454  return false;
455 }
456 
458  ScRange& rRange,
459  const OUString& rRangeStr,
460  const ScDocument& rDocument,
461  FormulaGrammar::AddressConvention eConv,
462  sal_Int32& nOffset,
463  sal_Unicode cSeparator,
464  sal_Unicode cQuote )
465 {
466  OUString sToken;
467  bool bResult(false);
468  GetTokenByOffset( sToken, rRangeStr, nOffset, cSeparator, cQuote );
469  if( nOffset >= 0 )
470  {
471  sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote );
472  OUString aUIString(sToken);
473 
474  if( nIndex < 0 )
475  {
476  if ( aUIString[0] == '.' )
477  aUIString = aUIString.copy( 1 );
478  bResult = (rRange.aStart.Parse( aUIString, rDocument, eConv) & ScRefFlags::VALID) ==
481  if (!bResult && eConv != eConvUI)
482  bResult = (rRange.aStart.Parse(aUIString, rDocument, eConvUI) & ScRefFlags::VALID) ==
484  rRange.aEnd = rRange.aStart;
485  }
486  else
487  {
488  if ( aUIString[0] == '.' )
489  {
490  aUIString = aUIString.copy( 1 );
491  --nIndex;
492  }
493 
494  if ( nIndex < aUIString.getLength() - 1 &&
495  aUIString[ nIndex + 1 ] == '.' )
496  aUIString = aUIString.replaceAt( nIndex + 1, 1, "" );
497 
498  bResult = ((rRange.Parse(aUIString, rDocument, eConv) & ScRefFlags::VALID) ==
500 
501  // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
502  // This isn't parsed by ScRange, so try to parse the two Addresses then.
503  if (!bResult)
504  {
505  bResult = ((rRange.aStart.Parse( aUIString.copy(0, nIndex), rDocument, eConv)
507  &&
508  ((rRange.aEnd.Parse( aUIString.copy(nIndex+1), rDocument, eConv)
510 
512  if (!bResult && eConv != eConvUI)
513  {
514  bResult = ((rRange.aStart.Parse( aUIString.copy(0, nIndex), rDocument, eConvUI)
516  &&
517  ((rRange.aEnd.Parse( aUIString.copy(nIndex+1), rDocument, eConvUI)
519  }
520  }
521  }
522  }
523  return bResult;
524 }
525 
527  ScRangeList& rRangeList,
528  const OUString& rRangeListStr,
529  const ScDocument& rDocument,
530  FormulaGrammar::AddressConvention eConv,
531  sal_Unicode cSeparator,
532  sal_Unicode cQuote )
533 {
534  bool bRet = true;
535  OSL_ENSURE( !rRangeListStr.isEmpty(), "ScXMLConverter::GetRangeListFromString - empty string!" );
536  sal_Int32 nOffset = 0;
537  while( nOffset >= 0 )
538  {
539  ScRange aRange;
540  if (
541  GetRangeFromString( aRange, rRangeListStr, rDocument, eConv, nOffset, cSeparator, cQuote ) &&
542  (nOffset >= 0)
543  )
544  {
545  rRangeList.push_back( aRange );
546  }
547  else if (nOffset > -1)
548  bRet = false;
549  }
550  return bRet;
551 }
552 
554  ScArea& rArea,
555  const OUString& rRangeStr,
556  const ScDocument& rDocument,
557  FormulaGrammar::AddressConvention eConv,
558  sal_Int32& nOffset,
559  sal_Unicode cSeparator )
560 {
561  ScRange aScRange;
562  bool bResult(false);
563  if( GetRangeFromString( aScRange, rRangeStr, rDocument, eConv, nOffset, cSeparator ) && (nOffset >= 0) )
564  {
565  rArea.nTab = aScRange.aStart.Tab();
566  rArea.nColStart = aScRange.aStart.Col();
567  rArea.nRowStart = aScRange.aStart.Row();
568  rArea.nColEnd = aScRange.aEnd.Col();
569  rArea.nRowEnd = aScRange.aEnd.Row();
570  bResult = true;
571  }
572  return bResult;
573 }
574 
576  table::CellRangeAddress& rRange,
577  const OUString& rRangeStr,
578  const ScDocument& rDocument,
579  FormulaGrammar::AddressConvention eConv,
580  sal_Int32& nOffset,
581  sal_Unicode cSeparator )
582 {
583  ScRange aScRange;
584  bool bResult(false);
585  if( GetRangeFromString( aScRange, rRangeStr, rDocument, eConv, nOffset, cSeparator ) && (nOffset >= 0) )
586  {
587  ScUnoConversion::FillApiRange( rRange, aScRange );
588  bResult = true;
589  }
590  return bResult;
591 }
592 
594  OUString& rString,
595  const ScAddress& rAddress,
596  const ScDocument* pDocument,
597  FormulaGrammar::AddressConvention eConv,
598  sal_Unicode cSeparator,
599  bool bAppendStr,
600  ScRefFlags nFormatFlags )
601 {
602  if (pDocument && pDocument->HasTable(rAddress.Tab()))
603  {
604  OUString sAddress(rAddress.Format(nFormatFlags, pDocument, eConv));
605  AssignString( rString, sAddress, bAppendStr, cSeparator );
606  }
607 }
608 
610  OUString& rString,
611  const ScRange& rRange,
612  const ScDocument* pDocument,
613  FormulaGrammar::AddressConvention eConv,
614  sal_Unicode cSeparator,
615  bool bAppendStr,
616  ScRefFlags nFormatFlags )
617 {
618  if (pDocument && pDocument->HasTable(rRange.aStart.Tab()))
619  {
620  ScAddress aStartAddress( rRange.aStart );
621  ScAddress aEndAddress( rRange.aEnd );
622  OUString sStartAddress(aStartAddress.Format(nFormatFlags, pDocument, eConv));
623  OUString sEndAddress(aEndAddress.Format(nFormatFlags, pDocument, eConv));
624  AssignString(
625  rString, sStartAddress + ":" + sEndAddress, bAppendStr, cSeparator);
626  }
627 }
628 
630  OUString& rString,
631  const ScRangeList* pRangeList,
632  const ScDocument* pDocument,
633  FormulaGrammar::AddressConvention eConv,
634  sal_Unicode cSeparator )
635 {
636  OUString sRangeListStr;
637  if( pRangeList )
638  {
639  for( size_t nIndex = 0, nCount = pRangeList->size(); nIndex < nCount; nIndex++ )
640  {
641  const ScRange & rRange = (*pRangeList)[nIndex];
642  GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeparator, true );
643  }
644  }
645  rString = sRangeListStr;
646 }
647 
649  OUString& rString,
650  const ScArea& rArea,
651  const ScDocument* pDocument,
652  FormulaGrammar::AddressConvention eConv,
653  sal_Unicode cSeparator,
654  bool bAppendStr,
655  ScRefFlags nFormatFlags )
656 {
657  ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
658  GetStringFromRange( rString, aRange, pDocument, eConv, cSeparator, bAppendStr, nFormatFlags );
659 }
660 
662  OUString& rString,
663  const table::CellAddress& rAddress,
664  const ScDocument* pDocument,
665  FormulaGrammar::AddressConvention eConv,
666  sal_Unicode cSeparator,
667  bool bAppendStr )
668 {
669  ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
670  GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeparator, bAppendStr );
671 }
672 
674  OUString& rString,
675  const table::CellRangeAddress& rRange,
676  const ScDocument* pDocument,
677  FormulaGrammar::AddressConvention eConv,
678  sal_Unicode cSeparator,
679  bool bAppendStr,
680  ScRefFlags nFormatFlags )
681 {
682  ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
683  static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
684  GetStringFromRange( rString, aScRange, pDocument, eConv, cSeparator, bAppendStr, nFormatFlags );
685 }
686 
688  OUString& rString,
689  const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
690  const ScDocument* pDocument,
691  FormulaGrammar::AddressConvention eConv,
692  sal_Unicode cSeparator )
693 {
694  OUString sRangeListStr;
695  for( const table::CellRangeAddress& rRange : rRangeSeq )
696  {
697  GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeparator, true );
698  }
699  rString = sRangeListStr;
700 }
701 
703  OUStringBuffer& rBuf, const ScDocument& rDoc, const ScAddress& rCell,
704  const ScAddress::ExternalInfo& rExtInfo)
705 {
706  if (rExtInfo.mbExternal)
707  {
709  const OUString* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true);
710  if (!pFilePath)
711  return;
712 
713  sal_Unicode cQuote = '\'';
714  rBuf.append(cQuote);
715  rBuf.append(*pFilePath);
716  rBuf.append(cQuote);
717  rBuf.append('#');
718  rBuf.append('$');
720  rBuf.append('.');
721 
722  OUString aAddr(rCell.Format(ScRefFlags::ADDR_ABS, nullptr, rDoc.GetAddressConvention()));
723  rBuf.append(aAddr);
724  }
725  else
726  {
727  OUString aAddr(rCell.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, rDoc.GetAddressConvention()));
728  rBuf.append(aAddr);
729  }
730 }
731 
733  OUStringBuffer& rBuf, const ScDocument& rDoc, const ScAddress& rCell1, const ScAddress& rCell2,
734  const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
735 {
736  if (rExtInfo1.mbExternal)
737  {
738  OSL_ENSURE(rExtInfo2.mbExternal, "2nd address is not external!?");
739  OSL_ENSURE(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
740 
742  const OUString* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true);
743  if (!pFilePath)
744  return;
745 
746  sal_Unicode cQuote = '\'';
747  rBuf.append(cQuote);
748  rBuf.append(*pFilePath);
749  rBuf.append(cQuote);
750  rBuf.append('#');
751  rBuf.append('$');
753  rBuf.append('.');
754 
755  OUString aAddr(rCell1.Format(ScRefFlags::ADDR_ABS, nullptr, rDoc.GetAddressConvention()));
756  rBuf.append(aAddr);
757 
758  rBuf.append(":");
759 
760  if (rExtInfo1.maTabName != rExtInfo2.maTabName)
761  {
762  rBuf.append('$');
764  rBuf.append('.');
765  }
766 
767  aAddr = rCell2.Format(ScRefFlags::ADDR_ABS, nullptr, rDoc.GetAddressConvention());
768  rBuf.append(aAddr);
769  }
770  else
771  {
772  ScRange aRange;
773  aRange.aStart = rCell1;
774  aRange.aEnd = rCell2;
775  OUString aAddr(aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
776  rBuf.append(aAddr);
777  }
778 }
779 
780 void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, const ScDocument& rDoc )
781 {
782  FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
784 
785  OUStringBuffer aRetStr;
786  sal_Int32 nOffset = 0;
787  bool bFirst = true;
788 
789  while (nOffset >= 0)
790  {
791  OUString aToken;
792  GetTokenByOffset(aToken, rXMLRange, nOffset);
793  if (nOffset < 0)
794  break;
795 
796  sal_Int32 nSepPos = IndexOf(aToken, ':', 0);
797  if (nSepPos >= 0)
798  {
799  // Cell range
800  OUString aBeginCell = aToken.copy(0, nSepPos);
801  OUString aEndCell = aToken.copy(nSepPos+1);
802 
803  if (aBeginCell.isEmpty() || aEndCell.isEmpty())
804  // both cell addresses must exist for this to work.
805  continue;
806 
807  sal_Int32 nEndCellDotPos = aEndCell.indexOf('.');
808  if (nEndCellDotPos <= 0)
809  {
810  // initialize buffer with table name...
811  sal_Int32 nDotPos = IndexOf(aBeginCell, '.', 0);
812  OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos);
813 
814  if (nEndCellDotPos == 0)
815  {
816  // workaround for old syntax (probably pre-chart2 age?)
817  // e.g. Sheet1.A1:.B2
818  aBuf.append(aEndCell);
819  }
820  else if (nEndCellDotPos < 0)
821  {
822  // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2).
823  aBuf.append('.');
824  aBuf.append(aEndCell);
825  }
826  aEndCell = aBuf.makeStringAndClear();
827  }
828 
829  ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
830  ScAddress aCell1, aCell2;
831  ScRefFlags nRet = aCell1.Parse(aBeginCell, rDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
832  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO)
833  {
834  // first cell is invalid.
835  if (eConv == FormulaGrammar::CONV_OOO)
836  continue;
837 
838  nRet = aCell1.Parse(aBeginCell, rDoc, eConv, &aExtInfo1);
839  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO)
840  // first cell is really invalid.
841  continue;
842  }
843 
844  nRet = aCell2.Parse(aEndCell, rDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
845  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO)
846  {
847  // second cell is invalid.
848  if (eConv == FormulaGrammar::CONV_OOO)
849  continue;
850 
851  nRet = aCell2.Parse(aEndCell, rDoc, eConv, &aExtInfo2);
852  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO)
853  // second cell is really invalid.
854  continue;
855  }
856 
857  if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
858  // external info inconsistency.
859  continue;
860 
861  // All looks good!
862 
863  if (bFirst)
864  bFirst = false;
865  else
866  aRetStr.append(cSepNew);
867 
868  lcl_appendCellRangeAddress(aRetStr, rDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
869  }
870  else
871  {
872  // Chart always saves ranges using CONV_OOO convention.
873  ScAddress::ExternalInfo aExtInfo;
874  ScAddress aCell;
875  ScRefFlags nRet = aCell.Parse(aToken, rDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
876  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO )
877  {
878  nRet = aCell.Parse(aToken, rDoc, eConv, &aExtInfo);
879  if ((nRet & ScRefFlags::VALID) == ScRefFlags::ZERO)
880  continue;
881  }
882 
883  // Looks good!
884 
885  if (bFirst)
886  bFirst = false;
887  else
888  aRetStr.append(cSepNew);
889 
890  lcl_appendCellAddress(aRetStr, rDoc, aCell, aExtInfo);
891  }
892  }
893 
894  rString = aRetStr.makeStringAndClear();
895 }
896 
897 ScRangeData* ScRangeStringConverter::GetRangeDataFromString(const OUString& rString, const SCTAB nTab, const ScDocument& rDoc)
898 {
899  ScRangeName* pLocalRangeName = rDoc.GetRangeName(nTab);
900  ScRangeData* pData = nullptr;
901  OUString aUpperName = ScGlobal::getCharClassPtr()->uppercase(rString);
902  if(pLocalRangeName)
903  {
904  pData = pLocalRangeName->findByUpperName(aUpperName);
905  }
906  if (!pData)
907  {
908  ScRangeName* pGlobalRangeName = rDoc.GetRangeName();
909  if (pGlobalRangeName)
910  {
911  pData = pGlobalRangeName->findByUpperName(aUpperName);
912  }
913  }
914  return pData;
915 }
916 
918  SCCOL colStart, SCROW rowStart,
919  SCCOL colEnd, SCROW rowEnd ) :
920  nTab ( tab ),
921  nColStart( colStart ), nRowStart( rowStart ),
922  nColEnd ( colEnd ), nRowEnd ( rowEnd )
923 {
924 }
925 
926 bool ScArea::operator==( const ScArea& r ) const
927 {
928  return ( (nTab == r.nTab)
929  && (nColStart == r.nColStart)
930  && (nRowStart == r.nRowStart)
931  && (nColEnd == r.nColEnd)
932  && (nRowEnd == r.nRowEnd) );
933 }
934 
936  pRangeName(rDoc.GetRangeName()),
937  pDBCollection(rDoc.GetDBCollection()),
938  bFirstPass(true)
939 {
940  if (pRangeName)
941  {
942  maRNPos = pRangeName->begin();
943  maRNEnd = pRangeName->end();
944  }
945 }
946 
947 bool ScAreaNameIterator::Next( OUString& rName, ScRange& rRange )
948 {
949  for (;;)
950  {
951  if ( bFirstPass ) // first the area names
952  {
953  if ( pRangeName && maRNPos != maRNEnd )
954  {
955  const ScRangeData& rData = *maRNPos->second;
956  ++maRNPos;
957  bool bValid = rData.IsValidReference(rRange);
958  if (bValid)
959  {
960  rName = rData.GetName();
961  return true; // found
962  }
963  }
964  else
965  {
966  bFirstPass = false;
967  if (pDBCollection)
968  {
970  maDBPos = rDBs.begin();
971  maDBEnd = rDBs.end();
972  }
973  }
974  }
975 
976  if ( !bFirstPass ) // then the DB areas
977  {
978  if (pDBCollection && maDBPos != maDBEnd)
979  {
980  const ScDBData& rData = **maDBPos;
981  ++maDBPos;
982  rData.GetArea(rRange);
983  rName = rData.GetName();
984  return true; // found
985  }
986  else
987  return false; // nothing left
988  }
989  }
990 }
991 
993 {
994  if (rCxt.mnInsertPos <= rAddr.Tab())
995  {
996  rAddr.IncTab(rCxt.mnSheets);
997  }
998 }
999 
1001 {
1002  if (rCxt.mnDeletePos <= rAddr.Tab())
1003  {
1004  rAddr.IncTab(-rCxt.mnSheets);
1005  }
1006 }
1007 
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool Next(OUString &rName, ScRange &rRange)
Definition: rangeutl.cxx:947
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2107
SCCOL nColEnd
Definition: rangeutl.hxx:242
SCCOL nColStart
Definition: rangeutl.hxx:240
static void UpdateInsertTab(ScAddress &rAddr, const sc::RefUpdateInsertTabContext &rCxt)
Definition: rangeutl.cxx:992
sal_Int32 nIndex
SC_DLLPUBLIC ScDBCollection * GetDBCollection() const
Definition: document.hxx:816
ScAddress aStart
Definition: address.hxx:500
SCROW nRowStart
Definition: rangeutl.hxx:241
RutlNameScope
Definition: rangeutl.hxx:36
void IncTab(SCTAB nDelta=1)
Definition: address.hxx:308
SCROW Row() const
Definition: address.hxx:262
static bool GetAddressFromString(ScAddress &rAddress, const OUString &rAddressStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Int32 &nOffset, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
String to Range core.
Definition: rangeutl.cxx:435
static void lcl_appendCellRangeAddress(OUStringBuffer &rBuf, const ScDocument &rDoc, const ScAddress &rCell1, const ScAddress &rCell2, const ScAddress::ExternalInfo &rExtInfo1, const ScAddress::ExternalInfo &rExtInfo2)
Definition: rangeutl.cxx:732
std::unique_ptr< ContentProperties > pData
static void GetStringFromRange(OUString &rString, const ScRange &rRange, const ScDocument *pDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ', bool bAppendStr=false, ScRefFlags nFormatFlags=ScRefFlags::VALID|ScRefFlags::TAB_3D)
bool ConvertSingleRef(const ScDocument &rDoc, const OUString &rRefString, SCTAB nDefTab, ScRefAddress &rRefAddress, const ScAddress::Details &rDetails, ScAddress::ExternalInfo *pExtInfo)
Definition: address.cxx:1491
void SetRelTab(bool bNewRelTab)
Definition: address.hxx:878
SC_DLLPUBLIC ScRangeName * GetRangeName(SCTAB nTab) const
Definition: documen3.cxx:168
ScRangeName * pRangeName
Definition: rangeutl.hxx:251
aBuf
const ContentProperties & rData
ScAddress aEnd
Definition: address.hxx:501
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:489
static bool GetAreaFromString(ScArea &rArea, const OUString &rRangeStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Int32 &nOffset, sal_Unicode cSeparator= ' ')
Definition: rangeutl.cxx:553
static void GetStringFromAddress(OUString &rString, const ScAddress &rAddress, const ScDocument *pDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ', bool bAppendStr=false, ScRefFlags nFormatFlags=ScRefFlags::VALID|ScRefFlags::TAB_3D)
Range to String core.
const OUString * getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal=false)
It returns a pointer to the name of the URI associated with a given external file ID...
ScArea(SCTAB tab=0, SCCOL colStart=0, SCROW rowStart=0, SCCOL colEnd=0, SCROW rowEnd=0)
Definition: rangeutl.cxx:917
sal_uInt16 sal_Unicode
int nCount
SCROW nRowEnd
Definition: rangeutl.hxx:243
SC_DLLPUBLIC bool GetTable(const OUString &rName, SCTAB &rTab) const
Definition: document.cxx:260
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:618
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1144
bool operator==(const ScArea &r) const
Definition: rangeutl.cxx:926
SC_DLLPUBLIC bool HasTable(SCTAB nTab) const
Definition: document.cxx:191
SCTAB Tab() const
Definition: address.hxx:271
SC_DLLPUBLIC const_iterator begin() const
Definition: rangenam.cxx:780
void GetName(OUString &rName) const
Definition: rangenam.hxx:111
static sal_Unicode GetNativeSymbolChar(OpCode eOp)
static sal_Int32 GetTokenCount(const OUString &rString, sal_Unicode cSeparator= ' ')
Definition: rangeutl.cxx:421
static bool GetRangeFromString(ScRange &rRange, const OUString &rRangeStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Int32 &nOffset, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
ocSep
static void GetStringFromArea(OUString &rString, const ScArea &rArea, const ScDocument *pDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator, bool bAppendStr=false, ScRefFlags nFormatFlags=ScRefFlags::VALID|ScRefFlags::TAB_3D)
Definition: rangeutl.cxx:648
static void AssignString(OUString &rString, const OUString &rNewStr, bool bAppendStr, sal_Unicode cSeparator= ' ')
helper methods
Definition: rangeutl.cxx:329
SC_DLLPUBLIC ScRangeData * findByUpperName(const OUString &rName)
Definition: rangenam.cxx:682
SC_DLLPUBLIC const_iterator end() const
Definition: rangenam.cxx:785
static bool MakeArea(const OUString &rAreaStr, ScArea &rArea, const ScDocument &rDoc, SCTAB nTab, ScAddress::Details const &rDetails)
Definition: rangeutl.cxx:36
ScRangeName::const_iterator maRNPos
Definition: rangeutl.hxx:253
SC_DLLPUBLIC void GetSymbol(OUString &rSymbol, const formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT) const
Definition: rangenam.cxx:246
int i
sal_Int16 SCCOL
Definition: types.hxx:22
SC_DLLPUBLIC OUString Format(const ScDocument &rDocument, ScRefFlags nFlags=ScRefFlags::ZERO, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1, bool bFullAddressNotation=false) const
Returns string with formatted cell range from aStart to aEnd, according to provided address conventio...
Definition: address.cxx:2203
static void GetStringFromRangeList(OUString &rString, const ScRangeList *pRangeList, const ScDocument *pDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ')
static bool IsAbsArea(const OUString &rAreaStr, const ScDocument &rDoc, SCTAB nTab, OUString *pCompleteStr, ScRefAddress *pStartPos=nullptr, ScRefAddress *pEndPos=nullptr, ScAddress::Details const &rDetails=ScAddress::detailsOOOa1)
Definition: rangeutl.cxx:169
size_t size() const
Definition: rangelst.hxx:90
static bool IsAbsPos(const OUString &rPosStr, const ScDocument &rDoc, SCTAB nTab, OUString *pCompleteStr, ScRefAddress *pPosTripel=nullptr, ScAddress::Details const &rDetails=ScAddress::detailsOOOa1)
Definition: rangeutl.cxx:208
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
static sal_Int32 IndexOfDifferent(const OUString &rString, sal_Unicode cSearchChar, sal_Int32 nOffset)
Definition: rangeutl.cxx:370
const OUString & GetName() const
Definition: dbdata.hxx:122
static bool IsAbsTabArea(const OUString &rAreaStr, const ScDocument *pDoc, std::unique_ptr< ScArea[]> *ppAreas, sal_uInt16 *pAreaCount, bool bAcceptCellRef=false, ScAddress::Details const &rDetails=ScAddress::detailsOOOa1)
Definition: rangeutl.cxx:86
const SCTAB MAXTAB
Definition: address.hxx:71
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:301
SCCOL Col() const
Definition: address.hxx:267
static bool MakeRangeFromName(const OUString &rName, const ScDocument &rDoc, SCTAB nCurTab, ScRange &rRange, RutlNameScope eScope=RUTL_NAMES, ScAddress::Details const &rDetails=ScAddress::detailsOOOa1)
Definition: rangeutl.cxx:233
ScDBCollection * pDBCollection
Definition: rangeutl.hxx:252
ScDBData * findByUpperName(const OUString &rName)
Definition: dbdata.cxx:1145
ScRangeName::const_iterator maRNEnd
Definition: rangeutl.hxx:254
Stores global named database ranges.
Definition: dbdata.hxx:235
ScDBCollection::NamedDBs::const_iterator maDBPos
Definition: rangeutl.hxx:255
static void AppendTableName(OUStringBuffer &rBuf, const OUString &rTabName)
Definition: rangeutl.cxx:413
sal_Int32 SCROW
Definition: types.hxx:18
ScAreaNameIterator(const ScDocument &rDoc)
Definition: rangeutl.cxx:935
SCROW Row() const
Definition: address.hxx:897
OUString aName
static void UpdateDeleteTab(ScAddress &rAddr, const sc::RefUpdateDeleteTabContext &rCxt)
Definition: rangeutl.cxx:1000
ScDBCollection::NamedDBs::const_iterator maDBEnd
Definition: rangeutl.hxx:256
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1, ScAddress::ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1733
SCCOL Col() const
Definition: address.hxx:893
static SC_DLLPUBLIC const CharClass * getCharClassPtr()
Definition: global.cxx:1010
SC_DLLPUBLIC bool IsValidReference(ScRange &rRef) const
Definition: rangenam.cxx:385
NamedDBs & getNamedDBs()
Definition: dbdata.hxx:315
static bool GetRangeListFromString(ScRangeList &rRangeList, const OUString &rRangeListStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:526
void SetRelCol(bool bNewRelCol)
Definition: address.hxx:870
bool ConvertDoubleRef(const ScDocument &rDoc, const OUString &rRefString, SCTAB nDefTab, ScRefAddress &rStartRefAddress, ScRefAddress &rEndRefAddress, const ScAddress::Details &rDetails, ScAddress::ExternalInfo *pExtInfo)
Definition: address.cxx:1513
static void FillApiRange(css::table::CellRangeAddress &rApiRange, const ScRange &rScRange)
Definition: convuno.hxx:88
SCTAB nTab
Definition: rangeutl.hxx:239
static sal_Int32 IndexOf(const OUString &rString, sal_Unicode cSearchChar, sal_Int32 nOffset, sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:348
SCTAB Tab() const
Definition: address.hxx:901
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1539
sal_Int32 nLength
OUString GetRefString(const ScDocument &rDocument, SCTAB nActTab, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1) const
Definition: address.cxx:2511
ScRefFlags
Definition: address.hxx:145
static void lcl_appendCellAddress(OUStringBuffer &rBuf, const ScDocument &rDoc, const ScAddress &rCell, const ScAddress::ExternalInfo &rExtInfo)
Definition: rangeutl.cxx:702
static ScRangeData * GetRangeDataFromString(const OUString &rString, const SCTAB nTab, const ScDocument &rDoc)
String to RangeData core.
Definition: rangeutl.cxx:897
static void GetStringFromXMLRangeString(OUString &rString, const OUString &rXMLRange, const ScDocument &rDoc)
XML Range to Calc Range.
Definition: rangeutl.cxx:780
static void CheckTabQuotes(OUString &aTabName, const formula::FormulaGrammar::AddressConvention eConv=formula::FormulaGrammar::CONV_OOO)
all
Definition: compiler.cxx:1933
static void GetTokenByOffset(OUString &rToken, const OUString &rString, sal_Int32 &nOffset, sal_Unicode cSeparator= ' ', sal_Unicode cQuote= '\'')
Definition: rangeutl.cxx:388
static void CutPosString(const OUString &theAreaStr, OUString &thePosStr)
Definition: rangeutl.cxx:69
sal_Int16 SCTAB
Definition: types.hxx:23
void SetRelRow(bool bNewRelRow)
Definition: address.hxx:874