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),
81  nIndex (0),
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(), aRange.aEnd.Col(),
577  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 bool ScDBData::UpdateReference(const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
589  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
590  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
591  SCCOL nDx, SCROW nDy, SCTAB nDz)
592 {
593  SCCOL theCol1;
594  SCROW theRow1;
595  SCTAB theTab1;
596  SCCOL theCol2;
597  SCROW theRow2;
598  SCTAB theTab2;
599  GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
600  theTab2 = theTab1;
601  SCCOL nOldCol1 = theCol1, nOldCol2 = theCol2;
602 
603  ScRefUpdateRes eRet
604  = ScRefUpdate::Update(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx,
605  nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
606 
607  bool bDoUpdate = eRet != UR_NOTHING;
608 
609  if (bDoUpdate && eRet != UR_INVALID)
610  {
611  // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
612  AdjustTableColumnNames( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
613  ::std::vector<OUString> aNames( maTableColumnNames);
614  bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
615  // tdf#48025, tdf#141946: update the column index of the filter criteria,
616  // when the deleted/inserted columns are inside the data range
617  if (HasAutoFilter() && theCol1 - nOldCol1 != theCol2 - nOldCol2)
618  MoveTo(theTab1, theCol1, theRow1, theCol2, theRow2, nCol1);
619  else
620  MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
621  // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
622  maTableColumnNames = aNames;
623  mbTableColumnNamesDirty = bTableColumnNamesDirty;
624  }
625 
626  ScRange aRangeAdvSource;
627  if ( GetAdvancedQuerySource(aRangeAdvSource) )
628  {
629  aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
630  if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
631  nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
632  theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
633  {
634  aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
635  aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
636  SetAdvancedQuerySource( &aRangeAdvSource );
637 
638  bDoUpdate = true; // DBData is modified
639  }
640  }
641 
642  SetModified(bDoUpdate);
643 
644  return eRet == UR_INVALID;
645 
646  //TODO: check if something was deleted/inserted with-in the range !!!
647 }
648 
650 {
651  // Extend the DB area to include data rows immediately below.
652  SCCOL nOldCol1 = nStartCol, nOldCol2 = nEndCol;
653  SCROW nOldEndRow = nEndRow;
654  rDoc.GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
655  // nOldEndRow==rDoc.MaxRow() may easily happen when selecting whole columns and
656  // setting an AutoFilter (i.e. creating an anonymous database-range). We
657  // certainly don't want to iterate over nearly a million empty cells, but
658  // keep only an intentionally user selected range.
659  if (nOldEndRow < rDoc.MaxRow() && nEndRow < nOldEndRow)
660  nEndRow = nOldEndRow;
661  if (nStartCol != nOldCol1 || nEndCol != nOldCol2)
662  {
663  SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
665  }
666 }
667 
669 {
670  if (mpContainer && bHasHeader)
671  {
673  if (!rDoc.IsClipOrUndo())
674  rDoc.StartListeningArea( GetHeaderArea(), false, this);
675  }
676 }
677 
679 {
680  EndListeningAll();
681 }
682 
683 void ScDBData::SetTableColumnNames( ::std::vector< OUString >&& rNames )
684 {
685  maTableColumnNames = std::move(rNames);
686  mbTableColumnNamesDirty = false;
687 }
688 
690  SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2 )
691 {
692  if (maTableColumnNames.empty())
693  return;
694 
695  SCCOL nDiff1 = nNewCol1 - nOldCol1;
696  SCCOL nDiff2 = nNewCol2 - nOldCol2;
697  if (nDiff1 == nDiff2)
698  return; // not moved or entirely moved, nothing to do
699 
700  ::std::vector<OUString> aNewNames;
701  if (eUpdateRefMode == URM_INSDEL)
702  {
703  if (nDx > 0)
704  mbTableColumnNamesDirty = true; // inserted columns will have empty names
705 
706  // nCol1 is the first column of the block that gets shifted, determine
707  // the head and tail elements that are to be copied for deletion or
708  // insertion.
709  size_t nHead = static_cast<size_t>(::std::max( nCol1 + std::min<SCCOL>(nDx, 0) - nOldCol1, 0));
710  size_t nTail = static_cast<size_t>(::std::max( nOldCol2 - nCol1 + 1, 0));
711  size_t n = nHead + nTail;
712  if (0 < n && n <= maTableColumnNames.size())
713  {
714  if (nDx > 0)
715  n += nDx;
716  aNewNames.resize(n);
717  // Copy head.
718  for (size_t i = 0; i < nHead; ++i)
719  {
720  aNewNames[i] = maTableColumnNames[i];
721  }
722  // Copy tail, inserted middle range, if any, stays empty.
723  for (size_t i = n - nTail, j = maTableColumnNames.size() - nTail; i < n; ++i, ++j)
724  {
725  aNewNames[i] = maTableColumnNames[j];
726  }
727  }
728  } // else empty aNewNames invalidates names/offsets
729 
730  SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
731  "sc.core", "ScDBData::AdjustTableColumnNames - invalidating column names/offsets");
732  aNewNames.swap( maTableColumnNames);
733  if (maTableColumnNames.empty())
736  InvalidateTableColumnNames( false); // preserve new column names array
737 }
738 
739 void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames )
740 {
742  if (bSwapToEmptyNames && !maTableColumnNames.empty())
743  ::std::vector<OUString>().swap( maTableColumnNames);
744  if (mpContainer)
745  {
746  // Add header range to dirty list.
747  if (HasHeader())
749  else
750  {
751  // We need *some* range in the dirty list even without header area,
752  // otherwise the container would not attempt to call a refresh.
754  }
755  }
756 }
757 
758 namespace {
759 class TableColumnNameSearch
760 {
761 public:
762  explicit TableColumnNameSearch( const OUString& rSearchName ) :
763  maSearchName( rSearchName )
764  {
765  }
766 
767  bool operator()( const OUString& rName ) const
768  {
769  return ScGlobal::GetTransliteration().isEqual( maSearchName, rName);
770  }
771 
772 private:
773  OUString maSearchName;
774 };
775 
780 void SetTableColumnName( ::std::vector<OUString>& rVec, size_t nIndex, const OUString& rName, size_t nCount )
781 {
782  OUString aStr;
783  do
784  {
785  if (nCount)
786  aStr = rName + OUString::number( nCount);
787  else
788  {
789  aStr = rName;
790  ++nCount;
791  }
792 
793  if (std::none_of( rVec.begin(), rVec.end(), TableColumnNameSearch( aStr)))
794  {
795  rVec[nIndex] = aStr;
796  break; // do while
797  }
798  ++nCount;
799  } while(true);
800 }
801 }
802 
804 {
805  ::std::vector<OUString> aNewNames;
806  aNewNames.resize( nEndCol - nStartCol + 1);
807  bool bHaveEmpty = false;
808  if (!HasHeader() || !pDoc)
809  bHaveEmpty = true; // Assume we have empty ones and fill below.
810  else
811  {
812  ScHorizontalCellIterator aIter(*pDoc, nTable, nStartCol, nStartRow, nEndCol, nStartRow); // header row only
813  ScRefCellValue* pCell;
814  SCCOL nCol, nLastColFilled = nStartCol - 1;
815  SCROW nRow;
816  while ((pCell = aIter.GetNext( nCol, nRow)) != nullptr)
817  {
818  if (pCell->hasString())
819  {
820  const OUString& rStr = pCell->getString( pDoc);
821  if (rStr.isEmpty())
822  bHaveEmpty = true;
823  else
824  {
825  SetTableColumnName( aNewNames, nCol-nStartCol, rStr, 0);
826  if (nLastColFilled < nCol-1)
827  bHaveEmpty = true;
828  }
829  nLastColFilled = nCol;
830  }
831  else
832  bHaveEmpty = true;
833  }
834  }
835 
836  // Never leave us with empty names, try to remember previous name that
837  // might had been used to compile formulas, but only if same number of
838  // columns and no duplicates.
839  if (bHaveEmpty && aNewNames.size() == maTableColumnNames.size())
840  {
841  bHaveEmpty = false;
842  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
843  {
844  if (aNewNames[i].isEmpty())
845  {
846  const OUString& rStr = maTableColumnNames[i];
847  if (rStr.isEmpty())
848  bHaveEmpty = true;
849  else
850  SetTableColumnName( aNewNames, i, rStr, 0);
851  }
852  }
853  }
854 
855  // If we still have empty ones then fill those with "Column#" with #
856  // starting at the column offset number. Still no duplicates of course.
857  if (bHaveEmpty)
858  {
859  OUString aColumn( ScResId(STR_COLUMN));
860  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
861  {
862  if (aNewNames[i].isEmpty())
863  SetTableColumnName( aNewNames, i, aColumn, i+1);
864  }
865  }
866 
867  aNewNames.swap( maTableColumnNames);
868  mbTableColumnNamesDirty = false;
869 }
870 
872 {
873  // Header-less tables get names generated, completely empty a full refresh.
875  {
877  return;
878  }
879 
880  // Check if this is affected for the range requested.
881  ScRange aIntersection( GetHeaderArea().Intersection( rRange));
882  if (!aIntersection.IsValid())
883  return;
884 
885  // Always fully refresh, only one cell of a range was broadcasted per area
886  // listener if multiple cells were affected. We don't know if there were
887  // more. Also, we need the full check anyway in case a duplicated name was
888  // entered.
890 }
891 
892 sal_Int32 ScDBData::GetColumnNameOffset( const OUString& rName ) const
893 {
894  if (maTableColumnNames.empty())
895  return -1;
896 
897  ::std::vector<OUString>::const_iterator it(
898  ::std::find_if( maTableColumnNames.begin(), maTableColumnNames.end(), TableColumnNameSearch( rName)));
899  if (it != maTableColumnNames.end())
900  return it - maTableColumnNames.begin();
901 
902  return -1;
903 }
904 
905 OUString ScDBData::GetTableColumnName( SCCOL nCol ) const
906 {
907  if (maTableColumnNames.empty())
908  return OUString();
909 
910  SCCOL nOffset = nCol - nStartCol;
911  if (nOffset < 0 || maTableColumnNames.size() <= o3tl::make_unsigned(nOffset))
912  return OUString();
913 
914  return maTableColumnNames[nOffset];
915 }
916 
917 void ScDBData::Notify( const SfxHint& rHint )
918 {
919  const ScHint* pScHint = dynamic_cast<const ScHint*>(&rHint);
920  if (!pScHint)
921  return;
922 
923  if (pScHint->GetId() != SfxHintId::ScDataChanged)
924  return;
925 
927  if (!mpContainer)
928  assert(!"ScDBData::Notify - how did we end up here without container?");
929  else
930  {
931  // Only one cell of a range is broadcasted per area listener if
932  // multiple cells are affected. Expand the range to what this is
933  // listening to. Broadcasted address outside should not happen,
934  // but... let it trigger a refresh if.
935  const ScRange aHeaderRange( GetHeaderArea());
936  ScAddress aHintAddress( pScHint->GetStartAddress());
937  if (aHeaderRange.IsValid())
938  {
939  mpContainer->GetDirtyTableColumnNames().Join( aHeaderRange);
940  // Header range is one row.
941  // The ScHint's "range" is an address with row count.
942  // Though broadcasted is usually only one cell, check for the
943  // possible case of row block and for one cell in the same row.
944  if (aHintAddress.Row() <= aHeaderRange.aStart.Row()
945  && aHeaderRange.aStart.Row() < aHintAddress.Row() + pScHint->GetRowCount())
946  {
947  aHintAddress.SetRow( aHeaderRange.aStart.Row());
948  if (!aHeaderRange.Contains( aHintAddress))
949  mpContainer->GetDirtyTableColumnNames().Join( aHintAddress);
950  }
951  }
952  else
953  {
954  // We need *some* range in the dirty list even without header area,
955  // otherwise the container would not attempt to call a refresh.
956  aHintAddress.SetRow( nStartRow);
957  mpContainer->GetDirtyTableColumnNames().Join( aHintAddress);
958  }
959  }
960 
961  // Do not refresh column names here, which might trigger unwanted
962  // recalculation.
963 }
964 
965 void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount )
966 {
967  SCSIZE nTotal = nEndRow - nStartRow + 1;
968  if ( bHasHeader )
969  nTotal -= 1;
970  nFilteredRowCount = nTotal - nNonFilteredRowCount;
971 }
972 
973 void ScDBData::GetFilterSelCount( SCSIZE& nSelected, SCSIZE& nTotal )
974 {
975  nTotal = nEndRow - nStartRow + 1;
976  if ( bHasHeader )
977  nTotal -= 1;
979  nSelected = nTotal - nFilteredRowCount;
980  else
981  nSelected = nFilteredRowCount;
982 }
983 
984 namespace {
985 
986 class FindByTable
987 {
988  SCTAB mnTab;
989 public:
990  explicit FindByTable(SCTAB nTab) : mnTab(nTab) {}
991 
992  bool operator() (std::unique_ptr<ScDBData> const& p) const
993  {
994  ScRange aRange;
995  p->GetArea(aRange);
996  return aRange.aStart.Tab() == mnTab;
997  }
998 };
999 
1000 class UpdateMoveTabFunc
1001 {
1002  SCTAB mnOldTab;
1003  SCTAB mnNewTab;
1004 public:
1005  UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
1006  void operator() (std::unique_ptr<ScDBData> const& p)
1007  {
1008  p->UpdateMoveTab(mnOldTab, mnNewTab);
1009  }
1010 };
1011 
1012 OUString lcl_IncrementNumberInNamedRange(ScDBCollection::NamedDBs& namedDBs,
1013  const OUString& sOldName)
1014 {
1015  sal_Int32 nLastIndex = sOldName.lastIndexOf('_') + 1;
1016  sal_Int32 nOldNumber = 1;
1017  if (nLastIndex >= 0)
1018  {
1019  std::u16string_view sLastPart(sOldName.subView(nLastIndex));
1020  nOldNumber = o3tl::toInt32(sLastPart);
1021 
1022  // When no number found, add number at the end.
1023  // When there is a literal "0" at the end, keep the "lastIndex" from above
1024  // (OUString::toInt32() also returns 0 on failure)
1025  if (nOldNumber == 0 && sLastPart != u"0")
1026  {
1027  nOldNumber = 1;
1028  nLastIndex = sOldName.getLength();
1029  }
1030  }
1031  else // No "_" found, add number at the end
1032  nLastIndex = sOldName.getLength();
1033  OUString sNewName;
1034  do
1035  {
1036  sNewName = sOldName.subView(0, nLastIndex) + OUString::number(++nOldNumber);
1037  } while (namedDBs.findByName(sNewName) != nullptr);
1038  return sNewName;
1039 }
1040 
1041 class FindByCursor
1042 {
1043  SCCOL mnCol;
1044  SCROW mnRow;
1045  SCTAB mnTab;
1046  ScDBDataPortion mePortion;
1047 public:
1048  FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) :
1049  mnCol(nCol), mnRow(nRow), mnTab(nTab), mePortion(ePortion) {}
1050 
1051  bool operator() (std::unique_ptr<ScDBData> const& p)
1052  {
1053  return p->IsDBAtCursor(mnCol, mnRow, mnTab, mePortion);
1054  }
1055 };
1056 
1057 class FindByRange
1058 {
1059  const ScRange& mrRange;
1060 public:
1061  explicit FindByRange(const ScRange& rRange) : mrRange(rRange) {}
1062 
1063  bool operator() (std::unique_ptr<ScDBData> const& p)
1064  {
1065  return p->IsDBAtArea(
1066  mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
1067  }
1068 };
1069 
1070 class FindByIndex
1071 {
1072  sal_uInt16 mnIndex;
1073 public:
1074  explicit FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
1075  bool operator() (std::unique_ptr<ScDBData> const& p) const
1076  {
1077  return p->GetIndex() == mnIndex;
1078  }
1079 };
1080 
1081 class FindByUpperName
1082 {
1083  const OUString& mrName;
1084 public:
1085  explicit FindByUpperName(const OUString& rName) : mrName(rName) {}
1086  bool operator() (std::unique_ptr<ScDBData> const& p) const
1087  {
1088  return p->GetUpperName() == mrName;
1089  }
1090 };
1091 
1092 class FindByName
1093 {
1094  const OUString& mrName;
1095 public:
1096  explicit FindByName(const OUString& rName) : mrName(rName) {}
1097  bool operator() (std::unique_ptr<ScDBData> const& p) const
1098  {
1099  return p->GetName() == mrName;
1100  }
1101 };
1102 
1103 class FindByPointer
1104 {
1105  const ScDBData* mpDBData;
1106 public:
1107  explicit FindByPointer(const ScDBData* pDBData) : mpDBData(pDBData) {}
1108  bool operator() (std::unique_ptr<ScDBData> const& p) const
1109  {
1110  return p.get() == mpDBData;
1111  }
1112 };
1113 
1114 }
1115 
1117 {
1118  return mrDoc;
1119 }
1120 
1122 {
1123  return maDirtyTableColumnNames;
1124 }
1125 
1127  ScDBDataContainerBase(rDoc), mrParent(rParent) {}
1128 
1130  : ScDBDataContainerBase(r.mrDoc)
1131  , mrParent(rParent)
1132 {
1133  for (auto const& it : r.m_DBs)
1134  {
1135  ScDBData* p = new ScDBData(*it);
1136  std::unique_ptr<ScDBData> pData(p);
1137  if (m_DBs.insert( std::move(pData)).second)
1138  initInserted(p);
1139  }
1140 }
1141 
1143 {
1144 }
1145 
1147 {
1148  p->SetContainer( this);
1149  if (mrDoc.IsClipOrUndo())
1150  return;
1151 
1152  p->StartTableColumnNamesListener(); // needs the container be set already
1153  if (!p->AreTableColumnNamesDirty())
1154  return;
1155 
1156  if (p->HasHeader())
1157  {
1158  // Refresh table column names in next round.
1159  maDirtyTableColumnNames.Join( p->GetHeaderArea());
1160  }
1161  else
1162  {
1163  // Header-less table can generate its column names
1164  // already without accessing the document.
1165  p->RefreshTableColumnNames( nullptr);
1166  }
1167 }
1168 
1170 {
1171  return m_DBs.begin();
1172 }
1173 
1175 {
1176  return m_DBs.end();
1177 }
1178 
1180 {
1181  return m_DBs.begin();
1182 }
1183 
1185 {
1186  return m_DBs.end();
1187 }
1188 
1190 {
1191  DBsType::iterator itr = find_if(
1192  m_DBs.begin(), m_DBs.end(), FindByIndex(nIndex));
1193  return itr == m_DBs.end() ? nullptr : itr->get();
1194 }
1195 
1197 {
1198  DBsType::iterator itr = find_if(
1199  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1200  return itr == m_DBs.end() ? nullptr : itr->get();
1201 }
1202 
1204 {
1205  return find_if(
1206  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1207 }
1208 
1210 {
1211  DBsType::iterator itr = find_if(m_DBs.begin(), m_DBs.end(), FindByName(rName));
1212  return itr == m_DBs.end() ? nullptr : itr->get();
1213 }
1214 
1215 bool ScDBCollection::NamedDBs::insert(std::unique_ptr<ScDBData> pData)
1216 {
1217  auto p = pData.get();
1218  if (!pData->GetIndex())
1219  pData->SetIndex(mrParent.nEntryIndex++);
1220 
1221  pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
1222 
1223  if (r.second)
1224  {
1225  initInserted(p);
1226 
1227  /* TODO: shouldn't the import refresh not be setup for
1228  * clipboard/undo documents? It was already like this before... */
1229  if (p->HasImportParam() && !p->HasImportSelection())
1230  {
1231  p->SetRefreshHandler(mrParent.GetRefreshHandler());
1232  p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
1233  }
1234  }
1235  return r.second;
1236 }
1237 
1239 {
1240  return m_DBs.erase(itr);
1241 }
1242 
1244 {
1245  return m_DBs.empty();
1246 }
1247 
1249 {
1250  return m_DBs.size();
1251 }
1252 
1254 {
1255  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1256 }
1257 
1259 {
1260  return m_DBs.begin();
1261 }
1262 
1264 {
1265  return m_DBs.end();
1266 }
1267 
1269 {
1270  return m_DBs.begin();
1271 }
1272 
1274 {
1275  return m_DBs.end();
1276 }
1277 
1279  ScDBDataPortion ePortion) const
1280 {
1281  DBsType::const_iterator itr = find_if(
1282  m_DBs.begin(), m_DBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1283  return itr == m_DBs.end() ? nullptr : itr->get();
1284 }
1285 
1287 {
1288  DBsType::const_iterator itr = find_if(
1289  m_DBs.begin(), m_DBs.end(), FindByRange(rRange));
1290  return itr == m_DBs.end() ? nullptr : itr->get();
1291 }
1292 
1294 {
1295  FindByTable func(nTab);
1296  m_DBs.erase(std::remove_if(m_DBs.begin(), m_DBs.end(), func), m_DBs.end());
1297 }
1298 
1300 {
1301  const ScDBData* pData = findByRange(rRange);
1302  if (!pData)
1303  {
1304  // Insert a new db data. They all have identical names.
1305  ::std::unique_ptr<ScDBData> pNew(new ScDBData(
1306  STR_DB_GLOBAL_NONAME, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
1307  rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
1308  pData = pNew.get();
1309  m_DBs.push_back(std::move(pNew));
1310  }
1311  return const_cast<ScDBData*>(pData);
1312 }
1313 
1315 {
1316  m_DBs.push_back(std::unique_ptr<ScDBData>(p));
1317 }
1318 
1320 {
1321  return m_DBs.erase(itr);
1322 }
1323 
1325 {
1326  return m_DBs.empty();
1327 }
1328 
1330 {
1331  return any_of(m_DBs.begin(), m_DBs.end(), FindByPointer(p));
1332 }
1333 
1335 {
1336  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1337 }
1338 
1340 {
1341 }
1342 
1344 {
1345  m_DBs.reserve(r.m_DBs.size());
1346  for (auto const& it : r.m_DBs)
1347  {
1348  m_DBs.push_back(std::make_unique<ScDBData>(*it));
1349  }
1350 }
1351 
1353  rDoc(rDocument), nEntryIndex(1), maNamedDBs(*this, rDocument) {}
1354 
1356  rDoc(r.rDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs, *this), maAnonDBs(r.maAnonDBs) {}
1357 
1358 const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
1359 {
1360  // First, search the global named db ranges.
1361  NamedDBs::DBsType::const_iterator itr = find_if(
1362  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1363  if (itr != maNamedDBs.end())
1364  return itr->get();
1365 
1366  // Check for the sheet-local anonymous db range.
1367  const ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1368  if (pNoNameData)
1369  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1370  return pNoNameData;
1371 
1372  // Check the global anonymous db ranges.
1373  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1374  if (pData)
1375  return pData;
1376 
1377  // Do NOT check for the document global temporary anonymous db range here.
1378 
1379  return nullptr;
1380 }
1381 
1383 {
1384  // First, search the global named db ranges.
1385  NamedDBs::DBsType::iterator itr = find_if(
1386  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1387  if (itr != maNamedDBs.end())
1388  return itr->get();
1389 
1390  // Check for the sheet-local anonymous db range.
1391  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1392  if (pNoNameData)
1393  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1394  return pNoNameData;
1395 
1396  // Check the global anonymous db ranges.
1397  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1398  if (pData)
1399  return const_cast<ScDBData*>(pData);
1400 
1401  // Do NOT check for the document global temporary anonymous db range here.
1402 
1403  return nullptr;
1404 }
1405 
1406 const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
1407 {
1408  // First, search the global named db ranges.
1409  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1410  NamedDBs::DBsType::const_iterator itr = find_if(
1411  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1412  if (itr != maNamedDBs.end())
1413  return itr->get();
1414 
1415  // Check for the sheet-local anonymous db range.
1416  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1417  if (pNoNameData)
1418  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1419  return pNoNameData;
1420 
1421  // Lastly, check the global anonymous db ranges.
1422  const ScDBData* pData = maAnonDBs.findByRange(aRange);
1423  if (pData)
1424  return pData;
1425 
1426  // As a last resort, check for the document global temporary anonymous db range.
1427  pNoNameData = rDoc.GetAnonymousDBData();
1428  if (pNoNameData)
1429  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1430  return pNoNameData;
1431 
1432  return nullptr;
1433 }
1434 
1436 {
1437  // First, search the global named db ranges.
1438  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1439  NamedDBs::DBsType::iterator itr = find_if(
1440  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1441  if (itr != maNamedDBs.end())
1442  return itr->get();
1443 
1444  // Check for the sheet-local anonymous db range.
1445  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1446  if (pNoNameData)
1447  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1448  return pNoNameData;
1449 
1450  // Lastly, check the global anonymous db ranges.
1451  const ScDBData* pData = getAnonDBs().findByRange(aRange);
1452  if (pData)
1453  return const_cast<ScDBData*>(pData);
1454 
1455  // As a last resort, check for the document global temporary anonymous db range.
1456  pNoNameData = rDoc.GetAnonymousDBData();
1457  if (pNoNameData)
1458  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1459  return pNoNameData;
1460 
1461  return nullptr;
1462 }
1463 
1465 {
1466  for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
1467  {
1468  const ScRange & rRange = maNamedDBs.maDirtyTableColumnNames[i];
1469  for (auto const& it : maNamedDBs)
1470  {
1471  if (it->AreTableColumnNamesDirty())
1472  it->RefreshTableColumnNames( &maNamedDBs.mrDoc, rRange);
1473  }
1474  }
1476 }
1477 
1479 {
1480  FindByTable func(nTab);
1481  // First, collect the positions of all items that need to be deleted.
1482  ::std::vector<NamedDBs::DBsType::iterator> v;
1483  {
1484  NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
1485  for (; itr != itrEnd; ++itr)
1486  {
1487  if (func(*itr))
1488  v.push_back(itr);
1489  }
1490  }
1491 
1492  // Delete them all.
1493  for (const auto& rIter : v)
1494  maNamedDBs.erase(rIter);
1495 
1496  maAnonDBs.deleteOnTab(nTab);
1497 }
1498 
1500  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1501  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1502  SCCOL nDx, SCROW nDy, SCTAB nDz )
1503 {
1505  if (pData)
1506  {
1507  if (nTab1 == nTab2 && nDz == 0)
1508  {
1509  // Delete the database range, if some part of the reference became invalid.
1510  if (pData->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1511  nTab2, nDx, nDy, nDz))
1512  rDoc.SetAnonymousDBData(nTab1, nullptr);
1513  }
1514  else
1515  {
1516  //this will perhaps break undo
1517  }
1518  }
1519 
1520  for (auto it = maNamedDBs.begin(); it != maNamedDBs.end(); )
1521  {
1522  // Delete the database range, if some part of the reference became invalid.
1523  if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1524  nTab2, nDx, nDy, nDz))
1525  it = maNamedDBs.erase(it);
1526  else
1527  ++it;
1528  }
1529  for (auto it = maAnonDBs.begin(); it != maAnonDBs.end(); )
1530  {
1531  // Delete the database range, if some part of the reference became invalid.
1532  if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1533  nTab2, nDx, nDy, nDz))
1534  it = maAnonDBs.erase(it);
1535  else
1536  ++it;
1537  }
1538 }
1539 
1541 {
1542  UpdateMoveTabFunc func(nOldPos, nNewPos);
1543  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1544  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1545 }
1546 
1548 {
1549  for (const auto& rxNamedDB : maNamedDBs)
1550  {
1551  if (rxNamedDB->GetTab() != nOldPos)
1552  return;
1553 
1554  OUString newName
1555  = lcl_IncrementNumberInNamedRange(getNamedDBs(), rxNamedDB->GetName());
1556  std::unique_ptr<ScDBData> pDataCopy = std::make_unique<ScDBData>(newName, *rxNamedDB);
1557  pDataCopy->UpdateMoveTab(nOldPos, nNewPos);
1558  pDataCopy->SetIndex(0);
1559  getNamedDBs().insert(std::move(pDataCopy));
1560  }
1561 }
1562 
1564 {
1565  ScDBData* pNearData = nullptr;
1566  for (const auto& rxNamedDB : maNamedDBs)
1567  {
1568  SCTAB nAreaTab;
1569  SCCOL nStartCol, nEndCol;
1570  SCROW nStartRow, nEndRow;
1571  rxNamedDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1572  if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
1573  nRow+1 >= nStartRow && nRow <= nEndRow+1 )
1574  {
1575  if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
1576  {
1577  if (!pNearData)
1578  pNearData = rxNamedDB.get(); // remember first adjacent area
1579  }
1580  else
1581  return rxNamedDB.get(); // not "unbenannt"/"unnamed" and cursor within
1582  }
1583  }
1584  if (pNearData)
1585  return pNearData; // adjacent, if no direct hit
1586  return rDoc.GetAnonymousDBData(nTab); // "unbenannt"/"unnamed" only if nothing else
1587 }
1588 
1589 std::vector<ScDBData*> ScDBCollection::GetAllDBsFromTab(SCTAB nTab)
1590 {
1591  std::vector<ScDBData*> pTabData;
1592  for (const auto& rxNamedDB : maNamedDBs)
1593  {
1594  if (rxNamedDB->GetTab() == nTab)
1595  pTabData.emplace_back(rxNamedDB.get());
1596  }
1597  auto pAnonDBData = rDoc.GetAnonymousDBData(nTab);
1598  if (pAnonDBData)
1599  pTabData.emplace_back(pAnonDBData);
1600  return pTabData;
1601 }
1602 
1604 {
1605  return maNamedDBs.empty() && maAnonDBs.empty();
1606 }
1607 
1609 {
1610  return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
1612 }
1613 
1614 /* 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:1215
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:497
ScDBData * findByIndex(sal_uInt16 nIndex)
Definition: dbdata.cxx:1189
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:1097
void GetFilterSelCount(SCSIZE &nSelected, SCSIZE &nTotal)
Definition: dbdata.cxx:973
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
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:308
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:413
SCROW Row() const
Definition: address.hxx:274
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:660
bool empty() const
Definition: dbdata.cxx:1324
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:320
bool bIsAdvanced
QueryParam.
Definition: dbdata.hxx:86
std::unique_ptr< sal_Int32[]> pData
OUString GetSourceString() const
Definition: dbdata.cxx:258
long Long
const ScDBData * findByRange(const ScRange &rRange) const
Definition: dbdata.cxx:1286
sal_Int64 n
NamedDBs(ScDBCollection &rParent, ScDocument &rDoc)
Definition: dbdata.cxx:1126
sal_Int32 mnCol
aBuf
void InvalidateTableColumnNames(bool bSwapToEmptyNames)
Definition: dbdata.cxx:739
bool IsClipOrUndo() const
Definition: document.hxx:1587
OUString newName(std::u16string_view aNewPrefix, const OUString &aOldPrefix, std::u16string_view old_Name)
SCCOLROW nField
Definition: queryentry.hxx:61
SCROW GetRowCount() const
Definition: brdcst.hxx:32
ScAddress aEnd
Definition: address.hxx:498
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:442
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:1329
SfxHintId GetId() const
void ExtendDataArea(const ScDocument &rDoc)
Definition: dbdata.cxx:649
ScDBData * GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dbdata.cxx:1563
std::unique_ptr< ScSortParam > mpSortParam
Definition: dbdata.hxx:63
sal_uInt16 nEntryIndex
counter for unique indices
Definition: dbdata.hxx:308
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:1299
void SetModified(bool bMod)
Definition: dbdata.hxx:208
ScDocument & rDoc
Definition: dbdata.hxx:307
void SetImportParam(const ScImportParam &rImportParam)
Definition: dbdata.cxx:490
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:891
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:319
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:668
iterator erase(const iterator &itr)
Definition: dbdata.cxx:1238
SCCOL nCol2
Definition: global.hxx:441
SCTAB Tab() const
Definition: address.hxx:283
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:437
::std::vector< OUString > maTableColumnNames
names of table columns
Definition: dbdata.hxx:95
std::vector< ScDBData * > GetAllDBsFromTab(SCTAB nTab)
Definition: dbdata.cxx:1589
SCROW nRow1
Definition: global.hxx:440
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:1406
Stores global anonymous database ranges.
Definition: dbdata.hxx:276
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:1091
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:965
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:1278
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:1499
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:1603
bool operator==(const ScDBCollection &r) const
Definition: dbdata.cxx:1608
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:403
void insert(ScDBData *p)
Definition: dbdata.cxx:1314
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:1024
bool operator==(const AnonDBs &r) const
Definition: dbdata.cxx:1334
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
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:917
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
iterator erase(const iterator &itr)
Definition: dbdata.cxx:1319
constexpr OUStringLiteral STR_DB_GLOBAL_NONAME
Definition: globalnames.hxx:15
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:1478
SCTAB nTable
Definition: dbdata.hxx:73
void deleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1293
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
void initInserted(ScDBData *p)
Definition: dbdata.cxx:1146
bool bByRow
Definition: dbdata.hxx:78
OUString GetOperations() const
Definition: dbdata.cxx:270
void CopyToTable(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:1547
bool IsValid() const
Definition: address.hxx:544
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:1248
void StopRefreshTimer()
Reference not affected, no change at all.
Definition: refupdat.hxx:31
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:905
SCCOL Col() const
Definition: address.hxx:279
sal_Int32 GetColumnNameOffset(const OUString &rName) const
Finds the column named rName and returns the corresponding offset within the table.
Definition: dbdata.cxx:892
void GetSubTotalParam(ScSubTotalParam &rSubTotalParam) const
Definition: dbdata.cxx:463
ScDBData * findByUpperName(const OUString &rName)
Definition: dbdata.cxx:1196
top left cell of area
DBsType::iterator iterator
Definition: dbdata.hxx:287
float v
Stores global named database ranges.
Definition: dbdata.hxx:234
UpdateRefMode
Definition: global.hxx:298
sal_Int32 SCROW
Definition: types.hxx:17
void RefreshDirtyTableColumnNames()
Definition: dbdata.cxx:1464
bool bHasHeader
Definition: sortparam.hxx:111
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:68
#define SAL_WARN_IF(condition, area, stream)
ScRangeList & GetDirtyTableColumnNames()
Definition: dbdata.cxx:1121
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:288
ScDBData * findByName(const OUString &rName)
Definition: dbdata.cxx:1209
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:588
virtual ~NamedDBs() override
Definition: dbdata.cxx:1142
void AdjustTableColumnNames(UpdateRefMode eUpdateRefMode, SCCOL nDx, SCCOL nCol1, SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2)
Definition: dbdata.cxx:689
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:250
AnonDBs maAnonDBs
Definition: dbdata.hxx:310
bool empty() const
Definition: dbdata.cxx:1243
bool Contains(const ScAddress &) const
is Address& fully in Range?
Definition: address.hxx:718
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:1358
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:678
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
NamedDBs & getNamedDBs()
Definition: dbdata.hxx:316
ScDocument & GetDocument() const
Definition: dbdata.cxx:1116
iterator findByUpperName2(const OUString &rName)
Definition: dbdata.cxx:1203
SCCOL nCol1
Definition: global.hxx:439
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:1540
ScDBCollection(ScDocument &rDocument)
Definition: dbdata.cxx:1352
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:803
std::unique_ptr< ScSubTotalParam > mpSubTotal
Definition: dbdata.hxx:65
sal_Int32 mnRow
static SC_DLLPUBLIC::utl::TransliterationWrapper & GetTransliteration()
Definition: global.cxx:986
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
void RemoveAll()
Definition: rangelst.cxx:1101
bool HasImportParam() const
Definition: dbdata.cxx:519
sal_Int16 SCTAB
Definition: types.hxx:22
Link< Timer *, void > aRefreshHandler
Definition: dbdata.hxx:306
SC_DLLPUBLIC void SetTableColumnNames(::std::vector< OUString > &&rNames)
Definition: dbdata.cxx:683
const ScAddress & GetStartAddress() const
Definition: brdcst.hxx:31
NamedDBs maNamedDBs
Definition: dbdata.hxx:309
sal_uInt16 nIndex
unique index formulas
Definition: dbdata.hxx:91
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:81
bool m_bDetectedRangeSegmentation false
bool operator==(const NamedDBs &r) const
Definition: dbdata.cxx:1253