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::GetpTransliteration()->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 {
346  tools::Long nDifX = static_cast<tools::Long>(nCol1) - static_cast<tools::Long>(nStartCol);
347  tools::Long nDifY = static_cast<tools::Long>(nRow1) - static_cast<tools::Long>(nStartRow);
348 
349  tools::Long nSortDif = bByRow ? nDifX : nDifY;
350  tools::Long nSortEnd = bByRow ? static_cast<tools::Long>(nCol2) : static_cast<tools::Long>(nRow2);
351 
352  for (sal_uInt16 i=0; i<mpSortParam->GetSortKeyCount(); i++)
353  {
354  mpSortParam->maKeyState[i].nField += nSortDif;
355  if (mpSortParam->maKeyState[i].nField > nSortEnd)
356  {
357  mpSortParam->maKeyState[i].nField = 0;
358  mpSortParam->maKeyState[i].bDoSort = false;
359  }
360  }
361 
362  SCSIZE nCount = mpQueryParam->GetEntryCount();
363  for (SCSIZE i = 0; i < nCount; ++i)
364  {
365  ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
366  rEntry.nField += nDifX;
367  if (rEntry.nField > nCol2)
368  {
369  rEntry.nField = 0;
370  rEntry.bDoQuery = false;
371  }
372  }
373  for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
374  {
375  mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
376  if (mpSubTotal->nField[i] > nCol2)
377  {
378  mpSubTotal->nField[i] = 0;
379  mpSubTotal->bGroupActive[i] = false;
380  }
381  }
382 
383  SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
384 }
385 
386 void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
387 {
388  rSortParam = *mpSortParam;
389  rSortParam.nCol1 = nStartCol;
390  rSortParam.nRow1 = nStartRow;
391  rSortParam.nCol2 = nEndCol;
392  rSortParam.nRow2 = nEndRow;
393  rSortParam.bByRow = bByRow;
394  rSortParam.bHasHeader = bHasHeader;
395  /* TODO: add Totals to ScSortParam? */
396 }
397 
398 void ScDBData::SetSortParam( const ScSortParam& rSortParam )
399 {
400  mpSortParam.reset(new ScSortParam(rSortParam));
401  bByRow = rSortParam.bByRow;
402 }
403 
405 {
406  bHasHeader = rSortParam.bHasHeader;
407 }
408 
409 void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
410 {
411  rQueryParam = *mpQueryParam;
412  rQueryParam.nCol1 = nStartCol;
413  rQueryParam.nRow1 = nStartRow;
414  rQueryParam.nCol2 = nEndCol;
415  rQueryParam.nRow2 = nEndRow;
416  rQueryParam.nTab = nTable;
417  rQueryParam.bByRow = bByRow;
418  rQueryParam.bHasHeader = bHasHeader;
419  /* TODO: add Totals to ScQueryParam? */
420 }
421 
422 void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
423 {
424  mpQueryParam.reset(new ScQueryParam(rQueryParam));
425 
426  // set bIsAdvanced to false for everything that is not from the
427  // advanced filter dialog
428  bIsAdvanced = false;
429 }
430 
432 {
433  if (pSource)
434  {
435  aAdvSource = *pSource;
436  bIsAdvanced = true;
437  }
438  else
439  bIsAdvanced = false;
440 }
441 
443 {
444  rSource = aAdvSource;
445  return bIsAdvanced;
446 }
447 
448 void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
449 {
450  rSubTotalParam = *mpSubTotal;
451 
452  // Share the data range with the parent db data. The range in the subtotal
453  // param struct is not used.
454  rSubTotalParam.nCol1 = nStartCol;
455  rSubTotalParam.nRow1 = nStartRow;
456  rSubTotalParam.nCol2 = nEndCol;
457  rSubTotalParam.nRow2 = nEndRow;
458 }
459 
460 void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
461 {
462  mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
463 }
464 
465 void ScDBData::GetImportParam(ScImportParam& rImportParam) const
466 {
467  rImportParam = *mpImportParam;
468  // set the range.
469  rImportParam.nCol1 = nStartCol;
470  rImportParam.nRow1 = nStartRow;
471  rImportParam.nCol2 = nEndCol;
472  rImportParam.nRow2 = nEndRow;
473 }
474 
475 void ScDBData::SetImportParam(const ScImportParam& rImportParam)
476 {
477  // the range is ignored.
478  mpImportParam.reset(new ScImportParam(rImportParam));
479 }
480 
481 bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
482 {
483  if (nTab == nTable)
484  {
485  switch (ePortion)
486  {
488  return nCol == nStartCol && nRow == nStartRow;
490  return nCol >= nStartCol && nCol <= nEndCol && nRow >= nStartRow && nRow <= nEndRow;
491  }
492  }
493 
494  return false;
495 }
496 
497 bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
498 {
499  return (nTab == nTable)
500  && (nCol1 == nStartCol) && (nRow1 == nStartRow)
501  && (nCol2 == nEndCol) && (nRow2 == nEndRow);
502 }
503 
505 {
506  return mpImportParam && mpImportParam->bImport;
507 }
508 
510 {
511  if (!mpQueryParam)
512  return false;
513 
514  if (!mpQueryParam->GetEntryCount())
515  return false;
516 
517  return mpQueryParam->GetEntry(0).bDoQuery;
518 }
519 
521 {
522  return mpSortParam &&
523  !mpSortParam->maKeyState.empty() &&
524  mpSortParam->maKeyState[0].bDoSort;
525 }
526 
528 {
529  return mpSubTotal && mpSubTotal->bGroupActive[0];
530 }
531 
532 void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
533 {
534  ScRange aRange;
535  GetArea( aRange );
536  SCTAB nTab = aRange.aStart.Tab(); // a database range is only on one sheet
537 
538  // customize as the current table as ScTablesHint (tabvwsh5.cxx)
539 
540  if ( nTab == nOldPos ) // moved sheet
541  nTab = nNewPos;
542  else if ( nOldPos < nNewPos ) // moved to the back
543  {
544  if ( nTab > nOldPos && nTab <= nNewPos ) // move this sheet
545  --nTab;
546  }
547  else // moved to the front
548  {
549  if ( nTab >= nNewPos && nTab < nOldPos ) // move this sheet
550  ++nTab;
551  }
552 
553  bool bChanged = ( nTab != aRange.aStart.Tab() );
554  if (bChanged)
555  {
556  // SetArea() invalidates column names, but it is the same column range
557  // just on a different sheet; remember and set new.
558  ::std::vector<OUString> aNames( maTableColumnNames);
559  bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
560  // Same column range.
561  SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
562  aRange.aEnd.Col(),aRange.aEnd.Row() );
563  // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
564  maTableColumnNames = aNames;
565  mbTableColumnNamesDirty = bTableColumnNamesDirty;
566  }
567 
568  // MoveTo() is not necessary if only the sheet changed.
569 
570  SetModified(bChanged);
571 
572 }
573 
574 void ScDBData::UpdateReference(const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
575  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
576  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
577  SCCOL nDx, SCROW nDy, SCTAB nDz)
578 {
579  SCCOL theCol1;
580  SCROW theRow1;
581  SCTAB theTab1;
582  SCCOL theCol2;
583  SCROW theRow2;
584  SCTAB theTab2;
585  GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
586  theTab2 = theTab1;
587  SCCOL nOldCol1 = theCol1, nOldCol2 = theCol2;
588 
589  bool bDoUpdate = ScRefUpdate::Update( pDoc, eUpdateRefMode,
590  nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
591  theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
592  if (bDoUpdate)
593  {
594  // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
595  AdjustTableColumnNames( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
596  ::std::vector<OUString> aNames( maTableColumnNames);
597  bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
598  MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
599  // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
600  maTableColumnNames = aNames;
601  mbTableColumnNamesDirty = bTableColumnNamesDirty;
602  }
603 
604  ScRange aRangeAdvSource;
605  if ( GetAdvancedQuerySource(aRangeAdvSource) )
606  {
607  aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
608  if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
609  nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
610  theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
611  {
612  aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
613  aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
614  SetAdvancedQuerySource( &aRangeAdvSource );
615 
616  bDoUpdate = true; // DBData is modified
617  }
618  }
619 
620  SetModified(bDoUpdate);
621 
622  //TODO: check if something was deleted/inserted with-in the range !!!
623 }
624 
626 {
627  // Extend the DB area to include data rows immediately below.
628  SCCOL nOldCol1 = nStartCol, nOldCol2 = nEndCol;
629  SCROW nOldEndRow = nEndRow;
630  rDoc.GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
631  // nOldEndRow==rDoc.MaxRow() may easily happen when selecting whole columns and
632  // setting an AutoFilter (i.e. creating an anonymous database-range). We
633  // certainly don't want to iterate over nearly a million empty cells, but
634  // keep only an intentionally user selected range.
635  if (nOldEndRow < rDoc.MaxRow() && nEndRow < nOldEndRow)
636  nEndRow = nOldEndRow;
637  if (nStartCol != nOldCol1 || nEndCol != nOldCol2)
638  {
639  SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
641  }
642 }
643 
645 {
646  if (mpContainer && bHasHeader)
647  {
649  if (!rDoc.IsClipOrUndo())
650  rDoc.StartListeningArea( GetHeaderArea(), false, this);
651  }
652 }
653 
655 {
656  EndListeningAll();
657 }
658 
659 void ScDBData::SetTableColumnNames( const ::std::vector< OUString >& rNames )
660 {
661  maTableColumnNames = rNames;
662  mbTableColumnNamesDirty = false;
663 }
664 
666  SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2 )
667 {
668  if (maTableColumnNames.empty())
669  return;
670 
671  SCCOL nDiff1 = nNewCol1 - nOldCol1;
672  SCCOL nDiff2 = nNewCol2 - nOldCol2;
673  if (nDiff1 == nDiff2)
674  return; // not moved or entirely moved, nothing to do
675 
676  ::std::vector<OUString> aNewNames;
677  if (eUpdateRefMode == URM_INSDEL)
678  {
679  if (nDx > 0)
680  mbTableColumnNamesDirty = true; // inserted columns will have empty names
681 
682  // nCol1 is the first column of the block that gets shifted, determine
683  // the head and tail elements that are to be copied for deletion or
684  // insertion.
685  size_t nHead = static_cast<size_t>(::std::max( nCol1 + std::min<SCCOL>(nDx, 0) - nOldCol1, 0));
686  size_t nTail = static_cast<size_t>(::std::max( nOldCol2 - nCol1 + 1, 0));
687  size_t n = nHead + nTail;
688  if (0 < n && n <= maTableColumnNames.size())
689  {
690  if (nDx > 0)
691  n += nDx;
692  aNewNames.resize(n);
693  // Copy head.
694  for (size_t i = 0; i < nHead; ++i)
695  {
696  aNewNames[i] = maTableColumnNames[i];
697  }
698  // Copy tail, inserted middle range, if any, stays empty.
699  for (size_t i = n - nTail, j = maTableColumnNames.size() - nTail; i < n; ++i, ++j)
700  {
701  aNewNames[i] = maTableColumnNames[j];
702  }
703  }
704  } // else empty aNewNames invalidates names/offsets
705 
706  SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
707  "sc.core", "ScDBData::AdjustTableColumnNames - invalidating column names/offsets");
708  aNewNames.swap( maTableColumnNames);
709  if (maTableColumnNames.empty())
712  InvalidateTableColumnNames( false); // preserve new column names array
713 }
714 
715 void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames )
716 {
718  if (bSwapToEmptyNames && !maTableColumnNames.empty())
719  ::std::vector<OUString>().swap( maTableColumnNames);
720  if (mpContainer)
721  {
722  // Add header range to dirty list.
723  if (HasHeader())
725  else
726  {
727  // We need *some* range in the dirty list even without header area,
728  // otherwise the container would not attempt to call a refresh.
730  }
731  }
732 }
733 
734 namespace {
735 class TableColumnNameSearch
736 {
737 public:
738  explicit TableColumnNameSearch( const OUString& rSearchName ) :
739  maSearchName( rSearchName )
740  {
741  }
742 
743  bool operator()( const OUString& rName ) const
744  {
745  return ScGlobal::GetpTransliteration()->isEqual( maSearchName, rName);
746  }
747 
748 private:
749  OUString maSearchName;
750 };
751 
756 void SetTableColumnName( ::std::vector<OUString>& rVec, size_t nIndex, const OUString& rName, size_t nCount )
757 {
758  OUString aStr;
759  do
760  {
761  if (nCount)
762  aStr = rName + OUString::number( nCount);
763  else
764  {
765  aStr = rName;
766  ++nCount;
767  }
768 
769  if (std::none_of( rVec.begin(), rVec.end(), TableColumnNameSearch( aStr)))
770  {
771  rVec[nIndex] = aStr;
772  break; // do while
773  }
774  ++nCount;
775  } while(true);
776 }
777 }
778 
780 {
781  ::std::vector<OUString> aNewNames;
782  aNewNames.resize( nEndCol - nStartCol + 1);
783  bool bHaveEmpty = false;
784  if (!HasHeader() || !pDoc)
785  bHaveEmpty = true; // Assume we have empty ones and fill below.
786  else
787  {
788  ScHorizontalCellIterator aIter(*pDoc, nTable, nStartCol, nStartRow, nEndCol, nStartRow); // header row only
789  ScRefCellValue* pCell;
790  SCCOL nCol, nLastColFilled = nStartCol - 1;
791  SCROW nRow;
792  for (size_t i=0; (pCell = aIter.GetNext( nCol, nRow)) != nullptr; ++i)
793  {
794  if (pCell->hasString())
795  {
796  const OUString& rStr = pCell->getString( pDoc);
797  if (rStr.isEmpty())
798  bHaveEmpty = true;
799  else
800  {
801  SetTableColumnName( aNewNames, nCol-nStartCol, rStr, 0);
802  if (nLastColFilled < nCol-1)
803  bHaveEmpty = true;
804  }
805  nLastColFilled = nCol;
806  }
807  else
808  bHaveEmpty = true;
809  }
810  }
811 
812  // Never leave us with empty names, try to remember previous name that
813  // might had been used to compile formulas, but only if same number of
814  // columns and no duplicates.
815  if (bHaveEmpty && aNewNames.size() == maTableColumnNames.size())
816  {
817  bHaveEmpty = false;
818  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
819  {
820  if (aNewNames[i].isEmpty())
821  {
822  const OUString& rStr = maTableColumnNames[i];
823  if (rStr.isEmpty())
824  bHaveEmpty = true;
825  else
826  SetTableColumnName( aNewNames, i, rStr, 0);
827  }
828  }
829  }
830 
831  // If we still have empty ones then fill those with "Column#" with #
832  // starting at the column offset number. Still no duplicates of course.
833  if (bHaveEmpty)
834  {
835  OUString aColumn( ScResId(STR_COLUMN));
836  for (size_t i=0, n=aNewNames.size(); i < n; ++i)
837  {
838  if (aNewNames[i].isEmpty())
839  SetTableColumnName( aNewNames, i, aColumn, i+1);
840  }
841  }
842 
843  aNewNames.swap( maTableColumnNames);
844  mbTableColumnNamesDirty = false;
845 }
846 
848 {
849  // Header-less tables get names generated, completely empty a full refresh.
851  {
853  return;
854  }
855 
856  // Check if this is affected for the range requested.
857  ScRange aIntersection( GetHeaderArea().Intersection( rRange));
858  if (!aIntersection.IsValid())
859  return;
860 
861  // Always fully refresh, only one cell of a range was broadcasted per area
862  // listener if multiple cells were affected. We don't know if there were
863  // more. Also, we need the full check anyway in case a duplicated name was
864  // entered.
866 }
867 
868 sal_Int32 ScDBData::GetColumnNameOffset( const OUString& rName ) const
869 {
870  if (maTableColumnNames.empty())
871  return -1;
872 
873  ::std::vector<OUString>::const_iterator it(
874  ::std::find_if( maTableColumnNames.begin(), maTableColumnNames.end(), TableColumnNameSearch( rName)));
875  if (it != maTableColumnNames.end())
876  return it - maTableColumnNames.begin();
877 
878  return -1;
879 }
880 
881 const OUString& ScDBData::GetTableColumnName( SCCOL nCol ) const
882 {
883  if (maTableColumnNames.empty())
884  return EMPTY_OUSTRING;
885 
886  SCCOL nOffset = nCol - nStartCol;
887  if (nOffset < 0 || maTableColumnNames.size() <= o3tl::make_unsigned(nOffset))
888  return EMPTY_OUSTRING;
889 
890  return maTableColumnNames[nOffset];
891 }
892 
893 void ScDBData::Notify( const SfxHint& rHint )
894 {
895  const ScHint* pScHint = dynamic_cast<const ScHint*>(&rHint);
896  if (!pScHint)
897  return;
898 
899  if (pScHint->GetId() != SfxHintId::ScDataChanged)
900  return;
901 
903  if (!mpContainer)
904  assert(!"ScDBData::Notify - how did we end up here without container?");
905  else
906  {
907  // Only one cell of a range is broadcasted per area listener if
908  // multiple cells are affected. Expand the range to what this is
909  // listening to. Broadcasted address outside should not happen,
910  // but... let it trigger a refresh if.
911  ScRange aHeaderRange( GetHeaderArea());
912  if (aHeaderRange.IsValid())
913  {
914  mpContainer->GetDirtyTableColumnNames().Join( aHeaderRange);
915  if (!aHeaderRange.In( pScHint->GetAddress()))
917  }
918  else
920  }
921 
922  // Do not refresh column names here, which might trigger unwanted
923  // recalculation.
924 }
925 
926 void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount )
927 {
928  SCSIZE nTotal = nEndRow - nStartRow + 1;
929  if ( bHasHeader )
930  nTotal -= 1;
931  nFilteredRowCount = nTotal - nNonFilteredRowCount;
932 }
933 
934 void ScDBData::GetFilterSelCount( SCSIZE& nSelected, SCSIZE& nTotal )
935 {
936  nTotal = nEndRow - nStartRow + 1;
937  if ( bHasHeader )
938  nTotal -= 1;
940  nSelected = nTotal - nFilteredRowCount;
941  else
942  nSelected = nFilteredRowCount;
943 }
944 
945 namespace {
946 
947 class FindByTable
948 {
949  SCTAB mnTab;
950 public:
951  explicit FindByTable(SCTAB nTab) : mnTab(nTab) {}
952 
953  bool operator() (std::unique_ptr<ScDBData> const& p) const
954  {
955  ScRange aRange;
956  p->GetArea(aRange);
957  return aRange.aStart.Tab() == mnTab;
958  }
959 };
960 
961 class UpdateRefFunc
962 {
963  ScDocument* mpDoc;
965  SCCOL mnCol1;
966  SCROW mnRow1;
967  SCTAB mnTab1;
968  SCCOL mnCol2;
969  SCROW mnRow2;
970  SCTAB mnTab2;
971  SCCOL mnDx;
972  SCROW mnDy;
973  SCTAB mnDz;
974 
975 public:
976  UpdateRefFunc(ScDocument* pDoc, UpdateRefMode eMode,
977  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
978  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
979  SCCOL nDx, SCROW nDy, SCTAB nDz) :
980  mpDoc(pDoc), meMode(eMode),
981  mnCol1(nCol1), mnRow1(nRow1), mnTab1(nTab1),
982  mnCol2(nCol2), mnRow2(nRow2), mnTab2(nTab2),
983  mnDx(nDx), mnDy(nDy), mnDz(nDz) {}
984 
985  void operator() (std::unique_ptr<ScDBData> const& p)
986  {
987  p->UpdateReference(mpDoc, meMode, mnCol1, mnRow1, mnTab1, mnCol2, mnRow2, mnTab2, mnDx, mnDy, mnDz);
988  }
989 };
990 
991 class UpdateMoveTabFunc
992 {
993  SCTAB mnOldTab;
994  SCTAB mnNewTab;
995 public:
996  UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
997  void operator() (std::unique_ptr<ScDBData> const& p)
998  {
999  p->UpdateMoveTab(mnOldTab, mnNewTab);
1000  }
1001 };
1002 
1003 class FindByCursor
1004 {
1005  SCCOL mnCol;
1006  SCROW mnRow;
1007  SCTAB mnTab;
1008  ScDBDataPortion mePortion;
1009 public:
1010  FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) :
1011  mnCol(nCol), mnRow(nRow), mnTab(nTab), mePortion(ePortion) {}
1012 
1013  bool operator() (std::unique_ptr<ScDBData> const& p)
1014  {
1015  return p->IsDBAtCursor(mnCol, mnRow, mnTab, mePortion);
1016  }
1017 };
1018 
1019 class FindByRange
1020 {
1021  const ScRange& mrRange;
1022 public:
1023  explicit FindByRange(const ScRange& rRange) : mrRange(rRange) {}
1024 
1025  bool operator() (std::unique_ptr<ScDBData> const& p)
1026  {
1027  return p->IsDBAtArea(
1028  mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
1029  }
1030 };
1031 
1032 class FindByIndex
1033 {
1034  sal_uInt16 mnIndex;
1035 public:
1036  explicit FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
1037  bool operator() (std::unique_ptr<ScDBData> const& p) const
1038  {
1039  return p->GetIndex() == mnIndex;
1040  }
1041 };
1042 
1043 class FindByUpperName
1044 {
1045  const OUString& mrName;
1046 public:
1047  explicit FindByUpperName(const OUString& rName) : mrName(rName) {}
1048  bool operator() (std::unique_ptr<ScDBData> const& p) const
1049  {
1050  return p->GetUpperName() == mrName;
1051  }
1052 };
1053 
1054 class FindByPointer
1055 {
1056  const ScDBData* mpDBData;
1057 public:
1058  explicit FindByPointer(const ScDBData* pDBData) : mpDBData(pDBData) {}
1059  bool operator() (std::unique_ptr<ScDBData> const& p) const
1060  {
1061  return p.get() == mpDBData;
1062  }
1063 };
1064 
1065 }
1066 
1068 {
1069  return mrDoc;
1070 }
1071 
1073 {
1074  return maDirtyTableColumnNames;
1075 }
1076 
1078  ScDBDataContainerBase(rDoc), mrParent(rParent) {}
1079 
1081  : ScDBDataContainerBase(r.mrDoc)
1082  , mrParent(rParent)
1083 {
1084  for (auto const& it : r.m_DBs)
1085  {
1086  ScDBData* p = new ScDBData(*it);
1087  std::unique_ptr<ScDBData> pData(p);
1088  if (m_DBs.insert( std::move(pData)).second)
1089  initInserted(p);
1090  }
1091 }
1092 
1094 {
1095 }
1096 
1098 {
1099  p->SetContainer( this);
1100  if (mrDoc.IsClipOrUndo())
1101  return;
1102 
1103  p->StartTableColumnNamesListener(); // needs the container be set already
1104  if (!p->AreTableColumnNamesDirty())
1105  return;
1106 
1107  if (p->HasHeader())
1108  {
1109  // Refresh table column names in next round.
1110  maDirtyTableColumnNames.Join( p->GetHeaderArea());
1111  }
1112  else
1113  {
1114  // Header-less table can generate its column names
1115  // already without accessing the document.
1116  p->RefreshTableColumnNames( nullptr);
1117  }
1118 }
1119 
1121 {
1122  return m_DBs.begin();
1123 }
1124 
1126 {
1127  return m_DBs.end();
1128 }
1129 
1131 {
1132  return m_DBs.begin();
1133 }
1134 
1136 {
1137  return m_DBs.end();
1138 }
1139 
1141 {
1142  DBsType::iterator itr = find_if(
1143  m_DBs.begin(), m_DBs.end(), FindByIndex(nIndex));
1144  return itr == m_DBs.end() ? nullptr : itr->get();
1145 }
1146 
1148 {
1149  DBsType::iterator itr = find_if(
1150  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1151  return itr == m_DBs.end() ? nullptr : itr->get();
1152 }
1153 
1155 {
1156  return find_if(
1157  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1158 }
1159 
1160 bool ScDBCollection::NamedDBs::insert(std::unique_ptr<ScDBData> pData)
1161 {
1162  auto p = pData.get();
1163  if (!pData->GetIndex())
1164  pData->SetIndex(mrParent.nEntryIndex++);
1165 
1166  pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
1167 
1168  if (r.second)
1169  {
1170  initInserted(p);
1171 
1172  /* TODO: shouldn't the import refresh not be setup for
1173  * clipboard/undo documents? It was already like this before... */
1174  if (p->HasImportParam() && !p->HasImportSelection())
1175  {
1176  p->SetRefreshHandler(mrParent.GetRefreshHandler());
1177  p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
1178  }
1179  }
1180  return r.second;
1181 }
1182 
1184 {
1185  m_DBs.erase(itr);
1186 }
1187 
1189 {
1190  return m_DBs.empty();
1191 }
1192 
1194 {
1195  return m_DBs.size();
1196 }
1197 
1199 {
1200  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1201 }
1202 
1204 {
1205  return m_DBs.begin();
1206 }
1207 
1209 {
1210  return m_DBs.end();
1211 }
1212 
1214 {
1215  return m_DBs.begin();
1216 }
1217 
1219 {
1220  return m_DBs.end();
1221 }
1222 
1224  ScDBDataPortion ePortion) const
1225 {
1226  DBsType::const_iterator itr = find_if(
1227  m_DBs.begin(), m_DBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1228  return itr == m_DBs.end() ? nullptr : itr->get();
1229 }
1230 
1232 {
1233  DBsType::const_iterator itr = find_if(
1234  m_DBs.begin(), m_DBs.end(), FindByRange(rRange));
1235  return itr == m_DBs.end() ? nullptr : itr->get();
1236 }
1237 
1239 {
1240  FindByTable func(nTab);
1241  m_DBs.erase(std::remove_if(m_DBs.begin(), m_DBs.end(), func), m_DBs.end());
1242 }
1243 
1245 {
1246  const ScDBData* pData = findByRange(rRange);
1247  if (!pData)
1248  {
1249  // Insert a new db data. They all have identical names.
1250  ::std::unique_ptr<ScDBData> pNew(new ScDBData(
1251  STR_DB_GLOBAL_NONAME, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
1252  rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
1253  pData = pNew.get();
1254  m_DBs.push_back(std::move(pNew));
1255  }
1256  return const_cast<ScDBData*>(pData);
1257 }
1258 
1260 {
1261  m_DBs.push_back(std::unique_ptr<ScDBData>(p));
1262 }
1263 
1265 {
1266  return m_DBs.empty();
1267 }
1268 
1270 {
1271  return any_of(m_DBs.begin(), m_DBs.end(), FindByPointer(p));
1272 }
1273 
1275 {
1276  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1277 }
1278 
1280 {
1281 }
1282 
1284 {
1285  m_DBs.reserve(r.m_DBs.size());
1286  for (auto const& it : r.m_DBs)
1287  {
1288  m_DBs.push_back(std::make_unique<ScDBData>(*it));
1289  }
1290 }
1291 
1293  rDoc(rDocument), nEntryIndex(1), maNamedDBs(*this, rDocument) {}
1294 
1296  rDoc(r.rDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs, *this), maAnonDBs(r.maAnonDBs) {}
1297 
1298 const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
1299 {
1300  // First, search the global named db ranges.
1301  NamedDBs::DBsType::const_iterator itr = find_if(
1302  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1303  if (itr != maNamedDBs.end())
1304  return itr->get();
1305 
1306  // Check for the sheet-local anonymous db range.
1307  const ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1308  if (pNoNameData)
1309  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1310  return pNoNameData;
1311 
1312  // Check the global anonymous db ranges.
1313  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1314  if (pData)
1315  return pData;
1316 
1317  // Do NOT check for the document global temporary anonymous db range here.
1318 
1319  return nullptr;
1320 }
1321 
1323 {
1324  // First, search the global named db ranges.
1325  NamedDBs::DBsType::iterator itr = find_if(
1326  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1327  if (itr != maNamedDBs.end())
1328  return itr->get();
1329 
1330  // Check for the sheet-local anonymous db range.
1331  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1332  if (pNoNameData)
1333  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1334  return pNoNameData;
1335 
1336  // Check the global anonymous db ranges.
1337  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1338  if (pData)
1339  return const_cast<ScDBData*>(pData);
1340 
1341  // Do NOT check for the document global temporary anonymous db range here.
1342 
1343  return nullptr;
1344 }
1345 
1346 const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
1347 {
1348  // First, search the global named db ranges.
1349  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1350  NamedDBs::DBsType::const_iterator itr = find_if(
1351  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1352  if (itr != maNamedDBs.end())
1353  return itr->get();
1354 
1355  // Check for the sheet-local anonymous db range.
1356  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1357  if (pNoNameData)
1358  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1359  return pNoNameData;
1360 
1361  // Lastly, check the global anonymous db ranges.
1362  const ScDBData* pData = maAnonDBs.findByRange(aRange);
1363  if (pData)
1364  return pData;
1365 
1366  // As a last resort, check for the document global temporary anonymous db range.
1367  pNoNameData = rDoc.GetAnonymousDBData();
1368  if (pNoNameData)
1369  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1370  return pNoNameData;
1371 
1372  return nullptr;
1373 }
1374 
1376 {
1377  // First, search the global named db ranges.
1378  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1379  NamedDBs::DBsType::iterator itr = find_if(
1380  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1381  if (itr != maNamedDBs.end())
1382  return itr->get();
1383 
1384  // Check for the sheet-local anonymous db range.
1385  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1386  if (pNoNameData)
1387  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1388  return pNoNameData;
1389 
1390  // Lastly, check the global anonymous db ranges.
1391  const ScDBData* pData = getAnonDBs().findByRange(aRange);
1392  if (pData)
1393  return const_cast<ScDBData*>(pData);
1394 
1395  // As a last resort, check for the document global temporary anonymous db range.
1396  pNoNameData = rDoc.GetAnonymousDBData();
1397  if (pNoNameData)
1398  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1399  return pNoNameData;
1400 
1401  return nullptr;
1402 }
1403 
1405 {
1406  for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
1407  {
1408  const ScRange & rRange = maNamedDBs.maDirtyTableColumnNames[i];
1409  for (auto const& it : maNamedDBs)
1410  {
1411  if (it->AreTableColumnNamesDirty())
1412  it->RefreshTableColumnNames( &maNamedDBs.mrDoc, rRange);
1413  }
1414  }
1416 }
1417 
1419 {
1420  FindByTable func(nTab);
1421  // First, collect the positions of all items that need to be deleted.
1422  ::std::vector<NamedDBs::DBsType::iterator> v;
1423  {
1424  NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
1425  for (; itr != itrEnd; ++itr)
1426  {
1427  if (func(*itr))
1428  v.push_back(itr);
1429  }
1430  }
1431 
1432  // Delete them all.
1433  for (const auto& rIter : v)
1434  maNamedDBs.erase(rIter);
1435 
1436  maAnonDBs.deleteOnTab(nTab);
1437 }
1438 
1440  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1441  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1442  SCCOL nDx, SCROW nDy, SCTAB nDz )
1443 {
1445  if (pData)
1446  {
1447  if (nTab1 == nTab2 && nDz == 0)
1448  {
1449  pData->UpdateReference(
1450  &rDoc, eUpdateRefMode,
1451  nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
1452  }
1453  else
1454  {
1455  //this will perhaps break undo
1456  }
1457  }
1458 
1459  UpdateRefFunc func(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
1460  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1461  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1462 }
1463 
1465 {
1466  UpdateMoveTabFunc func(nOldPos, nNewPos);
1467  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1468  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1469 }
1470 
1472 {
1473  ScDBData* pNearData = nullptr;
1474  for (const auto& rxNamedDB : maNamedDBs)
1475  {
1476  SCTAB nAreaTab;
1477  SCCOL nStartCol, nEndCol;
1478  SCROW nStartRow, nEndRow;
1479  rxNamedDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1480  if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
1481  nRow+1 >= nStartRow && nRow <= nEndRow+1 )
1482  {
1483  if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
1484  {
1485  if (!pNearData)
1486  pNearData = rxNamedDB.get(); // remember first adjacent area
1487  }
1488  else
1489  return rxNamedDB.get(); // not "unbenannt"/"unnamed" and cursor within
1490  }
1491  }
1492  if (pNearData)
1493  return pNearData; // adjacent, if no direct hit
1494  return rDoc.GetAnonymousDBData(nTab); // "unbenannt"/"unnamed" only if nothing else
1495 }
1496 
1498 {
1499  return maNamedDBs.empty() && maAnonDBs.empty();
1500 }
1501 
1503 {
1504  return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
1506 }
1507 
1508 /* 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)
SCROW nRow1
Definition: sortparam.hxx:43
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:1160
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:509
ScAddress aStart
Definition: address.hxx:499
ScDBData * findByIndex(sal_uInt16 nIndex)
Definition: dbdata.cxx:1140
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:2134
void GetFilterSelCount(SCSIZE &nSelected, SCSIZE &nTotal)
Definition: dbdata.cxx:934
#define EMPTY_OUSTRING
Definition: global.hxx:213
SCCOL nCol2
Definition: sortparam.hxx:44
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:306
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:398
SCROW Row() const
Definition: address.hxx:261
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:660
void 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:574
static SC_DLLPUBLIC::utl::TransliterationWrapper * GetpTransliteration()
Definition: global.cxx:975
std::unique_ptr< ContentProperties > pData
bool empty() const
Definition: dbdata.cxx:1264
bool HasHeader() const
Definition: dbdata.hxx:129
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:386
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:1231
sal_Int64 n
NamedDBs(ScDBCollection &rParent, ScDocument &rDoc)
Definition: dbdata.cxx:1077
sal_Int32 mnCol
aBuf
void InvalidateTableColumnNames(bool bSwapToEmptyNames)
Definition: dbdata.cxx:715
bool IsClipOrUndo() const
Definition: document.hxx:1530
SCCOLROW nField
Definition: queryentry.hxx:51
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:527
SCROW nRow2
Definition: global.hxx:453
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:532
bool mbTableColumnNamesDirty
Definition: dbdata.hxx:96
SCCOL nStartCol
Definition: dbdata.hxx:74
bool bDoSize
Definition: dbdata.hxx:81
bool operator==(const ScDBData &rData) const
Definition: dbdata.cxx:211
bool has(const ScDBData *p) const
Definition: dbdata.cxx:1269
SfxHintId GetId() const
void ExtendDataArea(const ScDocument &rDoc)
Definition: dbdata.cxx:625
const ScAddress & GetAddress() const
Definition: brdcst.hxx:30
ScDBData * GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dbdata.cxx:1471
std::unique_ptr< ScSortParam > mpSortParam
Definition: dbdata.hxx:63
SCROW nRow2
Definition: sortparam.hxx:45
sal_uInt16 nEntryIndex
counter for unique indices
Definition: dbdata.hxx:306
bool IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:497
ScDBData * getByRange(const ScRange &rRange)
Definition: dbdata.cxx:1244
void SetModified(bool bMod)
Definition: dbdata.hxx:207
ScDocument & rDoc
Definition: dbdata.hxx:305
void SetImportParam(const ScImportParam &rImportParam)
Definition: dbdata.cxx:475
void UpdateReference(sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr, bool bIncludeDraw=true, bool bUpdateNoteCaptionPos=true)
Definition: documen3.cxx:1005
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:871
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
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
AnonDBs & getAnonDBs()
Definition: dbdata.hxx:317
bool hasString() const
Definition: cellvalue.cxx:617
int nCount
SCROW nStartRow
Definition: dbdata.hxx:75
void StartTableColumnNamesListener()
Definition: dbdata.cxx:644
SCCOL nCol2
Definition: global.hxx:452
SCTAB Tab() const
Definition: address.hxx:270
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:422
::std::vector< OUString > maTableColumnNames
names of table columns
Definition: dbdata.hxx:95
SCROW nRow1
Definition: global.hxx:451
ColorMode meMode
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:1346
SCCOL nCol1
Definition: sortparam.hxx:42
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:926
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:1223
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:1439
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:404
void SetContainer(ScDBDataContainerBase *pContainer)
Definition: dbdata.hxx:142
bool empty() const
Definition: dbdata.cxx:1497
bool operator==(const ScDBCollection &r) const
Definition: dbdata.cxx:1502
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:1259
sal_Int16 SCCOL
Definition: types.hxx:21
OUString aUpper
Definition: dbdata.hxx:72
bool HasSortParam() const
Definition: dbdata.cxx:520
bool operator==(const AnonDBs &r) const
Definition: dbdata.cxx:1274
SC_DLLPUBLIC void SetAdvancedQuerySource(const ScRange *pSource)
Definition: dbdata.cxx:431
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:893
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
void GetImportParam(ScImportParam &rImportParam) const
Definition: dbdata.cxx:465
std::unique_ptr< ScQueryParam > mpQueryParam
Definition: dbdata.hxx:64
void DeleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1418
SCTAB nTable
Definition: dbdata.hxx:73
void deleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1238
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:1097
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
void MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dbdata.cxx:344
bool IsValid() const
Definition: address.hxx:546
bool IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:481
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:300
size_t size() const
Definition: dbdata.cxx:1193
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:868
void GetSubTotalParam(ScSubTotalParam &rSubTotalParam) const
Definition: dbdata.cxx:448
ScDBData * findByUpperName(const OUString &rName)
Definition: dbdata.cxx:1147
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:309
sal_Int32 SCROW
Definition: types.hxx:17
void RefreshDirtyTableColumnNames()
Definition: dbdata.cxx:1404
void erase(const iterator &itr)
Definition: dbdata.cxx:1183
bool bHasHeader
Definition: sortparam.hxx:47
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:68
#define SAL_WARN_IF(condition, area, stream)
ScRangeList & GetDirtyTableColumnNames()
Definition: dbdata.cxx:1072
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
virtual ~NamedDBs() override
Definition: dbdata.cxx:1093
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:881
void AdjustTableColumnNames(UpdateRefMode eUpdateRefMode, SCCOL nDx, SCCOL nCol1, SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2)
Definition: dbdata.cxx:665
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:250
AnonDBs maAnonDBs
Definition: dbdata.hxx:308
static SC_DLLPUBLIC const CharClass * getCharClassPtr()
Definition: global.cxx:1009
bool empty() const
Definition: dbdata.cxx:1188
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:1298
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:409
bool AreTableColumnNamesDirty() const
Definition: dbdata.hxx:149
void EndTableColumnNamesListener()
Definition: dbdata.cxx:654
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:1067
iterator findByUpperName2(const OUString &rName)
Definition: dbdata.cxx:1154
SCCOL nCol1
Definition: global.hxx:450
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:460
SC_DLLPUBLIC bool GetAdvancedQuerySource(ScRange &rSource) const
Definition: dbdata.cxx:442
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:1464
ScDBCollection(ScDocument &rDocument)
Definition: dbdata.cxx:1292
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:779
std::unique_ptr< ScSubTotalParam > mpSubTotal
Definition: dbdata.hxx:65
sal_Int32 mnRow
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:32
SC_DLLPUBLIC void SetTableColumnNames(const ::std::vector< OUString > &rNames)
Definition: dbdata.cxx:659
void RemoveAll()
Definition: rangelst.cxx:1106
bool HasImportParam() const
Definition: dbdata.cxx:504
sal_Int16 SCTAB
Definition: types.hxx:22
Link< Timer *, void > aRefreshHandler
Definition: dbdata.hxx:304
NamedDBs maNamedDBs
Definition: dbdata.hxx:307
sal_uInt16 nIndex
unique index formulas
Definition: dbdata.hxx:91
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:79
bool operator==(const NamedDBs &r) const
Definition: dbdata.cxx:1198