LibreOffice Module sc (master)  1
dbdata.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 <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <o3tl/safeint.hxx>
25 #include <unotools/charclass.hxx>
26 
27 #include <dbdata.hxx>
28 #include <globalnames.hxx>
29 #include <refupdat.hxx>
30 #include <document.hxx>
31 #include <queryparam.hxx>
32 #include <queryentry.hxx>
33 #include <globstr.hrc>
34 #include <scresid.hxx>
35 #include <subtotalparam.hxx>
36 #include <sortparam.hxx>
37 #include <dociter.hxx>
38 #include <brdcst.hxx>
39 
40 #include <comphelper/stl_types.hxx>
41 
42 #include <memory>
43 #include <utility>
44 
45 using ::std::unique_ptr;
46 using ::std::for_each;
47 using ::std::find_if;
48 using ::std::remove_if;
49 using ::std::pair;
50 
51 bool ScDBData::less::operator() (const std::unique_ptr<ScDBData>& left, const std::unique_ptr<ScDBData>& right) const
52 {
53  return ScGlobal::GetTransliteration().compareString(left->GetUpperName(), right->GetUpperName()) < 0;
54 }
55 
56 ScDBData::ScDBData( const OUString& rName,
57  SCTAB nTab,
58  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
59  bool bByR, bool bHasH, bool bTotals) :
60  // Listeners are to be setup by the "parent" container.
65  mpContainer (nullptr),
66  aName (rName),
67  aUpper (rName),
68  nTable (nTab),
69  nStartCol (nCol1),
70  nStartRow (nRow1),
71  nEndCol (nCol2),
72  nEndRow (nRow2),
73  bByRow (bByR),
74  bHasHeader (bHasH),
75  bHasTotals (bTotals),
76  bDoSize (false),
77  bKeepFmt (false),
78  bStripData (false),
79  bIsAdvanced (false),
80  bDBSelection(false),
81  nIndex (0),
82  bAutoFilter (false),
83  bModified (false),
86 {
88 }
89 
90 ScDBData::ScDBData( const ScDBData& rData ) :
91  // Listeners are to be setup by the "parent" container.
92  SvtListener (),
93  ScRefreshTimer ( rData ),
94  mpSortParam(new ScSortParam(*rData.mpSortParam)),
95  mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
96  mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
97  mpImportParam(new ScImportParam(*rData.mpImportParam)),
98  mpContainer (nullptr),
99  aName (rData.aName),
100  aUpper (rData.aUpper),
101  nTable (rData.nTable),
102  nStartCol (rData.nStartCol),
103  nStartRow (rData.nStartRow),
104  nEndCol (rData.nEndCol),
105  nEndRow (rData.nEndRow),
106  bByRow (rData.bByRow),
107  bHasHeader (rData.bHasHeader),
108  bHasTotals (rData.bHasTotals),
109  bDoSize (rData.bDoSize),
110  bKeepFmt (rData.bKeepFmt),
111  bStripData (rData.bStripData),
112  bIsAdvanced (rData.bIsAdvanced),
113  aAdvSource (rData.aAdvSource),
114  bDBSelection (rData.bDBSelection),
115  nIndex (rData.nIndex),
116  bAutoFilter (rData.bAutoFilter),
117  bModified (rData.bModified),
118  maTableColumnNames (rData.maTableColumnNames),
119  mbTableColumnNamesDirty(rData.mbTableColumnNamesDirty),
120  nFilteredRowCount (rData.nFilteredRowCount)
121 {
122 }
123 
124 ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
125  // Listeners are to be setup by the "parent" container.
126  SvtListener (),
127  ScRefreshTimer ( rData ),
128  mpSortParam(new ScSortParam(*rData.mpSortParam)),
129  mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
130  mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
131  mpImportParam(new ScImportParam(*rData.mpImportParam)),
132  mpContainer (nullptr),
133  aName (rName),
134  aUpper (rName),
135  nTable (rData.nTable),
136  nStartCol (rData.nStartCol),
137  nStartRow (rData.nStartRow),
138  nEndCol (rData.nEndCol),
139  nEndRow (rData.nEndRow),
140  bByRow (rData.bByRow),
141  bHasHeader (rData.bHasHeader),
142  bHasTotals (rData.bHasTotals),
143  bDoSize (rData.bDoSize),
144  bKeepFmt (rData.bKeepFmt),
145  bStripData (rData.bStripData),
146  bIsAdvanced (rData.bIsAdvanced),
147  aAdvSource (rData.aAdvSource),
148  bDBSelection (rData.bDBSelection),
149  nIndex (rData.nIndex),
150  bAutoFilter (rData.bAutoFilter),
151  bModified (rData.bModified),
152  maTableColumnNames (rData.maTableColumnNames),
153  mbTableColumnNamesDirty (rData.mbTableColumnNamesDirty),
154  nFilteredRowCount (rData.nFilteredRowCount)
155 {
157 }
158 
160 {
161  if (this != &rData)
162  {
163  // Don't modify the name. The name is not mutable as it is used as a key
164  // in the container to keep the db ranges sorted by the name.
165 
166  bool bHeaderRangeDiffers = (nTable != rData.nTable || nStartCol != rData.nStartCol ||
167  nEndCol != rData.nEndCol || nStartRow != rData.nStartRow);
168  bool bNeedsListening = ((bHasHeader && bHeaderRangeDiffers) || (!bHasHeader && rData.bHasHeader));
169  if (bHasHeader && (!rData.bHasHeader || bHeaderRangeDiffers))
170  {
172  }
173  ScRefreshTimer::operator=( rData );
174  mpSortParam.reset(new ScSortParam(*rData.mpSortParam));
175  mpQueryParam.reset(new ScQueryParam(*rData.mpQueryParam));
176  mpSubTotal.reset(new ScSubTotalParam(*rData.mpSubTotal));
177  mpImportParam.reset(new ScImportParam(*rData.mpImportParam));
178  // Keep mpContainer.
179  nTable = rData.nTable;
180  nStartCol = rData.nStartCol;
181  nStartRow = rData.nStartRow;
182  nEndCol = rData.nEndCol;
183  nEndRow = rData.nEndRow;
184  bByRow = rData.bByRow;
185  bHasHeader = rData.bHasHeader;
186  bHasTotals = rData.bHasTotals;
187  bDoSize = rData.bDoSize;
188  bKeepFmt = rData.bKeepFmt;
189  bStripData = rData.bStripData;
190  bIsAdvanced = rData.bIsAdvanced;
191  aAdvSource = rData.aAdvSource;
192  bDBSelection = rData.bDBSelection;
193  nIndex = rData.nIndex;
194  bAutoFilter = rData.bAutoFilter;
196 
197  if (bHeaderRangeDiffers)
199  else
200  {
203  }
204 
205  if (bNeedsListening)
207  }
208  return *this;
209 }
210 
211 bool ScDBData::operator== (const ScDBData& rData) const
212 {
213  // Data that is not in sort or query params.
214 
215  if ( nTable != rData.nTable ||
216  bDoSize != rData.bDoSize ||
217  bKeepFmt != rData.bKeepFmt ||
218  bIsAdvanced!= rData.bIsAdvanced||
219  bStripData != rData.bStripData ||
220 // SAB: I think this should be here, but I don't want to break something
221 // bAutoFilter!= rData.bAutoFilter||
222  ScRefreshTimer::operator!=( rData )
223  )
224  return false;
225 
226  if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
227  return false;
228 
229  ScSortParam aSort1, aSort2;
230  GetSortParam(aSort1);
231  rData.GetSortParam(aSort2);
232  if (!(aSort1 == aSort2))
233  return false;
234 
235  ScQueryParam aQuery1, aQuery2;
236  GetQueryParam(aQuery1);
237  rData.GetQueryParam(aQuery2);
238  if (!(aQuery1 == aQuery2))
239  return false;
240 
241  ScSubTotalParam aSubTotal1, aSubTotal2;
242  GetSubTotalParam(aSubTotal1);
243  rData.GetSubTotalParam(aSubTotal2);
244  if (!(aSubTotal1 == aSubTotal2))
245  return false;
246 
247  ScImportParam aImport1, aImport2;
248  GetImportParam(aImport1);
249  rData.GetImportParam(aImport2);
250  return aImport1 == aImport2;
251 }
252 
254 {
256 }
257 
259 {
260  OUStringBuffer aBuf;
261  if (mpImportParam->bImport)
262  {
263  aBuf.append(mpImportParam->aDBName);
264  aBuf.append('/');
265  aBuf.append(mpImportParam->aStatement);
266  }
267  return aBuf.makeStringAndClear();
268 }
269 
270 OUString ScDBData::GetOperations() const
271 {
272  OUStringBuffer aBuf;
273  if (mpQueryParam->GetEntryCount())
274  {
275  const ScQueryEntry& rEntry = mpQueryParam->GetEntry(0);
276  if (rEntry.bDoQuery)
277  aBuf.append(ScResId(STR_OPERATION_FILTER));
278  }
279 
280  if (mpSortParam->maKeyState[0].bDoSort)
281  {
282  if (!aBuf.isEmpty())
283  aBuf.append(", ");
284  aBuf.append(ScResId(STR_OPERATION_SORT));
285  }
286 
287  if (mpSubTotal->bGroupActive[0] && !mpSubTotal->bRemoveOnly)
288  {
289  if (!aBuf.isEmpty())
290  aBuf.append(", ");
291  aBuf.append(ScResId(STR_OPERATION_SUBTOTAL));
292  }
293 
294  if (aBuf.isEmpty())
295  aBuf.append(ScResId(STR_OPERATION_NONE));
296 
297  return aBuf.makeStringAndClear();
298 }
299 
300 void ScDBData::GetArea(SCTAB& rTab, SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2) const
301 {
302  rTab = nTable;
303  rCol1 = nStartCol;
304  rRow1 = nStartRow;
305  rCol2 = nEndCol;
306  rRow2 = nEndRow;
307 }
308 
309 void ScDBData::GetArea(ScRange& rRange) const
310 {
311  SCROW nNewEndRow = nEndRow;
312  rRange = ScRange( nStartCol, nStartRow, nTable, nEndCol, nNewEndRow, nTable );
313 }
314 
316 {
317  if (HasHeader())
320 }
321 
322 void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
323 {
324  bool bHeaderRangeChange = (nTab != nTable || nCol1 != nStartCol || nCol2 != nEndCol || nRow1 != nStartRow);
325  if (bHeaderRangeChange)
327 
328  nTable = nTab;
329  nStartCol = nCol1;
330  nStartRow = nRow1;
331  nEndCol = nCol2;
332  nEndRow = nRow2;
333 
334  if (bHeaderRangeChange)
335  {
336  SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::SetArea - invalidating column names/offsets");
337  // Invalidate *after* new area has been set above to add the proper
338  // header range to dirty list.
341  }
342 }
343 
344 void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
345  SCCOL nUpdateCol)
346 {
347  tools::Long nDifX = static_cast<tools::Long>(nCol1) - static_cast<tools::Long>(nStartCol);
348  tools::Long nDifY = static_cast<tools::Long>(nRow1) - static_cast<tools::Long>(nStartRow);
349 
350  tools::Long nSortDif = bByRow ? nDifX : nDifY;
351  tools::Long nSortEnd = bByRow ? static_cast<tools::Long>(nCol2) : static_cast<tools::Long>(nRow2);
352 
353  for (sal_uInt16 i=0; i<mpSortParam->GetSortKeyCount(); i++)
354  {
355  mpSortParam->maKeyState[i].nField += nSortDif;
356  if (mpSortParam->maKeyState[i].nField > nSortEnd)
357  {
358  mpSortParam->maKeyState[i].nField = 0;
359  mpSortParam->maKeyState[i].bDoSort = false;
360  }
361  }
362 
363  SCSIZE nCount = mpQueryParam->GetEntryCount();
364  for (SCSIZE i = 0; i < nCount; ++i)
365  {
366  ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
367  rEntry.nField += nDifX;
368 
369  // tdf#48025, tdf#141946: update the column index of the filter criteria,
370  // when the deleted/inserted columns are inside the data range
371  if (nUpdateCol != -1)
372  {
373  nUpdateCol += nDifX;
374  tools::Long nDifX2
375  = static_cast<tools::Long>(nCol2) - static_cast<tools::Long>(nEndCol);
376  if (rEntry.nField >= nUpdateCol)
377  rEntry.nField += nDifX2;
378  else if (rEntry.nField >= nUpdateCol + nDifX2)
379  rEntry.Clear();
380  }
381 
382  if (rEntry.nField > nCol2)
383  {
384  rEntry.nField = 0;
385  rEntry.bDoQuery = false;
386  }
387  }
388  for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
389  {
390  mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
391  if (mpSubTotal->nField[i] > nCol2)
392  {
393  mpSubTotal->nField[i] = 0;
394  mpSubTotal->bGroupActive[i] = false;
395  }
396  }
397 
398  SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
399 }
400 
401 void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
402 {
403  rSortParam = *mpSortParam;
404  rSortParam.nCol1 = nStartCol;
405  rSortParam.nRow1 = nStartRow;
406  rSortParam.nCol2 = nEndCol;
407  rSortParam.nRow2 = nEndRow;
408  rSortParam.bByRow = bByRow;
409  rSortParam.bHasHeader = bHasHeader;
410  /* TODO: add Totals to ScSortParam? */
411 }
412 
413 void ScDBData::SetSortParam( const ScSortParam& rSortParam )
414 {
415  mpSortParam.reset(new ScSortParam(rSortParam));
416  bByRow = rSortParam.bByRow;
417 }
418 
420 {
421  bHasHeader = rSortParam.bHasHeader;
422 }
423 
424 void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
425 {
426  rQueryParam = *mpQueryParam;
427  rQueryParam.nCol1 = nStartCol;
428  rQueryParam.nRow1 = nStartRow;
429  rQueryParam.nCol2 = nEndCol;
430  rQueryParam.nRow2 = nEndRow;
431  rQueryParam.nTab = nTable;
432  rQueryParam.bByRow = bByRow;
433  rQueryParam.bHasHeader = bHasHeader;
434  /* TODO: add Totals to ScQueryParam? */
435 }
436 
437 void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
438 {
439  mpQueryParam.reset(new ScQueryParam(rQueryParam));
440 
441  // set bIsAdvanced to false for everything that is not from the
442  // advanced filter dialog
443  bIsAdvanced = false;
444 }
445 
447 {
448  if (pSource)
449  {
450  aAdvSource = *pSource;
451  bIsAdvanced = true;
452  }
453  else
454  bIsAdvanced = false;
455 }
456 
458 {
459  rSource = aAdvSource;
460  return bIsAdvanced;
461 }
462 
463 void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
464 {
465  rSubTotalParam = *mpSubTotal;
466 
467  // Share the data range with the parent db data. The range in the subtotal
468  // param struct is not used.
469  rSubTotalParam.nCol1 = nStartCol;
470  rSubTotalParam.nRow1 = nStartRow;
471  rSubTotalParam.nCol2 = nEndCol;
472  rSubTotalParam.nRow2 = nEndRow;
473 }
474 
475 void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
476 {
477  mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
478 }
479 
480 void ScDBData::GetImportParam(ScImportParam& rImportParam) const
481 {
482  rImportParam = *mpImportParam;
483  // set the range.
484  rImportParam.nCol1 = nStartCol;
485  rImportParam.nRow1 = nStartRow;
486  rImportParam.nCol2 = nEndCol;
487  rImportParam.nRow2 = nEndRow;
488 }
489 
490 void ScDBData::SetImportParam(const ScImportParam& rImportParam)
491 {
492  // the range is ignored.
493  mpImportParam.reset(new ScImportParam(rImportParam));
494 }
495 
496 bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
497 {
498  if (nTab == nTable)
499  {
500  switch (ePortion)
501  {
503  return nCol == nStartCol && nRow == nStartRow;
505  return nCol >= nStartCol && nCol <= nEndCol && nRow >= nStartRow && nRow <= nEndRow;
506  }
507  }
508 
509  return false;
510 }
511 
512 bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
513 {
514  return (nTab == nTable)
515  && (nCol1 == nStartCol) && (nRow1 == nStartRow)
516  && (nCol2 == nEndCol) && (nRow2 == nEndRow);
517 }
518 
520 {
521  return mpImportParam && mpImportParam->bImport;
522 }
523 
525 {
526  if (!mpQueryParam)
527  return false;
528 
529  if (!mpQueryParam->GetEntryCount())
530  return false;
531 
532  return mpQueryParam->GetEntry(0).bDoQuery;
533 }
534 
536 {
537  return mpSortParam &&
538  !mpSortParam->maKeyState.empty() &&
539  mpSortParam->maKeyState[0].bDoSort;
540 }
541 
543 {
544  return mpSubTotal && mpSubTotal->bGroupActive[0];
545 }
546 
547 void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
548 {
549  ScRange aRange;
550  GetArea( aRange );
551  SCTAB nTab = aRange.aStart.Tab(); // a database range is only on one sheet
552 
553  // customize as the current table as ScTablesHint (tabvwsh5.cxx)
554 
555  if ( nTab == nOldPos ) // moved sheet
556  nTab = nNewPos;
557  else if ( nOldPos < nNewPos ) // moved to the back
558  {
559  if ( nTab > nOldPos && nTab <= nNewPos ) // move this sheet
560  --nTab;
561  }
562  else // moved to the front
563  {
564  if ( nTab >= nNewPos && nTab < nOldPos ) // move this sheet
565  ++nTab;
566  }
567 
568  bool bChanged = ( nTab != aRange.aStart.Tab() );
569  if (bChanged)
570  {
571  // SetArea() invalidates column names, but it is the same column range
572  // just on a different sheet; remember and set new.
573  ::std::vector<OUString> aNames( maTableColumnNames);
574  bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
575  // Same column range.
576  SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
577  aRange.aEnd.Col(),aRange.aEnd.Row() );
578  // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
579  maTableColumnNames = aNames;
580  mbTableColumnNamesDirty = bTableColumnNamesDirty;
581  }
582 
583  // MoveTo() is not necessary if only the sheet changed.
584 
585  SetModified(bChanged);
586 
587 }
588 
589 bool ScDBData::UpdateReference(const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
590  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
591  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
592  SCCOL nDx, SCROW nDy, SCTAB nDz)
593 {
594  SCCOL theCol1;
595  SCROW theRow1;
596  SCTAB theTab1;
597  SCCOL theCol2;
598  SCROW theRow2;
599  SCTAB theTab2;
600  GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
601  theTab2 = theTab1;
602  SCCOL nOldCol1 = theCol1, nOldCol2 = theCol2;
603 
604  ScRefUpdateRes eRet
605  = ScRefUpdate::Update(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx,
606  nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
607 
608  bool bDoUpdate = eRet != UR_NOTHING;
609 
610  if (bDoUpdate && eRet != UR_INVALID)
611  {
612  // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
613  AdjustTableColumnNames( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
614  ::std::vector<OUString> aNames( maTableColumnNames);
615  bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
616  // tdf#48025, tdf#141946: update the column index of the filter criteria,
617  // when the deleted/inserted columns are inside the data range
618  if (HasAutoFilter() && theCol1 - nOldCol1 != theCol2 - nOldCol2)
619  MoveTo(theTab1, theCol1, theRow1, theCol2, theRow2, nCol1);
620  else
621  MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
622  // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
623  maTableColumnNames = aNames;
624  mbTableColumnNamesDirty = bTableColumnNamesDirty;
625  }
626 
627  ScRange aRangeAdvSource;
628  if ( GetAdvancedQuerySource(aRangeAdvSource) )
629  {
630  aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
631  if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
632  nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
633  theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
634  {
635  aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
636  aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
637  SetAdvancedQuerySource( &aRangeAdvSource );
638 
639  bDoUpdate = true; // DBData is modified
640  }
641  }
642 
643  SetModified(bDoUpdate);
644 
645  return eRet == UR_INVALID;
646 
647  //TODO: check if something was deleted/inserted with-in the range !!!
648 }
649 
651 {
652  // Extend the DB area to include data rows immediately below.
653  SCCOL nOldCol1 = nStartCol, nOldCol2 = nEndCol;
654  SCROW nOldEndRow = nEndRow;
655  rDoc.GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
656  // nOldEndRow==rDoc.MaxRow() may easily happen when selecting whole columns and
657  // setting an AutoFilter (i.e. creating an anonymous database-range). We
658  // certainly don't want to iterate over nearly a million empty cells, but
659  // keep only an intentionally user selected range.
660  if (nOldEndRow < rDoc.MaxRow() && nEndRow < nOldEndRow)
661  nEndRow = nOldEndRow;
662  if (nStartCol != nOldCol1 || nEndCol != nOldCol2)
663  {
664  SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
666  }
667 }
668 
670 {
671  if (mpContainer && bHasHeader)
672  {
674  if (!rDoc.IsClipOrUndo())
675  rDoc.StartListeningArea( GetHeaderArea(), false, this);
676  }
677 }
678 
680 {
681  EndListeningAll();
682 }
683 
684 void ScDBData::SetTableColumnNames( const ::std::vector< OUString >& rNames )
685 {
686  maTableColumnNames = rNames;
687  mbTableColumnNamesDirty = false;
688 }
689 
691  SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2 )
692 {
693  if (maTableColumnNames.empty())
694  return;
695 
696  SCCOL nDiff1 = nNewCol1 - nOldCol1;
697  SCCOL nDiff2 = nNewCol2 - nOldCol2;
698  if (nDiff1 == nDiff2)
699  return; // not moved or entirely moved, nothing to do
700 
701  ::std::vector<OUString> aNewNames;
702  if (eUpdateRefMode == URM_INSDEL)
703  {
704  if (nDx > 0)
705  mbTableColumnNamesDirty = true; // inserted columns will have empty names
706 
707  // nCol1 is the first column of the block that gets shifted, determine
708  // the head and tail elements that are to be copied for deletion or
709  // insertion.
710  size_t nHead = static_cast<size_t>(::std::max( nCol1 + std::min<SCCOL>(nDx, 0) - nOldCol1, 0));
711  size_t nTail = static_cast<size_t>(::std::max( nOldCol2 - nCol1 + 1, 0));
712  size_t n = nHead + nTail;
713  if (0 < n && n <= maTableColumnNames.size())
714  {
715  if (nDx > 0)
716  n += nDx;
717  aNewNames.resize(n);
718  // Copy head.
719  for (size_t i = 0; i < nHead; ++i)
720  {
721  aNewNames[i] = maTableColumnNames[i];
722  }
723  // Copy tail, inserted middle range, if any, stays empty.
724  for (size_t i = n - nTail, j = maTableColumnNames.size() - nTail; i < n; ++i, ++j)
725  {
726  aNewNames[i] = maTableColumnNames[j];
727  }
728  }
729  } // else empty aNewNames invalidates names/offsets
730 
731  SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
732  "sc.core", "ScDBData::AdjustTableColumnNames - invalidating column names/offsets");
733  aNewNames.swap( maTableColumnNames);
734  if (maTableColumnNames.empty())
737  InvalidateTableColumnNames( false); // preserve new column names array
738 }
739 
740 void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames )
741 {
743  if (bSwapToEmptyNames && !maTableColumnNames.empty())
744  ::std::vector<OUString>().swap( maTableColumnNames);
745  if (mpContainer)
746  {
747  // Add header range to dirty list.
748  if (HasHeader())
750  else
751  {
752  // We need *some* range in the dirty list even without header area,
753  // otherwise the container would not attempt to call a refresh.
755  }
756  }
757 }
758 
759 namespace {
760 class TableColumnNameSearch
761 {
762 public:
763  explicit TableColumnNameSearch( const OUString& rSearchName ) :
764  maSearchName( rSearchName )
765  {
766  }
767 
768  bool operator()( const OUString& rName ) const
769  {
770  return ScGlobal::GetTransliteration().isEqual( maSearchName, rName);
771  }
772 
773 private:
774  OUString maSearchName;
775 };
776 
781 void SetTableColumnName( ::std::vector<OUString>& rVec, size_t nIndex, const OUString& rName, size_t nCount )
782 {
783  OUString aStr;
784  do
785  {
786  if (nCount)
787  aStr = rName + OUString::number( nCount);
788  else
789  {
790  aStr = rName;
791  ++nCount;
792  }
793 
794  if (std::none_of( rVec.begin(), rVec.end(), TableColumnNameSearch( aStr)))
795  {
796  rVec[nIndex] = aStr;
797  break; // do while
798  }
799  ++nCount;
800  } while(true);
801 }
802 }
803 
805 {
806  ::std::vector<OUString> aNewNames;
807  aNewNames.resize( nEndCol - nStartCol + 1);
808  bool bHaveEmpty = false;
809  if (!HasHeader() || !pDoc)
810  bHaveEmpty = true; // Assume we have empty ones and fill below.
811  else
812  {
813  ScHorizontalCellIterator aIter(*pDoc, nTable, nStartCol, nStartRow, nEndCol, nStartRow); // header row only
814  ScRefCellValue* pCell;
815  SCCOL nCol, nLastColFilled = nStartCol - 1;
816  SCROW nRow;
817  for (size_t i=0; (pCell = aIter.GetNext( nCol, nRow)) != nullptr; ++i)
818  {
819  if (pCell->hasString())
820  {
821  const OUString& rStr = pCell->getString( pDoc);
822  if (rStr.isEmpty())
823  bHaveEmpty = true;
824  else
825  {
826  SetTableColumnName( aNewNames, nCol-nStartCol, rStr, 0);
827  if (nLastColFilled < nCol-1)
828  bHaveEmpty = true;
829  }
830  nLastColFilled = nCol;
831  }
832  else
833  bHaveEmpty = true;
834  }
835  }
836 
837  // Never leave us with empty names, try to remember previous name that
838  // might had been used to compile formulas, but only if same number of
839  // columns and no duplicates.
840  if (bHaveEmpty && aNewNames.size() == maTableColumnNames.size())
841  {
842  bHaveEmpty = false;
843  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
844  {
845  if (aNewNames[i].isEmpty())
846  {
847  const OUString& rStr = maTableColumnNames[i];
848  if (rStr.isEmpty())
849  bHaveEmpty = true;
850  else
851  SetTableColumnName( aNewNames, i, rStr, 0);
852  }
853  }
854  }
855 
856  // If we still have empty ones then fill those with "Column#" with #
857  // starting at the column offset number. Still no duplicates of course.
858  if (bHaveEmpty)
859  {
860  OUString aColumn( ScResId(STR_COLUMN));
861  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
862  {
863  if (aNewNames[i].isEmpty())
864  SetTableColumnName( aNewNames, i, aColumn, i+1);
865  }
866  }
867 
868  aNewNames.swap( maTableColumnNames);
869  mbTableColumnNamesDirty = false;
870 }
871 
873 {
874  // Header-less tables get names generated, completely empty a full refresh.
876  {
878  return;
879  }
880 
881  // Check if this is affected for the range requested.
882  ScRange aIntersection( GetHeaderArea().Intersection( rRange));
883  if (!aIntersection.IsValid())
884  return;
885 
886  // Always fully refresh, only one cell of a range was broadcasted per area
887  // listener if multiple cells were affected. We don't know if there were
888  // more. Also, we need the full check anyway in case a duplicated name was
889  // entered.
891 }
892 
893 sal_Int32 ScDBData::GetColumnNameOffset( const OUString& rName ) const
894 {
895  if (maTableColumnNames.empty())
896  return -1;
897 
898  ::std::vector<OUString>::const_iterator it(
899  ::std::find_if( maTableColumnNames.begin(), maTableColumnNames.end(), TableColumnNameSearch( rName)));
900  if (it != maTableColumnNames.end())
901  return it - maTableColumnNames.begin();
902 
903  return -1;
904 }
905 
906 const OUString& ScDBData::GetTableColumnName( SCCOL nCol ) const
907 {
908  if (maTableColumnNames.empty())
909  return EMPTY_OUSTRING;
910 
911  SCCOL nOffset = nCol - nStartCol;
912  if (nOffset < 0 || maTableColumnNames.size() <= o3tl::make_unsigned(nOffset))
913  return EMPTY_OUSTRING;
914 
915  return maTableColumnNames[nOffset];
916 }
917 
918 void ScDBData::Notify( const SfxHint& rHint )
919 {
920  const ScHint* pScHint = dynamic_cast<const ScHint*>(&rHint);
921  if (!pScHint)
922  return;
923 
924  if (pScHint->GetId() != SfxHintId::ScDataChanged)
925  return;
926 
928  if (!mpContainer)
929  assert(!"ScDBData::Notify - how did we end up here without container?");
930  else
931  {
932  // Only one cell of a range is broadcasted per area listener if
933  // multiple cells are affected. Expand the range to what this is
934  // listening to. Broadcasted address outside should not happen,
935  // but... let it trigger a refresh if.
936  ScRange aHeaderRange( GetHeaderArea());
937  if (aHeaderRange.IsValid())
938  {
939  mpContainer->GetDirtyTableColumnNames().Join( aHeaderRange);
940  if (!aHeaderRange.In( pScHint->GetAddress()))
942  }
943  else
945  }
946 
947  // Do not refresh column names here, which might trigger unwanted
948  // recalculation.
949 }
950 
951 void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount )
952 {
953  SCSIZE nTotal = nEndRow - nStartRow + 1;
954  if ( bHasHeader )
955  nTotal -= 1;
956  nFilteredRowCount = nTotal - nNonFilteredRowCount;
957 }
958 
959 void ScDBData::GetFilterSelCount( SCSIZE& nSelected, SCSIZE& nTotal )
960 {
961  nTotal = nEndRow - nStartRow + 1;
962  if ( bHasHeader )
963  nTotal -= 1;
965  nSelected = nTotal - nFilteredRowCount;
966  else
967  nSelected = nFilteredRowCount;
968 }
969 
970 namespace {
971 
972 class FindByTable
973 {
974  SCTAB mnTab;
975 public:
976  explicit FindByTable(SCTAB nTab) : mnTab(nTab) {}
977 
978  bool operator() (std::unique_ptr<ScDBData> const& p) const
979  {
980  ScRange aRange;
981  p->GetArea(aRange);
982  return aRange.aStart.Tab() == mnTab;
983  }
984 };
985 
986 class UpdateMoveTabFunc
987 {
988  SCTAB mnOldTab;
989  SCTAB mnNewTab;
990 public:
991  UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
992  void operator() (std::unique_ptr<ScDBData> const& p)
993  {
994  p->UpdateMoveTab(mnOldTab, mnNewTab);
995  }
996 };
997 
998 class FindByCursor
999 {
1000  SCCOL mnCol;
1001  SCROW mnRow;
1002  SCTAB mnTab;
1003  ScDBDataPortion mePortion;
1004 public:
1005  FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) :
1006  mnCol(nCol), mnRow(nRow), mnTab(nTab), mePortion(ePortion) {}
1007 
1008  bool operator() (std::unique_ptr<ScDBData> const& p)
1009  {
1010  return p->IsDBAtCursor(mnCol, mnRow, mnTab, mePortion);
1011  }
1012 };
1013 
1014 class FindByRange
1015 {
1016  const ScRange& mrRange;
1017 public:
1018  explicit FindByRange(const ScRange& rRange) : mrRange(rRange) {}
1019 
1020  bool operator() (std::unique_ptr<ScDBData> const& p)
1021  {
1022  return p->IsDBAtArea(
1023  mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
1024  }
1025 };
1026 
1027 class FindByIndex
1028 {
1029  sal_uInt16 mnIndex;
1030 public:
1031  explicit FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
1032  bool operator() (std::unique_ptr<ScDBData> const& p) const
1033  {
1034  return p->GetIndex() == mnIndex;
1035  }
1036 };
1037 
1038 class FindByUpperName
1039 {
1040  const OUString& mrName;
1041 public:
1042  explicit FindByUpperName(const OUString& rName) : mrName(rName) {}
1043  bool operator() (std::unique_ptr<ScDBData> const& p) const
1044  {
1045  return p->GetUpperName() == mrName;
1046  }
1047 };
1048 
1049 class FindByPointer
1050 {
1051  const ScDBData* mpDBData;
1052 public:
1053  explicit FindByPointer(const ScDBData* pDBData) : mpDBData(pDBData) {}
1054  bool operator() (std::unique_ptr<ScDBData> const& p) const
1055  {
1056  return p.get() == mpDBData;
1057  }
1058 };
1059 
1060 }
1061 
1063 {
1064  return mrDoc;
1065 }
1066 
1068 {
1069  return maDirtyTableColumnNames;
1070 }
1071 
1073  ScDBDataContainerBase(rDoc), mrParent(rParent) {}
1074 
1076  : ScDBDataContainerBase(r.mrDoc)
1077  , mrParent(rParent)
1078 {
1079  for (auto const& it : r.m_DBs)
1080  {
1081  ScDBData* p = new ScDBData(*it);
1082  std::unique_ptr<ScDBData> pData(p);
1083  if (m_DBs.insert( std::move(pData)).second)
1084  initInserted(p);
1085  }
1086 }
1087 
1089 {
1090 }
1091 
1093 {
1094  p->SetContainer( this);
1095  if (mrDoc.IsClipOrUndo())
1096  return;
1097 
1098  p->StartTableColumnNamesListener(); // needs the container be set already
1099  if (!p->AreTableColumnNamesDirty())
1100  return;
1101 
1102  if (p->HasHeader())
1103  {
1104  // Refresh table column names in next round.
1105  maDirtyTableColumnNames.Join( p->GetHeaderArea());
1106  }
1107  else
1108  {
1109  // Header-less table can generate its column names
1110  // already without accessing the document.
1111  p->RefreshTableColumnNames( nullptr);
1112  }
1113 }
1114 
1116 {
1117  return m_DBs.begin();
1118 }
1119 
1121 {
1122  return m_DBs.end();
1123 }
1124 
1126 {
1127  return m_DBs.begin();
1128 }
1129 
1131 {
1132  return m_DBs.end();
1133 }
1134 
1136 {
1137  DBsType::iterator itr = find_if(
1138  m_DBs.begin(), m_DBs.end(), FindByIndex(nIndex));
1139  return itr == m_DBs.end() ? nullptr : itr->get();
1140 }
1141 
1143 {
1144  DBsType::iterator itr = find_if(
1145  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1146  return itr == m_DBs.end() ? nullptr : itr->get();
1147 }
1148 
1150 {
1151  return find_if(
1152  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1153 }
1154 
1155 bool ScDBCollection::NamedDBs::insert(std::unique_ptr<ScDBData> pData)
1156 {
1157  auto p = pData.get();
1158  if (!pData->GetIndex())
1159  pData->SetIndex(mrParent.nEntryIndex++);
1160 
1161  pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
1162 
1163  if (r.second)
1164  {
1165  initInserted(p);
1166 
1167  /* TODO: shouldn't the import refresh not be setup for
1168  * clipboard/undo documents? It was already like this before... */
1169  if (p->HasImportParam() && !p->HasImportSelection())
1170  {
1171  p->SetRefreshHandler(mrParent.GetRefreshHandler());
1172  p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
1173  }
1174  }
1175  return r.second;
1176 }
1177 
1179 {
1180  m_DBs.erase(itr);
1181 }
1182 
1184 {
1185  return m_DBs.empty();
1186 }
1187 
1189 {
1190  return m_DBs.size();
1191 }
1192 
1194 {
1195  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1196 }
1197 
1199 {
1200  return m_DBs.begin();
1201 }
1202 
1204 {
1205  return m_DBs.end();
1206 }
1207 
1209 {
1210  return m_DBs.begin();
1211 }
1212 
1214 {
1215  return m_DBs.end();
1216 }
1217 
1219  ScDBDataPortion ePortion) const
1220 {
1221  DBsType::const_iterator itr = find_if(
1222  m_DBs.begin(), m_DBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1223  return itr == m_DBs.end() ? nullptr : itr->get();
1224 }
1225 
1227 {
1228  DBsType::const_iterator itr = find_if(
1229  m_DBs.begin(), m_DBs.end(), FindByRange(rRange));
1230  return itr == m_DBs.end() ? nullptr : itr->get();
1231 }
1232 
1234 {
1235  FindByTable func(nTab);
1236  m_DBs.erase(std::remove_if(m_DBs.begin(), m_DBs.end(), func), m_DBs.end());
1237 }
1238 
1240 {
1241  const ScDBData* pData = findByRange(rRange);
1242  if (!pData)
1243  {
1244  // Insert a new db data. They all have identical names.
1245  ::std::unique_ptr<ScDBData> pNew(new ScDBData(
1246  STR_DB_GLOBAL_NONAME, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
1247  rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
1248  pData = pNew.get();
1249  m_DBs.push_back(std::move(pNew));
1250  }
1251  return const_cast<ScDBData*>(pData);
1252 }
1253 
1255 {
1256  m_DBs.push_back(std::unique_ptr<ScDBData>(p));
1257 }
1258 
1260  m_DBs.erase(itr);
1261 }
1262 
1264 {
1265  return m_DBs.empty();
1266 }
1267 
1269 {
1270  return any_of(m_DBs.begin(), m_DBs.end(), FindByPointer(p));
1271 }
1272 
1274 {
1275  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1276 }
1277 
1279 {
1280 }
1281 
1283 {
1284  m_DBs.reserve(r.m_DBs.size());
1285  for (auto const& it : r.m_DBs)
1286  {
1287  m_DBs.push_back(std::make_unique<ScDBData>(*it));
1288  }
1289 }
1290 
1292  rDoc(rDocument), nEntryIndex(1), maNamedDBs(*this, rDocument) {}
1293 
1295  rDoc(r.rDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs, *this), maAnonDBs(r.maAnonDBs) {}
1296 
1297 const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
1298 {
1299  // First, search the global named db ranges.
1300  NamedDBs::DBsType::const_iterator itr = find_if(
1301  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1302  if (itr != maNamedDBs.end())
1303  return itr->get();
1304 
1305  // Check for the sheet-local anonymous db range.
1306  const ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1307  if (pNoNameData)
1308  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1309  return pNoNameData;
1310 
1311  // Check the global anonymous db ranges.
1312  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1313  if (pData)
1314  return pData;
1315 
1316  // Do NOT check for the document global temporary anonymous db range here.
1317 
1318  return nullptr;
1319 }
1320 
1322 {
1323  // First, search the global named db ranges.
1324  NamedDBs::DBsType::iterator itr = find_if(
1325  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1326  if (itr != maNamedDBs.end())
1327  return itr->get();
1328 
1329  // Check for the sheet-local anonymous db range.
1330  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1331  if (pNoNameData)
1332  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1333  return pNoNameData;
1334 
1335  // Check the global anonymous db ranges.
1336  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1337  if (pData)
1338  return const_cast<ScDBData*>(pData);
1339 
1340  // Do NOT check for the document global temporary anonymous db range here.
1341 
1342  return nullptr;
1343 }
1344 
1345 const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
1346 {
1347  // First, search the global named db ranges.
1348  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1349  NamedDBs::DBsType::const_iterator itr = find_if(
1350  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1351  if (itr != maNamedDBs.end())
1352  return itr->get();
1353 
1354  // Check for the sheet-local anonymous db range.
1355  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1356  if (pNoNameData)
1357  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1358  return pNoNameData;
1359 
1360  // Lastly, check the global anonymous db ranges.
1361  const ScDBData* pData = maAnonDBs.findByRange(aRange);
1362  if (pData)
1363  return pData;
1364 
1365  // As a last resort, check for the document global temporary anonymous db range.
1366  pNoNameData = rDoc.GetAnonymousDBData();
1367  if (pNoNameData)
1368  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1369  return pNoNameData;
1370 
1371  return nullptr;
1372 }
1373 
1375 {
1376  // First, search the global named db ranges.
1377  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1378  NamedDBs::DBsType::iterator itr = find_if(
1379  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1380  if (itr != maNamedDBs.end())
1381  return itr->get();
1382 
1383  // Check for the sheet-local anonymous db range.
1384  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1385  if (pNoNameData)
1386  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1387  return pNoNameData;
1388 
1389  // Lastly, check the global anonymous db ranges.
1390  const ScDBData* pData = getAnonDBs().findByRange(aRange);
1391  if (pData)
1392  return const_cast<ScDBData*>(pData);
1393 
1394  // As a last resort, check for the document global temporary anonymous db range.
1395  pNoNameData = rDoc.GetAnonymousDBData();
1396  if (pNoNameData)
1397  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1398  return pNoNameData;
1399 
1400  return nullptr;
1401 }
1402 
1404 {
1405  for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
1406  {
1407  const ScRange & rRange = maNamedDBs.maDirtyTableColumnNames[i];
1408  for (auto const& it : maNamedDBs)
1409  {
1410  if (it->AreTableColumnNamesDirty())
1411  it->RefreshTableColumnNames( &maNamedDBs.mrDoc, rRange);
1412  }
1413  }
1415 }
1416 
1418 {
1419  FindByTable func(nTab);
1420  // First, collect the positions of all items that need to be deleted.
1421  ::std::vector<NamedDBs::DBsType::iterator> v;
1422  {
1423  NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
1424  for (; itr != itrEnd; ++itr)
1425  {
1426  if (func(*itr))
1427  v.push_back(itr);
1428  }
1429  }
1430 
1431  // Delete them all.
1432  for (const auto& rIter : v)
1433  maNamedDBs.erase(rIter);
1434 
1435  maAnonDBs.deleteOnTab(nTab);
1436 }
1437 
1439  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1440  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1441  SCCOL nDx, SCROW nDy, SCTAB nDz )
1442 {
1444  if (pData)
1445  {
1446  if (nTab1 == nTab2 && nDz == 0)
1447  {
1448  // Delete the database range, if some part of the reference became invalid.
1449  if (pData->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1450  nTab2, nDx, nDy, nDz))
1451  rDoc.SetAnonymousDBData(nTab1, nullptr);
1452  }
1453  else
1454  {
1455  //this will perhaps break undo
1456  }
1457  }
1458 
1459  for (auto it = maNamedDBs.begin(); it != maNamedDBs.end(); )
1460  {
1461  // Delete the database range, if some part of the reference became invalid.
1462  if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1463  nTab2, nDx, nDy, nDz))
1464  maNamedDBs.erase(it++);
1465  else
1466  ++it;
1467  }
1468  for (auto it = maAnonDBs.begin(); it != maAnonDBs.end(); )
1469  {
1470  // Delete the database range, if some part of the reference became invalid.
1471  if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1472  nTab2, nDx, nDy, nDz))
1473  maAnonDBs.erase(it++);
1474  else
1475  ++it;
1476  }
1477 }
1478 
1480 {
1481  UpdateMoveTabFunc func(nOldPos, nNewPos);
1482  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1483  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1484 }
1485 
1487 {
1488  ScDBData* pNearData = nullptr;
1489  for (const auto& rxNamedDB : maNamedDBs)
1490  {
1491  SCTAB nAreaTab;
1492  SCCOL nStartCol, nEndCol;
1493  SCROW nStartRow, nEndRow;
1494  rxNamedDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1495  if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
1496  nRow+1 >= nStartRow && nRow <= nEndRow+1 )
1497  {
1498  if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
1499  {
1500  if (!pNearData)
1501  pNearData = rxNamedDB.get(); // remember first adjacent area
1502  }
1503  else
1504  return rxNamedDB.get(); // not "unbenannt"/"unnamed" and cursor within
1505  }
1506  }
1507  if (pNearData)
1508  return pNearData; // adjacent, if no direct hit
1509  return rDoc.GetAnonymousDBData(nTab); // "unbenannt"/"unnamed" only if nothing else
1510 }
1511 
1513 {
1514  return maNamedDBs.empty() && maAnonDBs.empty();
1515 }
1516 
1518 {
1519  return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
1521 }
1522 
1523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScDBData & operator=(const ScDBData &rData)
Definition: dbdata.cxx:159
ScDocument & mrDoc
Definition: dbdata.hxx:56
ScRefreshTimer & operator=(const ScRefreshTimer &r)
ScRange aAdvSource
source range
Definition: dbdata.hxx:87
ScRangeList maDirtyTableColumnNames
Definition: dbdata.hxx:57
bool insert(std::unique_ptr< ScDBData > p)
Takes ownership of p and attempts to insert it into the collection.
Definition: dbdata.cxx:1155
bool HasAutoFilter() const
Definition: dbdata.hxx:204
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
sal_Int32 nIndex
SC_DLLPUBLIC bool HasQueryParam() const
Definition: dbdata.cxx:524
ScAddress aStart
Definition: address.hxx:499
ScDBData * findByIndex(sal_uInt16 nIndex)
Definition: dbdata.cxx:1135
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:2132
void GetFilterSelCount(SCSIZE &nSelected, SCSIZE &nTotal)
Definition: dbdata.cxx:959
#define EMPTY_OUSTRING
Definition: global.hxx:214
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:89
SCCOL nCol1
selected area
Container base class to provide selected access for ScDBData.
Definition: dbdata.hxx:47
SC_DLLPUBLIC ScDBData * GetAnonymousDBData(SCTAB nTab)
Definition: document.cxx:307
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:413
SCROW Row() const
Definition: address.hxx:261
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:660
std::unique_ptr< ContentProperties > pData
bool empty() const
Definition: dbdata.cxx:1263
bool HasHeader() const
Definition: dbdata.hxx:130
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:401
SC_DLLPUBLIC void SetAnonymousDBData(SCTAB nTab, std::unique_ptr< ScDBData > pDBData)
Definition: document.cxx:319
bool bIsAdvanced
QueryParam.
Definition: dbdata.hxx:86
OUString GetSourceString() const
Definition: dbdata.cxx:258
long Long
const ScDBData * findByRange(const ScRange &rRange) const
Definition: dbdata.cxx:1226
sal_Int64 n
NamedDBs(ScDBCollection &rParent, ScDocument &rDoc)
Definition: dbdata.cxx:1072
sal_Int32 mnCol
aBuf
void InvalidateTableColumnNames(bool bSwapToEmptyNames)
Definition: dbdata.cxx:740
bool IsClipOrUndo() const
Definition: document.hxx:1532
SCCOLROW nField
Definition: queryentry.hxx:60
ScAddress aEnd
Definition: address.hxx:500
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
bool HasSubTotalParam() const
Definition: dbdata.cxx:542
SCROW nRow2
Definition: global.hxx:454
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:547
bool mbTableColumnNamesDirty
Definition: dbdata.hxx:96
SCCOL nStartCol
Definition: dbdata.hxx:74
bool bDoSize
Definition: dbdata.hxx:81
Some part of the reference became invalid.
Definition: refupdat.hxx:33
bool operator==(const ScDBData &rData) const
Definition: dbdata.cxx:211
bool has(const ScDBData *p) const
Definition: dbdata.cxx:1268
SfxHintId GetId() const
void ExtendDataArea(const ScDocument &rDoc)
Definition: dbdata.cxx:650
const ScAddress & GetAddress() const
Definition: brdcst.hxx:30
ScDBData * GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dbdata.cxx:1486
std::unique_ptr< ScSortParam > mpSortParam
Definition: dbdata.hxx:63
sal_uInt16 nEntryIndex
counter for unique indices
Definition: dbdata.hxx:307
bool IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:512
ScDBData * getByRange(const ScRange &rRange)
Definition: dbdata.cxx:1239
void SetModified(bool bMod)
Definition: dbdata.hxx:208
ScDocument & rDoc
Definition: dbdata.hxx:306
void SetImportParam(const ScImportParam &rImportParam)
Definition: dbdata.cxx:490
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:872
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
AnonDBs & getAnonDBs()
Definition: dbdata.hxx:318
bool hasString() const
Definition: cellvalue.cxx:617
void MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCCOL nUpdateCol=-1)
Definition: dbdata.cxx:344
int nCount
SCROW nStartRow
Definition: dbdata.hxx:75
void StartTableColumnNamesListener()
Definition: dbdata.cxx:669
SCCOL nCol2
Definition: global.hxx:453
SCTAB Tab() const
Definition: address.hxx:270
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:437
::std::vector< OUString > maTableColumnNames
names of table columns
Definition: dbdata.hxx:95
SCROW nRow1
Definition: global.hxx:452
bool operator()(const std::unique_ptr< ScDBData > &left, const std::unique_ptr< ScDBData > &right) const
Definition: dbdata.cxx:51
const ScDBData * GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:1345
Stores global anonymous database ranges.
Definition: dbdata.hxx:275
void SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dbdata.cxx:322
void EndListeningAll()
SC_DLLPUBLIC void GetDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow, bool bIncludeOld, bool bOnlyDown) const
Return the smallest area containing at least all contiguous cells having data.
Definition: document.cxx:1088
ScDBDataPortion
Enum used to indicate which portion of the DBArea is to be considered.
Definition: dbdata.hxx:40
void CalcSaveFilteredCount(SCSIZE nNonFilteredRowCount)
Definition: dbdata.cxx:951
bool bKeepFmt
Definition: dbdata.hxx:82
bool bAutoFilter
AutoFilter? (not saved)
Definition: dbdata.hxx:92
SCROW nEndRow
Definition: dbdata.hxx:77
SCCOL nEndCol
Definition: dbdata.hxx:76
const ScDBData * findAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1218
void UpdateReference(UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: dbdata.cxx:1438
const OUString aName
DBParam.
Definition: dbdata.hxx:71
int i
bool bHasTotals
Definition: dbdata.hxx:80
void UpdateFromSortParam(const ScSortParam &rSortParam)
Remember some more settings of ScSortParam, only to be called at anonymous DB ranges as it at least o...
Definition: dbdata.cxx:419
void SetContainer(ScDBDataContainerBase *pContainer)
Definition: dbdata.hxx:143
bool empty() const
Definition: dbdata.cxx:1512
bool operator==(const ScDBCollection &r) const
Definition: dbdata.cxx:1517
SC_DLLPUBLIC ScDBData(const OUString &rName, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bByR=true, bool bHasH=true, bool bTotals=false)
Definition: dbdata.cxx:56
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:405
void insert(ScDBData *p)
Definition: dbdata.cxx:1254
sal_Int16 SCCOL
Definition: types.hxx:21
OUString aUpper
Definition: dbdata.hxx:72
bool HasSortParam() const
Definition: dbdata.cxx:535
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1016
bool operator==(const AnonDBs &r) const
Definition: dbdata.cxx:1273
SC_DLLPUBLIC void SetAdvancedQuerySource(const ScRange *pSource)
Definition: dbdata.cxx:446
SCSIZE nFilteredRowCount
Definition: dbdata.hxx:97
const SCSIZE SCSIZE_MAX
Definition: address.hxx:59
void erase(const iterator &itr)
Definition: dbdata.cxx:1259
DBsType::iterator iterator
Definition: dbdata.hxx:249
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
size_t size() const
Definition: rangelst.hxx:89
virtual void Notify(const SfxHint &rHint) override
Definition: dbdata.cxx:918
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
void GetImportParam(ScImportParam &rImportParam) const
Definition: dbdata.cxx:480
std::unique_ptr< ScQueryParam > mpQueryParam
Definition: dbdata.hxx:64
void DeleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1417
SCTAB nTable
Definition: dbdata.hxx:73
void deleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1233
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:692
void initInserted(ScDBData *p)
Definition: dbdata.cxx:1092
bool In(const ScAddress &) const
is Address& in Range?
Definition: address.hxx:732
bool bByRow
Definition: dbdata.hxx:78
OUString GetOperations() const
Definition: dbdata.cxx:270
bool IsValid() const
Definition: address.hxx:546
bool IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:496
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:300
size_t size() const
Definition: dbdata.cxx:1188
void StopRefreshTimer()
Reference not affected, no change at all.
Definition: refupdat.hxx:31
SCCOL Col() const
Definition: address.hxx:266
sal_Int32 GetColumnNameOffset(const OUString &rName) const
Finds the column named rName and returns the corresponding offset within the table.
Definition: dbdata.cxx:893
void GetSubTotalParam(ScSubTotalParam &rSubTotalParam) const
Definition: dbdata.cxx:463
ScDBData * findByUpperName(const OUString &rName)
Definition: dbdata.cxx:1142
top left cell of area
DBsType::iterator iterator
Definition: dbdata.hxx:286
float v
Stores global named database ranges.
Definition: dbdata.hxx:234
UpdateRefMode
Definition: global.hxx:310
sal_Int32 SCROW
Definition: types.hxx:17
void RefreshDirtyTableColumnNames()
Definition: dbdata.cxx:1403
void erase(const iterator &itr)
Definition: dbdata.cxx:1178
bool bHasHeader
Definition: sortparam.hxx:111
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:68
#define SAL_WARN_IF(condition, area, stream)
ScRangeList & GetDirtyTableColumnNames()
Definition: dbdata.cxx:1067
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:164
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:287
#define STR_DB_GLOBAL_NONAME
Definition: globalnames.hxx:13
OUString aName
bool UpdateReference(const ScDocument *pDoc, UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: dbdata.cxx:589
virtual ~NamedDBs() override
Definition: dbdata.cxx:1088
const OUString & GetTableColumnName(SCCOL nCol) const
Returns table column name if nCol is within column range and name is stored, else empty string...
Definition: dbdata.cxx:906
void AdjustTableColumnNames(UpdateRefMode eUpdateRefMode, SCCOL nDx, SCCOL nCol1, SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2)
Definition: dbdata.cxx:690
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:250
AnonDBs maAnonDBs
Definition: dbdata.hxx:309
bool empty() const
Definition: dbdata.cxx:1183
bool bDBSelection
not in Param: if selection, block update
Definition: dbdata.hxx:89
const ScDBData * GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1297
ScRefUpdateRes
Definition: refupdat.hxx:30
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:424
bool AreTableColumnNamesDirty() const
Definition: dbdata.hxx:150
void EndTableColumnNamesListener()
Definition: dbdata.cxx:679
std::unique_ptr< ScImportParam > mpImportParam
Definition: dbdata.hxx:66
bool bHasHeader
Definition: dbdata.hxx:79
bool bModified
is set/cleared for/by(?) UpdateReference
Definition: dbdata.hxx:93
ScDocument & GetDocument() const
Definition: dbdata.cxx:1062
iterator findByUpperName2(const OUString &rName)
Definition: dbdata.cxx:1149
SCCOL nCol1
Definition: global.hxx:451
ScRange GetHeaderArea() const
Returns header row range if has headers, else invalid range.
Definition: dbdata.cxx:315
void SetSubTotalParam(const ScSubTotalParam &rSubTotalParam)
Definition: dbdata.cxx:475
SC_DLLPUBLIC bool GetAdvancedQuerySource(ScRange &rSource) const
Definition: dbdata.cxx:457
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:1479
ScDBCollection(ScDocument &rDocument)
Definition: dbdata.cxx:1291
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
SC_DLLPUBLIC void RefreshTableColumnNames(ScDocument *pDoc)
Refresh/update the column names with the header row's cell contents.
Definition: dbdata.cxx:804
std::unique_ptr< ScSubTotalParam > mpSubTotal
Definition: dbdata.hxx:65
sal_Int32 mnRow
static SC_DLLPUBLIC::utl::TransliterationWrapper & GetTransliteration()
Definition: global.cxx:978
virtual SC_DLLPUBLIC ~ScDBData() override
Definition: dbdata.cxx:253
int mnIndex
bool bStripData
Definition: dbdata.hxx:83
BaseContainerNodeSharedPtr & mrParent
aStr
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
SC_DLLPUBLIC void SetTableColumnNames(const ::std::vector< OUString > &rNames)
Definition: dbdata.cxx:684
void RemoveAll()
Definition: rangelst.cxx:1105
bool HasImportParam() const
Definition: dbdata.cxx:519
sal_Int16 SCTAB
Definition: types.hxx:22
Link< Timer *, void > aRefreshHandler
Definition: dbdata.hxx:305
NamedDBs maNamedDBs
Definition: dbdata.hxx:308
sal_uInt16 nIndex
unique index formulas
Definition: dbdata.hxx:91
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:80
bool operator==(const NamedDBs &r) const
Definition: dbdata.cxx:1193