LibreOffice Module sc (master)  1
rangelst.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 <stdlib.h>
22 #include <sal/log.hxx>
23 
24 #include <rangelst.hxx>
25 #include <document.hxx>
26 #include <refupdat.hxx>
27 #include <compiler.hxx>
28 #include <algorithm>
29 #include <memory>
30 
31 using ::std::vector;
32 using ::std::find_if;
33 using ::std::for_each;
34 using ::formula::FormulaGrammar;
35 
36 namespace {
37 
38 template<typename T>
39 class FindEnclosingRange
40 {
41 public:
42  explicit FindEnclosingRange(const T& rTest) : mrTest(rTest) {}
43  bool operator() (const ScRange & rRange) const
44  {
45  return rRange.In(mrTest);
46  }
47 private:
48  const T& mrTest;
49 };
50 
51 template<typename T>
52 class FindRangeIn
53 {
54 public:
55  FindRangeIn(const T& rTest) : mrTest(rTest) {}
56  bool operator() (const ScRange& rRange) const
57  {
58  return mrTest.In(rRange);
59  }
60 private:
61  const T& mrTest;
62 };
63 
64 template<typename T>
65 class FindIntersectingRange
66 {
67 public:
68  explicit FindIntersectingRange(const T& rTest) : mrTest(rTest) {}
69  bool operator() (const ScRange & rRange) const
70  {
71  return rRange.Intersects(mrTest);
72  }
73 private:
74  const T& mrTest;
75 };
76 
77 class CountCells
78 {
79 public:
80  CountCells() : mnCellCount(0) {}
81 
82  void operator() (const ScRange & r)
83  {
84  mnCellCount +=
85  size_t(r.aEnd.Col() - r.aStart.Col() + 1)
86  * size_t(r.aEnd.Row() - r.aStart.Row() + 1)
87  * size_t(r.aEnd.Tab() - r.aStart.Tab() + 1);
88  }
89 
90  size_t getCellCount() const { return mnCellCount; }
91 
92 private:
93  size_t mnCellCount;
94 };
95 
96 
97 }
98 
99 // ScRangeList
101 {
102 }
103 
104 ScRefFlags ScRangeList::Parse( const OUString& rStr, const ScDocument& rDoc,
106  SCTAB nDefaultTab, sal_Unicode cDelimiter )
107 {
108  if ( !rStr.isEmpty() )
109  {
110  if (!cDelimiter)
112 
113  ScRefFlags nResult = ~ScRefFlags::ZERO; // set all bits
114  ScRange aRange;
115  const SCTAB nTab = nDefaultTab;
116 
117  sal_Int32 nPos = 0;
118  do
119  {
120  const OUString aOne = rStr.getToken( 0, cDelimiter, nPos );
121  aRange.aStart.SetTab( nTab ); // default tab if not specified
122  ScRefFlags nRes = aRange.ParseAny( aOne, rDoc, eConv );
124  ScRefFlags nTmp1 = nRes & ScRefFlags::BITS;
125  ScRefFlags nTmp2 = nRes & nEndRangeBits;
126  // If we have a valid single range with
127  // any of the address bits we are interested in
128  // set - set the equiv end range bits
129  if ( (nRes & ScRefFlags::VALID ) && (nTmp1 != ScRefFlags::ZERO) && ( nTmp2 != nEndRangeBits ) )
130  applyStartToEndFlags(nRes, nTmp1);
131 
132  if ( nRes & ScRefFlags::VALID )
133  push_back( aRange );
134  nResult &= nRes; // all common bits are preserved
135  }
136  while (nPos >= 0);
137 
138  return nResult; // ScRefFlags::VALID set when all are OK
139  }
140  else
141  return ScRefFlags::ZERO;
142 }
143 
144 void ScRangeList::Format( OUString& rStr, ScRefFlags nFlags, const ScDocument& rDoc,
146  sal_Unicode cDelimiter, bool bFullAddressNotation ) const
147 {
148  if (!cDelimiter)
150 
151  OUStringBuffer aBuf;
152  bool bFirst = true;
153  for( auto const & r : maRanges)
154  {
155  if (bFirst)
156  bFirst = false;
157  else
158  aBuf.append(OUStringChar(cDelimiter));
159  aBuf.append(r.Format(rDoc, nFlags, eConv, bFullAddressNotation));
160  }
161  rStr = aBuf.makeStringAndClear();
162 }
163 
164 void ScRangeList::Join( const ScRange& rNewRange, bool bIsInList )
165 {
166  if ( maRanges.empty() )
167  {
168  push_back( rNewRange );
169  return ;
170  }
171 
172  // One common usage is to join ranges that actually are top to bottom
173  // appends but the caller doesn't exactly know about it, e.g. when invoked
174  // by ScMarkData::FillRangeListWithMarks(), check for this special case
175  // first and speed up things by not looping over all ranges for each range
176  // to be joined. We don't remember the exact encompassing range that would
177  // have to be updated on refupdates and insertions and deletions, instead
178  // remember just the maximum row used, even independently of the sheet.
179  // This satisfies most use cases.
180 
181  if (!bIsInList)
182  {
183  const SCROW nRow1 = rNewRange.aStart.Row();
184  if (nRow1 > mnMaxRowUsed + 1)
185  {
186  push_back( rNewRange );
187  return;
188  }
189  else if (nRow1 == mnMaxRowUsed + 1)
190  {
191  // Check if we can simply enlarge the last range.
192  ScRange & rLast = maRanges.back();
193  if (rLast.aEnd.Row() + 1 == nRow1 &&
194  rLast.aStart.Col() == rNewRange.aStart.Col() && rLast.aEnd.Col() == rNewRange.aEnd.Col() &&
195  rLast.aStart.Tab() == rNewRange.aStart.Tab() && rLast.aEnd.Tab() == rNewRange.aEnd.Tab())
196  {
197  const SCROW nRow2 = rNewRange.aEnd.Row();
198  rLast.aEnd.SetRow( nRow2 );
199  mnMaxRowUsed = nRow2;
200  return;
201  }
202  }
203  }
204 
205  bool bJoinedInput = false;
206  const ScRange* pOver = &rNewRange;
207 
208 Label_Range_Join:
209 
210  assert(pOver);
211  const SCCOL nCol1 = pOver->aStart.Col();
212  const SCROW nRow1 = pOver->aStart.Row();
213  const SCCOL nTab1 = pOver->aStart.Tab();
214  const SCCOL nCol2 = pOver->aEnd.Col();
215  const SCROW nRow2 = pOver->aEnd.Row();
216  const SCCOL nTab2 = pOver->aEnd.Tab();
217 
218  size_t nOverPos = std::numeric_limits<size_t>::max();
219  for (size_t i = 0; i < maRanges.size(); ++i)
220  {
221  ScRange & rRange = maRanges[i];
222  if ( &rRange == pOver )
223  {
224  nOverPos = i;
225  continue; // the same one, continue with the next
226  }
227  bool bJoined = false;
228  if ( rRange.In( *pOver ) )
229  { // range pOver included in or identical to range p
230  // XXX if we never used Append() before Join() we could remove
231  // pOver and end processing, but it is not guaranteed and there can
232  // be duplicates.
233  if ( bIsInList )
234  bJoined = true; // do away with range pOver
235  else
236  { // that was all then
237  bJoinedInput = true; // don't append
238  break; // for
239  }
240  }
241  else if ( pOver->In( rRange ) )
242  { // range rRange included in range pOver, make pOver the new range
243  rRange = *pOver;
244  bJoined = true;
245  }
246  if ( !bJoined && rRange.aStart.Tab() == nTab1 && rRange.aEnd.Tab() == nTab2 )
247  { // 2D
248  if ( rRange.aStart.Col() == nCol1 && rRange.aEnd.Col() == nCol2 )
249  {
250  if ( rRange.aStart.Row() <= nRow2+1 &&
251  rRange.aStart.Row() >= nRow1 )
252  { // top
253  rRange.aStart.SetRow( nRow1 );
254  bJoined = true;
255  }
256  else if ( rRange.aEnd.Row() >= nRow1-1 &&
257  rRange.aEnd.Row() <= nRow2 )
258  { // bottom
259  rRange.aEnd.SetRow( nRow2 );
260  bJoined = true;
261  }
262  }
263  else if ( rRange.aStart.Row() == nRow1 && rRange.aEnd.Row() == nRow2 )
264  {
265  if ( rRange.aStart.Col() <= nCol2+1 &&
266  rRange.aStart.Col() >= nCol1 )
267  { // left
268  rRange.aStart.SetCol( nCol1 );
269  bJoined = true;
270  }
271  else if ( rRange.aEnd.Col() >= nCol1-1 &&
272  rRange.aEnd.Col() <= nCol2 )
273  { // right
274  rRange.aEnd.SetCol( nCol2 );
275  bJoined = true;
276  }
277  }
278  }
279  if ( bJoined )
280  {
281  if ( bIsInList )
282  { // delete range pOver within the list
283  if (nOverPos != std::numeric_limits<size_t>::max())
284  {
285  Remove(nOverPos);
286  if (nOverPos < i)
287  --i;
288  }
289  else
290  {
291  for (size_t nOver = 0, nRanges = maRanges.size(); nOver < nRanges; ++nOver)
292  {
293  if (&maRanges[nOver] == pOver)
294  {
295  Remove(nOver);
296  break;
297  }
298  }
299  }
300  }
301  bJoinedInput = true;
302  pOver = &maRanges[i];
303  bIsInList = true;
304  goto Label_Range_Join;
305  }
306  }
307  if ( !bIsInList && !bJoinedInput )
308  push_back( rNewRange );
309 }
310 
312 {
313  if ( maRanges.empty() )
314  {
315  push_back( rNewRange );
316  return ;
317  }
318 
319  // One common usage is to join ranges that actually are top to bottom
320  // appends but the caller doesn't exactly know about it, e.g. when invoked
321  // by ScMarkData::FillRangeListWithMarks(), check for this special case
322  // first and speed up things by not looping over all ranges for each range
323  // to be joined. We don't remember the exact encompassing range that would
324  // have to be updated on refupdates and insertions and deletions, instead
325  // remember just the maximum row used, even independently of the sheet.
326  // This satisfies most use cases.
327 
328  const SCROW nRow1 = rNewRange.aStart.Row();
329  if (nRow1 > mnMaxRowUsed + 1)
330  {
331  push_back( rNewRange );
332  return;
333  }
334 
335  // scan backwards 2 rows to see if we can merge with anything
336  auto it = maRanges.rbegin();
337  while (it != maRanges.rend() && it->aStart.Row() >= (rNewRange.aStart.Row() - 2))
338  {
339  // Check if we can simply enlarge this range.
340  ScRange & rLast = *it;
341  if (rLast.aEnd.Row() + 1 == nRow1 &&
342  rLast.aStart.Col() == rNewRange.aStart.Col() && rLast.aEnd.Col() == rNewRange.aEnd.Col() &&
343  rLast.aStart.Tab() == rNewRange.aStart.Tab() && rLast.aEnd.Tab() == rNewRange.aEnd.Tab())
344  {
345  const SCROW nRow2 = rNewRange.aEnd.Row();
346  rLast.aEnd.SetRow( nRow2 );
347  mnMaxRowUsed = std::max(mnMaxRowUsed, nRow2);
348  return;
349  }
350  ++it;
351  }
352 
353  push_back( rNewRange );
354 }
355 
356 bool ScRangeList::operator==( const ScRangeList& r ) const
357 {
358  if ( this == &r )
359  return true;
360 
361  return maRanges == r.maRanges;
362 }
363 
364 bool ScRangeList::operator!=( const ScRangeList& r ) const
365 {
366  return !operator==( r );
367 }
368 
370  UpdateRefMode eUpdateRefMode,
371  const ScDocument* pDoc,
372  const ScRange& rWhere,
373  SCCOL nDx,
374  SCROW nDy,
375  SCTAB nDz
376 )
377 {
378  if (maRanges.empty())
379  // No ranges to update. Bail out.
380  return false;
381 
382  bool bChanged = false;
383  SCCOL nCol1;
384  SCROW nRow1;
385  SCTAB nTab1;
386  SCCOL nCol2;
387  SCROW nRow2;
388  SCTAB nTab2;
389  rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
390 
391  if(eUpdateRefMode == URM_INSDEL)
392  {
393  // right now this only works for nTab1 == nTab2
394  if(nTab1 == nTab2)
395  {
396  if(nDx < 0)
397  {
398  bChanged = DeleteArea(nCol1+nDx, nRow1, nTab1, nCol1-1, nRow2, nTab2);
399  }
400  if(nDy < 0)
401  {
402  bChanged = DeleteArea(nCol1, nRow1+nDy, nTab1, nCol2, nRow1-1, nTab2);
403  }
404  SAL_WARN_IF(nDx < 0 && nDy < 0, "sc", "nDx and nDy are negative, check why");
405  }
406  }
407 
408  if(maRanges.empty())
409  return true;
410 
411  for (auto& rR : maRanges)
412  {
413  SCCOL theCol1;
414  SCROW theRow1;
415  SCTAB theTab1;
416  SCCOL theCol2;
417  SCROW theRow2;
418  SCTAB theTab2;
419  rR.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
420  if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
421  nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
422  nDx, nDy, nDz,
423  theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
424  != UR_NOTHING )
425  {
426  bChanged = true;
427  rR.aStart.Set( theCol1, theRow1, theTab1 );
428  rR.aEnd.Set( theCol2, theRow2, theTab2 );
429  if (mnMaxRowUsed < theRow2)
430  mnMaxRowUsed = theRow2;
431  }
432  }
433 
434  if(eUpdateRefMode == URM_INSDEL)
435  {
436  if( nDx < 0 || nDy < 0 )
437  {
438  size_t n = maRanges.size();
439  for(size_t i = n-1; i > 0;)
440  {
441  Join(maRanges[i], true);
442  // Join() may merge and remove even more than one item, protect against it.
443  if(i >= maRanges.size())
444  i = maRanges.size()-1;
445  else
446  --i;
447  }
448  }
449  }
450 
451  return bChanged;
452 }
453 
454 void ScRangeList::InsertRow( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize )
455 {
456  std::vector<ScRange> aNewRanges;
457  for(const auto & rRange : maRanges)
458  {
459  if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab)
460  {
461  if(rRange.aEnd.Row() == nRowPos - 1 && (nColStart <= rRange.aEnd.Col() || nColEnd >= rRange.aStart.Col()))
462  {
463  SCCOL nNewRangeStartCol = std::max<SCCOL>(nColStart, rRange.aStart.Col());
464  SCCOL nNewRangeEndCol = std::min<SCCOL>(nColEnd, rRange.aEnd.Col());
465  SCROW nNewRangeStartRow = rRange.aEnd.Row() + 1;
466  SCROW nNewRangeEndRow = nRowPos + nSize - 1;
467  aNewRanges.emplace_back(nNewRangeStartCol, nNewRangeStartRow, nTab, nNewRangeEndCol,
468  nNewRangeEndRow, nTab);
469  if (mnMaxRowUsed < nNewRangeEndRow)
470  mnMaxRowUsed = nNewRangeEndRow;
471  }
472  }
473  }
474 
475  for(const auto & rRange : aNewRanges)
476  {
477  if(!rRange.IsValid())
478  continue;
479 
480  Join(rRange);
481  }
482 }
483 
484 void ScRangeList::InsertCol( SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize )
485 {
486  std::vector<ScRange> aNewRanges;
487  for(const auto & rRange : maRanges)
488  {
489  if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab)
490  {
491  if(rRange.aEnd.Col() == nColPos - 1 && (nRowStart <= rRange.aEnd.Row() || nRowEnd >= rRange.aStart.Row()))
492  {
493  SCROW nNewRangeStartRow = std::max<SCROW>(nRowStart, rRange.aStart.Row());
494  SCROW nNewRangeEndRow = std::min<SCROW>(nRowEnd, rRange.aEnd.Row());
495  SCCOL nNewRangeStartCol = rRange.aEnd.Col() + 1;
496  SCCOL nNewRangeEndCol = nColPos + nSize - 1;
497  aNewRanges.emplace_back(nNewRangeStartCol, nNewRangeStartRow, nTab, nNewRangeEndCol,
498  nNewRangeEndRow, nTab);
499  }
500  }
501  }
502 
503  for(const auto & rRange : aNewRanges)
504  {
505  if(!rRange.IsValid())
506  continue;
507 
508  Join(rRange);
509  }
510 }
511 
513 {
514  std::vector<ScRange> aNewRanges;
515  for(const auto & rRange : maRanges)
516  {
517  if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab)
518  {
519  if(rRange.aEnd.Col() == nCol - 1)
520  {
521  SCCOL nNewRangeStartCol = rRange.aEnd.Col() + 1;
522  SCCOL nNewRangeEndCol = nCol;
523  aNewRanges.emplace_back(nNewRangeStartCol, rRange.aStart.Row(), nTab, nNewRangeEndCol,
524  rRange.aEnd.Row(), nTab);
525  }
526  }
527  }
528 
529  for(const auto & rRange : aNewRanges)
530  {
531  if(!rRange.IsValid())
532  continue;
533 
534  Join(rRange);
535  }
536 }
537 
538 namespace {
539 
559 template<typename X, typename Y>
560 bool checkForOneRange(
561  X nDeleteX1, X nDeleteX2, Y nDeleteY1, Y nDeleteY2, X nX1, X nX2, Y nY1, Y nY2)
562 {
563  return nDeleteX1 <= nX1 && nX2 <= nDeleteX2 && (nDeleteY1 <= nY1 || nY2 <= nDeleteY2);
564 }
565 
566 bool handleOneRange( const ScRange& rDeleteRange, ScRange& r )
567 {
568  const ScAddress& rDelStart = rDeleteRange.aStart;
569  const ScAddress& rDelEnd = rDeleteRange.aEnd;
570  ScAddress aPStart = r.aStart;
571  ScAddress aPEnd = r.aEnd;
572  SCCOL nDeleteCol1 = rDelStart.Col();
573  SCCOL nDeleteCol2 = rDelEnd.Col();
574  SCROW nDeleteRow1 = rDelStart.Row();
575  SCROW nDeleteRow2 = rDelEnd.Row();
576  SCCOL nCol1 = aPStart.Col();
577  SCCOL nCol2 = aPEnd.Col();
578  SCROW nRow1 = aPStart.Row();
579  SCROW nRow2 = aPEnd.Row();
580 
581  if (checkForOneRange(nDeleteCol1, nDeleteCol2, nDeleteRow1, nDeleteRow2, nCol1, nCol2, nRow1, nRow2))
582  {
583  // Deleting range fully overlaps the column range. Adjust the row span.
584  if (nDeleteRow1 <= nRow1)
585  {
586  // +------+
587  // |xxxxxx|
588  // +------+
589  // | |
590  // +------+ (xxx) = deleted region
591 
592  r.aStart.SetRow(nDeleteRow1+1);
593  return true;
594  }
595  else if (nRow2 <= nDeleteRow2)
596  {
597  // +------+
598  // | |
599  // +------+
600  // |xxxxxx|
601  // +------+ (xxx) = deleted region
602 
603  r.aEnd.SetRow(nDeleteRow1-1);
604  return true;
605  }
606  }
607  else if (checkForOneRange(nDeleteRow1, nDeleteRow2, nDeleteCol1, nDeleteCol2, nRow1, nRow2, nCol1, nCol2))
608  {
609  // Deleting range fully overlaps the row range. Adjust the column span.
610  if (nDeleteCol1 <= nCol1)
611  {
612  // +--+--+
613  // |xx| |
614  // |xx| |
615  // |xx| |
616  // +--+--+ (xxx) = deleted region
617 
618  r.aStart.SetCol(nDeleteCol2+1);
619  return true;
620  }
621  else if (nCol2 <= nDeleteCol2)
622  {
623  // +--+--+
624  // | |xx|
625  // | |xx|
626  // | |xx|
627  // +--+--+ (xxx) = deleted region
628 
629  r.aEnd.SetCol(nDeleteCol1-1);
630  return true;
631  }
632  }
633  return false;
634 }
635 
636 bool handleTwoRanges( const ScRange& rDeleteRange, ScRange& r, std::vector<ScRange>& rNewRanges )
637 {
638  const ScAddress& rDelStart = rDeleteRange.aStart;
639  const ScAddress& rDelEnd = rDeleteRange.aEnd;
640  ScAddress aPStart = r.aStart;
641  ScAddress aPEnd = r.aEnd;
642  SCCOL nDeleteCol1 = rDelStart.Col();
643  SCCOL nDeleteCol2 = rDelEnd.Col();
644  SCROW nDeleteRow1 = rDelStart.Row();
645  SCROW nDeleteRow2 = rDelEnd.Row();
646  SCCOL nCol1 = aPStart.Col();
647  SCCOL nCol2 = aPEnd.Col();
648  SCROW nRow1 = aPStart.Row();
649  SCROW nRow2 = aPEnd.Row();
650  SCTAB nTab = aPStart.Tab();
651 
652  if (nCol1 < nDeleteCol1 && nDeleteCol1 <= nCol2 && nCol2 <= nDeleteCol2)
653  {
654  // column deleted : |-------|
655  // column original: |-------|
656  if (nRow1 < nDeleteRow1 && nDeleteRow1 <= nRow2 && nRow2 <= nDeleteRow2)
657  {
658  // row deleted: |------|
659  // row original: |------|
660  //
661  // +-------+
662  // | 1 |
663  // +---+---+---+
664  // | 2 |xxxxxxx|
665  // +---+xxxxxxx|
666  // |xxxxxxx|
667  // +-------+ (xxx) deleted region
668 
669  ScRange aNewRange( nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nRow2, nTab ); // 2
670  rNewRanges.push_back(aNewRange);
671 
672  r.aEnd.SetRow(nDeleteRow1-1); // 1
673  return true;
674  }
675  else if (nRow1 <= nDeleteRow2 && nDeleteRow2 < nRow2 && nDeleteRow1 <= nRow1)
676  {
677  // row deleted: |------|
678  // row original: |------|
679  //
680  // +-------+
681  // |xxxxxxx|
682  // +---+xxxxxxx|
683  // | 1 |xxxxxxx|
684  // +---+---+---+
685  // | 2 | (xxx) deleted region
686  // +-------+
687 
688  ScRange aNewRange( aPStart, ScAddress(nDeleteCol1-1, nRow2, nTab) ); // 1
689  rNewRanges.push_back(aNewRange);
690 
691  r.aStart.SetRow(nDeleteRow2+1); // 2
692  return true;
693  }
694  }
695  else if (nCol1 <= nDeleteCol2 && nDeleteCol2 < nCol2 && nDeleteCol1 <= nCol1)
696  {
697  // column deleted : |-------|
698  // column original: |-------|
699  if (nRow1 < nDeleteRow1 && nDeleteRow1 <= nRow2 && nRow2 <= nDeleteRow2)
700  {
701  // row deleted: |------|
702  // row original: |------|
703  //
704  // +-------+
705  // | 1 |
706  // +-------+---+
707  // |xxxxxxx| 2 |
708  // |xxxxxxx+---+
709  // |xxxxxxx|
710  // +-------+
711  // (xxx) deleted region
712 
713  ScRange aNewRange( ScAddress( nDeleteCol2+1, nDeleteRow1, nTab ), aPEnd ); // 2
714  rNewRanges.push_back(aNewRange);
715 
716  r.aEnd.SetRow(nDeleteRow1-1); // 1
717  return true;
718  }
719  else if (nRow1 <= nDeleteRow2 && nDeleteRow2 < nRow2 && nDeleteRow1 <= nRow1)
720  {
721  // row deleted: |-------|
722  // row original: |--------|
723  //
724  // +-------+
725  // |xxxxxxx|
726  // |xxxxxxx+---+
727  // |xxxxxxx| 1 |
728  // +-------+---+
729  // | 2 |
730  // +-------+ (xxx) deleted region
731 
732  ScRange aNewRange(nDeleteCol2+1, nRow1, nTab, nCol2, nDeleteRow2, nTab); // 1
733  rNewRanges.push_back(aNewRange);
734 
735  r.aStart.SetRow(nDeleteRow2+1); // 2
736  return true;
737  }
738  }
739  else if (nRow1 < nDeleteRow1 && nDeleteRow2 < nRow2 && nDeleteCol1 <= nCol1 && nCol2 <= nDeleteCol2)
740  {
741  // +--------+
742  // | 1 |
743  // +--------+
744  // |xxxxxxxx| (xxx) deleted region
745  // +--------+
746  // | 2 |
747  // +--------+
748 
749  ScRange aNewRange( aPStart, ScAddress(nCol2, nDeleteRow1-1, nTab) ); // 1
750  rNewRanges.push_back(aNewRange);
751 
752  r.aStart.SetRow(nDeleteRow2+1); // 2
753  return true;
754  }
755  else if (nCol1 < nDeleteCol1 && nDeleteCol2 < nCol2 && nDeleteRow1 <= nRow1 && nRow2 <= nDeleteRow2)
756  {
757  // +---+-+---+
758  // | |x| |
759  // | |x| |
760  // | 1 |x| 2 | (xxx) deleted region
761  // | |x| |
762  // | |x| |
763  // +---+-+---+
764 
765  ScRange aNewRange( aPStart, ScAddress(nDeleteCol1-1, nRow2, nTab) ); // 1
766  rNewRanges.push_back(aNewRange);
767 
768  r.aStart.SetCol(nDeleteCol2+1); // 2
769  return true;
770  }
771 
772  return false;
773 }
774 
799 template<typename X, typename Y>
800 bool checkForThreeRanges(
801  X nDeleteX1, X nDeleteX2, Y nDeleteY1, Y nDeleteY2, X nX1, X nX2, Y nY1, Y nY2)
802 {
803  if (nX1 <= nDeleteX1 && nX2 <= nDeleteX2 && nY1 < nDeleteY1 && nDeleteY2 < nY2)
804  return true;
805 
806  if (nDeleteX1 <= nX1 && nDeleteX2 <= nX2 && nY1 < nDeleteY1 && nDeleteY2 < nY2)
807  return true;
808 
809  return false;
810 }
811 
812 bool handleThreeRanges( const ScRange& rDeleteRange, ScRange& r, std::vector<ScRange>& rNewRanges )
813 {
814  const ScAddress& rDelStart = rDeleteRange.aStart;
815  const ScAddress& rDelEnd = rDeleteRange.aEnd;
816  ScAddress aPStart = r.aStart;
817  ScAddress aPEnd = r.aEnd;
818  SCCOL nDeleteCol1 = rDelStart.Col();
819  SCCOL nDeleteCol2 = rDelEnd.Col();
820  SCROW nDeleteRow1 = rDelStart.Row();
821  SCROW nDeleteRow2 = rDelEnd.Row();
822  SCCOL nCol1 = aPStart.Col();
823  SCCOL nCol2 = aPEnd.Col();
824  SCROW nRow1 = aPStart.Row();
825  SCROW nRow2 = aPEnd.Row();
826  SCTAB nTab = aPStart.Tab();
827 
828  if (checkForThreeRanges(nDeleteCol1, nDeleteCol2, nDeleteRow1, nDeleteRow2, nCol1, nCol2, nRow1, nRow2))
829  {
830  if (nCol1 < nDeleteCol1)
831  {
832  // +---+------+
833  // | | 2 |
834  // | +------+---+
835  // | 1 |xxxxxxxxxx|
836  // | +------+---+
837  // | | 3 |
838  // +---+------+
839 
840  ScRange aNewRange(nDeleteCol1, nRow1, nTab, nCol2, nDeleteRow1-1, nTab); // 2
841  rNewRanges.push_back(aNewRange);
842 
843  aNewRange = ScRange(ScAddress(nDeleteCol1, nDeleteRow2+1, nTab), aPEnd); // 3
844  rNewRanges.push_back(aNewRange);
845 
846  r.aEnd.SetCol(nDeleteCol1-1); // 1
847  }
848  else
849  {
850  // +------+---+
851  // | 1 | |
852  // +---+------+ |
853  // |xxxxxxxxxx| 2 |
854  // +---+------+ |
855  // | 3 | |
856  // +------+---+
857 
858  ScRange aNewRange(aPStart, ScAddress(nDeleteCol2, nDeleteRow1-1, nTab)); // 1
859  rNewRanges.push_back(aNewRange);
860 
861  aNewRange = ScRange(nCol1, nDeleteRow2+1, nTab, nDeleteCol2, nRow2, nTab); // 3
862  rNewRanges.push_back(aNewRange);
863 
864  r.aStart.SetCol(nDeleteCol2+1); // 2
865  }
866  return true;
867  }
868  else if (checkForThreeRanges(nDeleteRow1, nDeleteRow2, nDeleteCol1, nDeleteCol2, nRow1, nRow2, nCol1, nCol2))
869  {
870  if (nRow1 < nDeleteRow1)
871  {
872  // +----------+
873  // | 1 |
874  // +---+--+---+
875  // | |xx| |
876  // | 2 |xx| 3 |
877  // | |xx| |
878  // +---+xx+---+
879  // |xx|
880  // +--+
881 
882  ScRange aNewRange(nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nRow2, nTab); // 2
883  rNewRanges.push_back( aNewRange );
884 
885  aNewRange = ScRange(ScAddress(nDeleteCol2+1, nDeleteRow1, nTab), aPEnd); // 3
886  rNewRanges.push_back( aNewRange );
887 
888  r.aEnd.SetRow(nDeleteRow1-1); // 1
889  }
890  else
891  {
892  // +--+
893  // |xx|
894  // +---+xx+---+
895  // | 1 |xx| 2 |
896  // | |xx| |
897  // +---+--+---+
898  // | 3 |
899  // +----------+
900 
901  ScRange aNewRange(aPStart, ScAddress(nDeleteCol1-1, nDeleteRow2, nTab)); // 1
902  rNewRanges.push_back(aNewRange);
903 
904  aNewRange = ScRange(nDeleteCol2+1, nRow1, nTab, nCol2, nDeleteRow2, nTab); // 2
905  rNewRanges.push_back( aNewRange );
906 
907  r.aStart.SetRow(nDeleteRow2+1); // 3
908  }
909  return true;
910  }
911 
912  return false;
913 }
914 
915 bool handleFourRanges( const ScRange& rDelRange, ScRange& r, std::vector<ScRange>& rNewRanges )
916 {
917  const ScAddress& rDelStart = rDelRange.aStart;
918  const ScAddress& rDelEnd = rDelRange.aEnd;
919  ScAddress aPStart = r.aStart;
920  ScAddress aPEnd = r.aEnd;
921  SCCOL nDeleteCol1 = rDelStart.Col();
922  SCCOL nDeleteCol2 = rDelEnd.Col();
923  SCROW nDeleteRow1 = rDelStart.Row();
924  SCROW nDeleteRow2 = rDelEnd.Row();
925  SCCOL nCol1 = aPStart.Col();
926  SCCOL nCol2 = aPEnd.Col();
927  SCROW nRow1 = aPStart.Row();
928  SCROW nRow2 = aPEnd.Row();
929  SCTAB nTab = aPStart.Tab();
930 
931  if (nCol1 < nDeleteCol1 && nDeleteCol2 < nCol2 && nRow1 < nDeleteRow1 && nDeleteRow2 < nRow2)
932  {
933 
934  // +---------------+
935  // | 1 |
936  // +---+-------+---+
937  // | |xxxxxxx| |
938  // | 2 |xxxxxxx| 3 |
939  // | |xxxxxxx| |
940  // +---+-------+---+
941  // | 4 |
942  // +---------------+
943 
944  ScRange aNewRange(ScAddress(nCol1, nDeleteRow2+1, nTab), aPEnd); // 4
945  rNewRanges.push_back( aNewRange );
946 
947  aNewRange = ScRange(nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nDeleteRow2, nTab); // 2
948  rNewRanges.push_back( aNewRange );
949 
950  aNewRange = ScRange(nDeleteCol2+1, nDeleteRow1, nTab, nCol2, nDeleteRow2, nTab); // 3
951  rNewRanges.push_back( aNewRange );
952 
953  r.aEnd.SetRow(nDeleteRow1-1); // 1
954 
955  return true;
956  }
957 
958  return false;
959 }
960 
961 }
962 
963 bool ScRangeList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
964  SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
965 {
966  bool bChanged = false;
967  ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
968  for(size_t i = 0; i < maRanges.size();)
969  {
970  if(FindRangeIn< ScRange >(aRange)(maRanges[i]))
971  {
972  Remove(i);
973  bChanged = true;
974  }
975  else
976  ++i;
977  }
978 
979  std::vector<ScRange> aNewRanges;
980 
981  for(auto & rRange : maRanges)
982  {
983  // we have two basic cases here:
984  // 1. Delete area and pRange intersect
985  // 2. Delete area and pRange are not intersecting
986  // checking for 2 and if true skip this range
987  if(!rRange.Intersects(aRange))
988  continue;
989 
990  // We get between 1 and 4 ranges from the difference of the first with the second
991 
992  // X either Col or Row and Y then the opposite
993  // r = deleteRange, p = entry from ScRangeList
994 
995  // getting exactly one range is the simple case
996  // r.aStart.X() <= p.aStart.X() && r.aEnd.X() >= p.aEnd.X()
997  // && ( r.aStart.Y() <= p.aStart.Y() || r.aEnd.Y() >= r.aEnd.Y() )
998  if(handleOneRange( aRange, rRange ))
999  {
1000  bChanged = true;
1001  continue;
1002  }
1003 
1004  // getting two ranges
1005  // r.aStart.X()
1006  else if(handleTwoRanges( aRange, rRange, aNewRanges ))
1007  {
1008  bChanged = true;
1009  continue;
1010  }
1011 
1012  // getting 3 ranges
1013  // r.aStart.X() > p.aStart.X() && r.aEnd.X() >= p.aEnd.X()
1014  // && r.aStart.Y() > p.aStart.Y() && r.aEnd.Y() < p.aEnd.Y()
1015  // or
1016  // r.aStart.X() <= p.aStart.X() && r.aEnd.X() < p.aEnd.X()
1017  // && r.aStart.Y() > p.aStart.Y() && r.aEnd.Y() < p.aEnd.Y()
1018  else if(handleThreeRanges( aRange, rRange, aNewRanges ))
1019  {
1020  bChanged = true;
1021  continue;
1022  }
1023 
1024  // getting 4 ranges
1025  // r.aStart.X() > p.aStart.X() && r.aEnd().X() < p.aEnd.X()
1026  // && r.aStart.Y() > p.aStart.Y() && r.aEnd().Y() < p.aEnd.Y()
1027  else if(handleFourRanges( aRange, rRange, aNewRanges ))
1028  {
1029  bChanged = true;
1030  continue;
1031  }
1032  }
1033  for(const auto & rRange : aNewRanges)
1034  Join(rRange);
1035 
1036  return bChanged;
1037 }
1038 
1039 const ScRange* ScRangeList::Find( const ScAddress& rAdr ) const
1040 {
1041  auto itr = find_if(
1042  maRanges.cbegin(), maRanges.cend(), FindEnclosingRange<ScAddress>(rAdr));
1043  return itr == maRanges.end() ? nullptr : &*itr;
1044 }
1045 
1047 {
1048  auto itr = find_if(
1049  maRanges.begin(), maRanges.end(), FindEnclosingRange<ScAddress>(rAdr));
1050  return itr == maRanges.end() ? nullptr : &*itr;
1051 }
1052 
1053 ScRangeList::ScRangeList() : mnMaxRowUsed(-1) {}
1054 
1056  SvRefBase(rList),
1057  maRanges(rList.maRanges),
1058  mnMaxRowUsed(rList.mnMaxRowUsed)
1059 {
1060 }
1061 
1063  maRanges(std::move(rList.maRanges)),
1064  mnMaxRowUsed(rList.mnMaxRowUsed)
1065 {
1066 }
1067 
1069  mnMaxRowUsed(-1)
1070 {
1071  maRanges.reserve(1);
1072  push_back(rRange);
1073 }
1074 
1076 {
1077  maRanges = rList.maRanges;
1078  mnMaxRowUsed = rList.mnMaxRowUsed;
1079  return *this;
1080 }
1081 
1083 {
1084  maRanges = std::move(rList.maRanges);
1085  mnMaxRowUsed = rList.mnMaxRowUsed;
1086  return *this;
1087 }
1088 
1089 bool ScRangeList::Intersects( const ScRange& rRange ) const
1090 {
1091  return std::any_of(maRanges.begin(), maRanges.end(), FindIntersectingRange<ScRange>(rRange));
1092 }
1093 
1094 bool ScRangeList::In( const ScRange& rRange ) const
1095 {
1096  return std::any_of(maRanges.begin(), maRanges.end(), FindEnclosingRange<ScRange>(rRange));
1097 }
1098 
1100 {
1101  CountCells func;
1102  return for_each(maRanges.begin(), maRanges.end(), func).getCellCount();
1103 }
1104 
1105 void ScRangeList::Remove(size_t nPos)
1106 {
1107  if (maRanges.size() <= nPos)
1108  // Out-of-bound condition. Bail out.
1109  return;
1110  maRanges.erase(maRanges.begin() + nPos);
1111 }
1112 
1114 {
1115  maRanges.clear();
1116  mnMaxRowUsed = -1;
1117 }
1118 
1120 {
1121  if (maRanges.empty())
1122  return ScRange();
1123 
1124  auto itr = maRanges.cbegin(), itrEnd = maRanges.cend();
1125  ScRange aRet = *itr;
1126  ++itr;
1127  for (; itr != itrEnd; ++itr)
1128  {
1129  const ScRange& r = *itr;
1130  SCROW nRow1 = r.aStart.Row(), nRow2 = r.aEnd.Row();
1131  SCCOL nCol1 = r.aStart.Col(), nCol2 = r.aEnd.Col();
1132  SCTAB nTab1 = r.aStart.Tab(), nTab2 = r.aEnd.Tab();
1133  if (aRet.aStart.Row() > nRow1)
1134  aRet.aStart.SetRow(nRow1);
1135  if (aRet.aStart.Col() > nCol1)
1136  aRet.aStart.SetCol(nCol1);
1137  if (aRet.aStart.Tab() > nTab1)
1138  aRet.aStart.SetTab(nTab1);
1139  if (aRet.aEnd.Row() < nRow2)
1140  aRet.aEnd.SetRow(nRow2);
1141  if (aRet.aEnd.Col() < nCol2)
1142  aRet.aEnd.SetCol(nCol2);
1143  if (aRet.aEnd.Tab() < nTab2)
1144  aRet.aEnd.SetTab(nTab2);
1145  }
1146  return aRet;
1147 }
1148 
1150 {
1151  maRanges.push_back(r);
1152  if (mnMaxRowUsed < r.aEnd.Row())
1153  mnMaxRowUsed = r.aEnd.Row();
1154 }
1155 
1157 {
1158  maRanges.swap(r.maRanges);
1159  std::swap(mnMaxRowUsed, r.mnMaxRowUsed);
1160 }
1161 
1163 {
1164  if(empty())
1165  return ScAddress();
1166 
1167  ScAddress const * pAddr = &maRanges[0].aStart;
1168  for(size_t i = 1, n = size(); i < n; ++i)
1169  {
1170  if(maRanges[i].aStart < *pAddr)
1171  pAddr = &maRanges[i].aStart;
1172  }
1173 
1174  return *pAddr;
1175 }
1176 
1178 {
1179  ScRangeList aReturn;
1180  for(auto& rR : maRanges)
1181  {
1182  if(rR.Intersects(rRange))
1183  {
1184  SCCOL nColStart1, nColEnd1, nColStart2, nColEnd2;
1185  SCROW nRowStart1, nRowEnd1, nRowStart2, nRowEnd2;
1186  SCTAB nTabStart1, nTabEnd1, nTabStart2, nTabEnd2;
1187  rR.GetVars(nColStart1, nRowStart1, nTabStart1,
1188  nColEnd1, nRowEnd1, nTabEnd1);
1189  rRange.GetVars(nColStart2, nRowStart2, nTabStart2,
1190  nColEnd2, nRowEnd2, nTabEnd2);
1191 
1192  ScRange aNewRange(std::max<SCCOL>(nColStart1, nColStart2), std::max<SCROW>(nRowStart1, nRowStart2),
1193  std::max<SCTAB>(nTabStart1, nTabStart2), std::min<SCCOL>(nColEnd1, nColEnd2),
1194  std::min<SCROW>(nRowEnd1, nRowEnd2), std::min<SCTAB>(nTabEnd1, nTabEnd2));
1195  aReturn.Join(aNewRange);
1196  }
1197  }
1198 
1199  return aReturn;
1200 }
1201 
1202 // ScRangePairList
1204 {
1205 }
1206 
1207 void ScRangePairList::Remove(size_t nPos)
1208 {
1209  if (maPairs.size() <= nPos)
1210  // Out-of-bound condition. Bail out.
1211  return;
1212  maPairs.erase(maPairs.begin() + nPos);
1213 }
1214 
1216 {
1217  auto itr = std::find_if(maPairs.begin(), maPairs.end(), [&rAdr](const ScRangePair& rPair) { return &rAdr == &rPair; });
1218  if (itr != maPairs.end())
1219  {
1220  maPairs.erase( itr );
1221  return;
1222  }
1223  assert(false);
1224 }
1225 
1227 {
1228  return maPairs[idx];
1229 }
1230 
1232 {
1233  return maPairs[idx];
1234 }
1235 
1237 {
1238  return maPairs.size();
1239 }
1240 
1242  const ScDocument* pDoc, const ScRange& rWhere,
1243  SCCOL nDx, SCROW nDy, SCTAB nDz )
1244 {
1245  if ( maPairs.empty() )
1246  return;
1247 
1248  SCCOL nCol1;
1249  SCROW nRow1;
1250  SCTAB nTab1;
1251  SCCOL nCol2;
1252  SCROW nRow2;
1253  SCTAB nTab2;
1254  rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1255  for (ScRangePair & rR : maPairs)
1256  {
1257  for ( sal_uInt16 j=0; j<2; j++ )
1258  {
1259  ScRange& rRange = rR.GetRange(j);
1260  SCCOL theCol1;
1261  SCROW theRow1;
1262  SCTAB theTab1;
1263  SCCOL theCol2;
1264  SCROW theRow2;
1265  SCTAB theTab2;
1266  rRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
1267  if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
1268  nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
1269  nDx, nDy, nDz,
1270  theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
1271  != UR_NOTHING )
1272  {
1273  rRange.aStart.Set( theCol1, theRow1, theTab1 );
1274  rRange.aEnd.Set( theCol2, theRow2, theTab2 );
1275  }
1276  }
1277  }
1278 }
1279 
1280 // Delete entries that have the labels (first range) on nTab
1282 {
1283  maPairs.erase(std::remove_if(maPairs.begin(), maPairs.end(),
1284  [&nTab](const ScRangePair& rR) {
1285  const ScRange & rRange = rR.GetRange(0);
1286  return (rRange.aStart.Tab() == nTab) && (rRange.aEnd.Tab() == nTab);
1287  }),
1288  maPairs.end());
1289 }
1290 
1292 {
1293  for (ScRangePair & rR : maPairs)
1294  {
1295  if ( rR.GetRange(0).In( rAdr ) )
1296  return &rR;
1297  }
1298  return nullptr;
1299 }
1300 
1302 {
1303  for (ScRangePair & rR : maPairs)
1304  {
1305  if ( rR.GetRange(0) == rRange )
1306  return &rR;
1307  }
1308  return nullptr;
1309 }
1310 
1312 {
1313  ScRangePairList* pNew = new ScRangePairList;
1314  for (const ScRangePair & rR : maPairs)
1315  {
1316  pNew->Append( rR );
1317  }
1318  return pNew;
1319 }
1320 
1321 namespace {
1322 
1323 class ScRangePairList_sortNameCompare
1324 {
1325 public:
1326  ScRangePairList_sortNameCompare(ScDocument& rDoc) : mrDoc(rDoc) {}
1327 
1328  bool operator()( const ScRangePair *ps1, const ScRangePair* ps2 ) const
1329  {
1330  const ScAddress& rStartPos1 = ps1->GetRange(0).aStart;
1331  const ScAddress& rStartPos2 = ps2->GetRange(0).aStart;
1332  OUString aStr1, aStr2;
1333  sal_Int32 nComp;
1334  if ( rStartPos1.Tab() == rStartPos2.Tab() )
1335  nComp = 0;
1336  else
1337  {
1338  mrDoc.GetName( rStartPos1.Tab(), aStr1 );
1339  mrDoc.GetName( rStartPos2.Tab(), aStr2 );
1340  nComp = ScGlobal::GetCollator().compareString( aStr1, aStr2 );
1341  }
1342  if (nComp < 0)
1343  {
1344  return true; // -1;
1345  }
1346  else if (nComp > 0)
1347  {
1348  return false; // 1;
1349  }
1350 
1351  // equal tabs
1352  if ( rStartPos1.Col() < rStartPos2.Col() )
1353  return true; // -1;
1354  if ( rStartPos1.Col() > rStartPos2.Col() )
1355  return false; // 1;
1356  // equal cols
1357  if ( rStartPos1.Row() < rStartPos2.Row() )
1358  return true; // -1;
1359  if ( rStartPos1.Row() > rStartPos2.Row() )
1360  return false; // 1;
1361 
1362  // first corner equal, second corner
1363  const ScAddress& rEndPos1 = ps1->GetRange(0).aEnd;
1364  const ScAddress& rEndPos2 = ps2->GetRange(0).aEnd;
1365  if ( rEndPos1.Tab() == rEndPos2.Tab() )
1366  nComp = 0;
1367  else
1368  {
1369  mrDoc.GetName( rEndPos1.Tab(), aStr1 );
1370  mrDoc.GetName( rEndPos2.Tab(), aStr2 );
1371  nComp = ScGlobal::GetCollator().compareString( aStr1, aStr2 );
1372  }
1373  if (nComp < 0)
1374  {
1375  return true; // -1;
1376  }
1377  else if (nComp > 0)
1378  {
1379  return false; // 1;
1380  }
1381 
1382  // equal tabs
1383  if ( rEndPos1.Col() < rEndPos2.Col() )
1384  return true; // -1;
1385  if ( rEndPos1.Col() > rEndPos2.Col() )
1386  return false; // 1;
1387  // equal cols
1388  if ( rEndPos1.Row() < rEndPos2.Row() )
1389  return true; // -1;
1390  if ( rEndPos1.Row() > rEndPos2.Row() )
1391  return false; // 1;
1392 
1393  return false;
1394  }
1395 private:
1396  ScDocument& mrDoc;
1397 };
1398 
1399 }
1400 
1401 void ScRangePairList::Join( const ScRangePair& r, bool bIsInList )
1402 {
1403  if ( maPairs.empty() )
1404  {
1405  Append( r );
1406  return ;
1407  }
1408 
1409  bool bJoinedInput = false;
1410  const ScRangePair* pOver = &r;
1411 
1412 Label_RangePair_Join:
1413 
1414  assert(pOver);
1415  const ScRange& r1 = pOver->GetRange(0);
1416  const ScRange& r2 = pOver->GetRange(1);
1417  const SCCOL nCol1 = r1.aStart.Col();
1418  const SCROW nRow1 = r1.aStart.Row();
1419  const SCTAB nTab1 = r1.aStart.Tab();
1420  const SCCOL nCol2 = r1.aEnd.Col();
1421  const SCROW nRow2 = r1.aEnd.Row();
1422  const SCTAB nTab2 = r1.aEnd.Tab();
1423 
1424  size_t nOverPos = std::numeric_limits<size_t>::max();
1425  for (size_t i = 0; i < maPairs.size(); ++i)
1426  {
1427  ScRangePair & rPair = maPairs[ i ];
1428  if ( &rPair == pOver )
1429  {
1430  nOverPos = i;
1431  continue; // the same one, continue with the next
1432  }
1433  bool bJoined = false;
1434  ScRange& rp1 = rPair.GetRange(0);
1435  ScRange& rp2 = rPair.GetRange(1);
1436  if ( rp2 == r2 )
1437  { // only if Range2 is equal
1438  if ( rp1.In( r1 ) )
1439  { // RangePair pOver included in or identical to RangePair p
1440  if ( bIsInList )
1441  bJoined = true; // do away with RangePair pOver
1442  else
1443  { // that was all then
1444  bJoinedInput = true; // don't append
1445  break; // for
1446  }
1447  }
1448  else if ( r1.In( rp1 ) )
1449  { // RangePair p included in RangePair pOver, make pOver the new RangePair
1450  rPair = *pOver;
1451  bJoined = true;
1452  }
1453  }
1454  if ( !bJoined && rp1.aStart.Tab() == nTab1 && rp1.aEnd.Tab() == nTab2
1455  && rp2.aStart.Tab() == r2.aStart.Tab()
1456  && rp2.aEnd.Tab() == r2.aEnd.Tab() )
1457  { // 2D, Range2 must be located side-by-side just like Range1
1458  if ( rp1.aStart.Col() == nCol1 && rp1.aEnd.Col() == nCol2
1459  && rp2.aStart.Col() == r2.aStart.Col()
1460  && rp2.aEnd.Col() == r2.aEnd.Col() )
1461  {
1462  if ( rp1.aStart.Row() == nRow2+1
1463  && rp2.aStart.Row() == r2.aEnd.Row()+1 )
1464  { // top
1465  rp1.aStart.SetRow( nRow1 );
1466  rp2.aStart.SetRow( r2.aStart.Row() );
1467  bJoined = true;
1468  }
1469  else if ( rp1.aEnd.Row() == nRow1-1
1470  && rp2.aEnd.Row() == r2.aStart.Row()-1 )
1471  { // bottom
1472  rp1.aEnd.SetRow( nRow2 );
1473  rp2.aEnd.SetRow( r2.aEnd.Row() );
1474  bJoined = true;
1475  }
1476  }
1477  else if ( rp1.aStart.Row() == nRow1 && rp1.aEnd.Row() == nRow2
1478  && rp2.aStart.Row() == r2.aStart.Row()
1479  && rp2.aEnd.Row() == r2.aEnd.Row() )
1480  {
1481  if ( rp1.aStart.Col() == nCol2+1
1482  && rp2.aStart.Col() == r2.aEnd.Col()+1 )
1483  { // left
1484  rp1.aStart.SetCol( nCol1 );
1485  rp2.aStart.SetCol( r2.aStart.Col() );
1486  bJoined = true;
1487  }
1488  else if ( rp1.aEnd.Col() == nCol1-1
1489  && rp2.aEnd.Col() == r2.aEnd.Col()-1 )
1490  { // right
1491  rp1.aEnd.SetCol( nCol2 );
1492  rp2.aEnd.SetCol( r2.aEnd.Col() );
1493  bJoined = true;
1494  }
1495  }
1496  }
1497  if ( bJoined )
1498  {
1499  if ( bIsInList )
1500  { // delete RangePair pOver within the list
1501  if (nOverPos != std::numeric_limits<size_t>::max())
1502  {
1503  Remove(nOverPos);
1504  if (nOverPos < i)
1505  --i;
1506  }
1507  else
1508  {
1509  for (size_t nOver = 0, nRangePairs = maPairs.size(); nOver < nRangePairs; ++nOver)
1510  {
1511  if (&maPairs[nOver] == pOver)
1512  {
1513  maPairs.erase(maPairs.begin() + nOver);
1514  break;
1515  }
1516  }
1517  assert(false);
1518  }
1519  }
1520  bJoinedInput = true;
1521  pOver = &maPairs[i];
1522  bIsInList = true;
1523  goto Label_RangePair_Join;
1524  }
1525  }
1526  if ( !bIsInList && !bJoinedInput )
1527  Append( r );
1528 }
1529 
1530 std::vector<const ScRangePair*> ScRangePairList::CreateNameSortedArray( ScDocument& rDoc ) const
1531 {
1532  std::vector<const ScRangePair*> aSortedVec(maPairs.size());
1533  size_t i = 0;
1534  for ( auto const & rPair : maPairs)
1535  {
1536  aSortedVec[i++] = &rPair;
1537  }
1538 
1539  std::sort( aSortedVec.begin(), aSortedVec.end(), ScRangePairList_sortNameCompare(rDoc) );
1540 
1541  return aSortedVec;
1542 }
1543 
1544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScRefFlags ParseAny(const OUString &, const ScDocument &, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1)
Definition: address.cxx:1775
bool UpdateReference(UpdateRefMode, const ScDocument *, const ScRange &rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: rangelst.cxx:369
bool operator!=(const ScRangeList &r) const
Definition: rangelst.cxx:364
bool Intersects(const ScRange &) const
Definition: rangelst.cxx:1089
static ScRefUpdateRes Update(const ScDocument *pDoc, UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz, SCCOL &theCol1, SCROW &theRow1, SCTAB &theTab1, SCCOL &theCol2, SCROW &theRow2, SCTAB &theTab2)
Definition: refupdat.cxx:188
ScAddress aStart
Definition: address.hxx:499
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
SCROW Row() const
Definition: address.hxx:261
void Format(OUString &, ScRefFlags nFlags, const ScDocument &, formula::FormulaGrammar::AddressConvention eConv=formula::FormulaGrammar::CONV_OOO, sal_Unicode cDelimiter=0, bool bFullAddressNotation=false) const
Definition: rangelst.cxx:144
bool Intersects(const ScRange &rRange) const
Definition: address.cxx:1558
sal_Int64 n
aBuf
ScRange Combine() const
Definition: rangelst.cxx:1119
ScAddress aEnd
Definition: address.hxx:500
const sal_Unicode cDelimiter
Definition: tpusrlst.cxx:45
void DeleteOnTab(SCTAB nTab)
Definition: rangelst.cxx:1281
virtual ~ScRangeList() override
Definition: rangelst.cxx:100
void UpdateReference(UpdateRefMode, const ScDocument *, const ScRange &rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: rangelst.cxx:1241
void Append(const ScRangePair &rRangePair)
Definition: rangelst.hxx:136
void Remove(size_t nPos)
Definition: rangelst.cxx:1207
size_t GetCellCount() const
Definition: rangelst.cxx:1099
::std::vector< ScRange > maRanges
Definition: rangelst.hxx:107
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
Definition: rangelst.cxx:454
sal_uInt16 sal_Unicode
bool DeleteArea(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
For now this method assumes that nTab1 == nTab2 The algorithm will be much more complicated if nTab1 ...
Definition: rangelst.cxx:963
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
ScRangePair & operator[](size_t idx)
Definition: rangelst.cxx:1226
bool In(const ScRange &) const
Definition: rangelst.cxx:1094
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1149
void swap(ScRangeList &r)
Definition: rangelst.cxx:1156
SCTAB Tab() const
Definition: address.hxx:270
void SetRow(SCROW nRowP)
Definition: address.hxx:274
const ScRange * Find(const ScAddress &) const
Definition: rangelst.cxx:1039
static sal_Unicode GetNativeSymbolChar(OpCode eOp)
void SetCol(SCCOL nColP)
Definition: address.hxx:278
ScAddress GetTopLeftCorner() const
Definition: rangelst.cxx:1162
bool empty() const
Definition: rangelst.hxx:88
ocSep
void Remove(size_t nPos)
Definition: rangelst.cxx:1105
void SetTab(SCTAB nTabP)
Definition: address.hxx:282
void Join(const ScRangePair &, bool bIsInList=false)
Definition: rangelst.cxx:1401
ScRangePairList * Clone() const
Definition: rangelst.cxx:1311
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
Definition: rangelst.cxx:484
int i
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:405
sal_Int16 SCCOL
Definition: types.hxx:21
void applyStartToEndFlags(ScRefFlags &target, const ScRefFlags source)
Definition: address.hxx:183
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:2212
ScRefFlags Parse(const OUString &, const ScDocument &, formula::FormulaGrammar::AddressConvention eConv=formula::FormulaGrammar::CONV_OOO, SCTAB nDefaultTab=0, sal_Unicode cDelimiter=0)
Definition: rangelst.cxx:104
size_t size() const
Definition: rangelst.hxx:89
const ScRange & GetRange(sal_uInt16 n) const
Definition: address.hxx:816
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:692
bool In(const ScAddress &) const
is Address& in Range?
Definition: address.hxx:732
Reference not affected, no change at all.
Definition: refupdat.hxx:31
SCCOL Col() const
Definition: address.hxx:266
ScRangeList & operator=(const ScRangeList &rList)
Definition: rangelst.cxx:1075
UpdateRefMode
Definition: global.hxx:310
sal_Int32 SCROW
Definition: types.hxx:17
virtual ~ScRangePairList() override
Definition: rangelst.cxx:1203
#define SAL_WARN_IF(condition, area, stream)
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1047
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:164
size_t size() const
Definition: rangelst.cxx:1236
bool operator==(const ScRangeList &) const
Definition: rangelst.cxx:356
ScRangeList GetIntersectedRange(const ScRange &rRange) const
Definition: rangelst.cxx:1177
SCROW mnMaxRowUsed
Definition: rangelst.hxx:108
void AddAndPartialCombine(const ScRange &)
Definition: rangelst.cxx:311
ScRefFlags
Definition: address.hxx:144
std::vector< const ScRangePair * > CreateNameSortedArray(ScDocument &) const
Definition: rangelst.cxx:1530
::std::vector< ScRangePair > maPairs
Definition: rangelst.hxx:158
ScRangePair * Find(const ScAddress &)
Definition: rangelst.cxx:1291
void RemoveAll()
Definition: rangelst.cxx:1113
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:22