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