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