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;
939  nSelected = nTotal - nFilteredRowCount;
940 }
941 
942 namespace {
943 
944 class FindByTable
945 {
946  SCTAB mnTab;
947 public:
948  explicit FindByTable(SCTAB nTab) : mnTab(nTab) {}
949 
950  bool operator() (std::unique_ptr<ScDBData> const& p) const
951  {
952  ScRange aRange;
953  p->GetArea(aRange);
954  return aRange.aStart.Tab() == mnTab;
955  }
956 };
957 
958 class UpdateRefFunc
959 {
960  ScDocument* mpDoc;
962  SCCOL mnCol1;
963  SCROW mnRow1;
964  SCTAB mnTab1;
965  SCCOL mnCol2;
966  SCROW mnRow2;
967  SCTAB mnTab2;
968  SCCOL mnDx;
969  SCROW mnDy;
970  SCTAB mnDz;
971 
972 public:
973  UpdateRefFunc(ScDocument* pDoc, UpdateRefMode eMode,
974  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
975  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
976  SCCOL nDx, SCROW nDy, SCTAB nDz) :
977  mpDoc(pDoc), meMode(eMode),
978  mnCol1(nCol1), mnRow1(nRow1), mnTab1(nTab1),
979  mnCol2(nCol2), mnRow2(nRow2), mnTab2(nTab2),
980  mnDx(nDx), mnDy(nDy), mnDz(nDz) {}
981 
982  void operator() (std::unique_ptr<ScDBData> const& p)
983  {
984  p->UpdateReference(mpDoc, meMode, mnCol1, mnRow1, mnTab1, mnCol2, mnRow2, mnTab2, mnDx, mnDy, mnDz);
985  }
986 };
987 
988 class UpdateMoveTabFunc
989 {
990  SCTAB mnOldTab;
991  SCTAB mnNewTab;
992 public:
993  UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
994  void operator() (std::unique_ptr<ScDBData> const& p)
995  {
996  p->UpdateMoveTab(mnOldTab, mnNewTab);
997  }
998 };
999 
1000 class FindByCursor
1001 {
1002  SCCOL mnCol;
1003  SCROW mnRow;
1004  SCTAB mnTab;
1005  ScDBDataPortion mePortion;
1006 public:
1007  FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) :
1008  mnCol(nCol), mnRow(nRow), mnTab(nTab), mePortion(ePortion) {}
1009 
1010  bool operator() (std::unique_ptr<ScDBData> const& p)
1011  {
1012  return p->IsDBAtCursor(mnCol, mnRow, mnTab, mePortion);
1013  }
1014 };
1015 
1016 class FindByRange
1017 {
1018  const ScRange& mrRange;
1019 public:
1020  explicit FindByRange(const ScRange& rRange) : mrRange(rRange) {}
1021 
1022  bool operator() (std::unique_ptr<ScDBData> const& p)
1023  {
1024  return p->IsDBAtArea(
1025  mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
1026  }
1027 };
1028 
1029 class FindByIndex
1030 {
1031  sal_uInt16 mnIndex;
1032 public:
1033  explicit FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
1034  bool operator() (std::unique_ptr<ScDBData> const& p) const
1035  {
1036  return p->GetIndex() == mnIndex;
1037  }
1038 };
1039 
1040 class FindByUpperName
1041 {
1042  const OUString& mrName;
1043 public:
1044  explicit FindByUpperName(const OUString& rName) : mrName(rName) {}
1045  bool operator() (std::unique_ptr<ScDBData> const& p) const
1046  {
1047  return p->GetUpperName() == mrName;
1048  }
1049 };
1050 
1051 class FindByPointer
1052 {
1053  const ScDBData* mpDBData;
1054 public:
1055  explicit FindByPointer(const ScDBData* pDBData) : mpDBData(pDBData) {}
1056  bool operator() (std::unique_ptr<ScDBData> const& p) const
1057  {
1058  return p.get() == mpDBData;
1059  }
1060 };
1061 
1062 }
1063 
1065 {
1066  return mrDoc;
1067 }
1068 
1070 {
1071  return maDirtyTableColumnNames;
1072 }
1073 
1075  ScDBDataContainerBase(rDoc), mrParent(rParent) {}
1076 
1078  : ScDBDataContainerBase(r.mrDoc)
1079  , mrParent(rParent)
1080 {
1081  for (auto const& it : r.m_DBs)
1082  {
1083  ScDBData* p = new ScDBData(*it);
1084  std::unique_ptr<ScDBData> pData(p);
1085  if (m_DBs.insert( std::move(pData)).second)
1086  initInserted(p);
1087  }
1088 }
1089 
1091 {
1092 }
1093 
1095 {
1096  p->SetContainer( this);
1097  if (mrDoc.IsClipOrUndo())
1098  return;
1099 
1100  p->StartTableColumnNamesListener(); // needs the container be set already
1101  if (!p->AreTableColumnNamesDirty())
1102  return;
1103 
1104  if (p->HasHeader())
1105  {
1106  // Refresh table column names in next round.
1107  maDirtyTableColumnNames.Join( p->GetHeaderArea());
1108  }
1109  else
1110  {
1111  // Header-less table can generate its column names
1112  // already without accessing the document.
1113  p->RefreshTableColumnNames( nullptr);
1114  }
1115 }
1116 
1118 {
1119  return m_DBs.begin();
1120 }
1121 
1123 {
1124  return m_DBs.end();
1125 }
1126 
1128 {
1129  return m_DBs.begin();
1130 }
1131 
1133 {
1134  return m_DBs.end();
1135 }
1136 
1138 {
1139  DBsType::iterator itr = find_if(
1140  m_DBs.begin(), m_DBs.end(), FindByIndex(nIndex));
1141  return itr == m_DBs.end() ? nullptr : itr->get();
1142 }
1143 
1145 {
1146  DBsType::iterator itr = find_if(
1147  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1148  return itr == m_DBs.end() ? nullptr : itr->get();
1149 }
1150 
1152 {
1153  return find_if(
1154  m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1155 }
1156 
1157 bool ScDBCollection::NamedDBs::insert(std::unique_ptr<ScDBData> pData)
1158 {
1159  auto p = pData.get();
1160  if (!pData->GetIndex())
1161  pData->SetIndex(mrParent.nEntryIndex++);
1162 
1163  pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
1164 
1165  if (r.second)
1166  {
1167  initInserted(p);
1168 
1169  /* TODO: shouldn't the import refresh not be setup for
1170  * clipboard/undo documents? It was already like this before... */
1171  if (p->HasImportParam() && !p->HasImportSelection())
1172  {
1173  p->SetRefreshHandler(mrParent.GetRefreshHandler());
1174  p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
1175  }
1176  }
1177  return r.second;
1178 }
1179 
1181 {
1182  m_DBs.erase(itr);
1183 }
1184 
1186 {
1187  return m_DBs.empty();
1188 }
1189 
1191 {
1192  return m_DBs.size();
1193 }
1194 
1196 {
1197  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1198 }
1199 
1201 {
1202  return m_DBs.begin();
1203 }
1204 
1206 {
1207  return m_DBs.end();
1208 }
1209 
1211 {
1212  return m_DBs.begin();
1213 }
1214 
1216 {
1217  return m_DBs.end();
1218 }
1219 
1221  ScDBDataPortion ePortion) const
1222 {
1223  DBsType::const_iterator itr = find_if(
1224  m_DBs.begin(), m_DBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1225  return itr == m_DBs.end() ? nullptr : itr->get();
1226 }
1227 
1229 {
1230  DBsType::const_iterator itr = find_if(
1231  m_DBs.begin(), m_DBs.end(), FindByRange(rRange));
1232  return itr == m_DBs.end() ? nullptr : itr->get();
1233 }
1234 
1236 {
1237  FindByTable func(nTab);
1238  m_DBs.erase(std::remove_if(m_DBs.begin(), m_DBs.end(), func), m_DBs.end());
1239 }
1240 
1242 {
1243  const ScDBData* pData = findByRange(rRange);
1244  if (!pData)
1245  {
1246  // Insert a new db data. They all have identical names.
1247  ::std::unique_ptr<ScDBData> pNew(new ScDBData(
1248  STR_DB_GLOBAL_NONAME, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
1249  rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
1250  pData = pNew.get();
1251  m_DBs.push_back(std::move(pNew));
1252  }
1253  return const_cast<ScDBData*>(pData);
1254 }
1255 
1257 {
1258  m_DBs.push_back(std::unique_ptr<ScDBData>(p));
1259 }
1260 
1262 {
1263  return m_DBs.empty();
1264 }
1265 
1267 {
1268  return any_of(m_DBs.begin(), m_DBs.end(), FindByPointer(p));
1269 }
1270 
1272 {
1273  return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1274 }
1275 
1277 {
1278 }
1279 
1281 {
1282  m_DBs.reserve(r.m_DBs.size());
1283  for (auto const& it : r.m_DBs)
1284  {
1285  m_DBs.push_back(std::make_unique<ScDBData>(*it));
1286  }
1287 }
1288 
1290  rDoc(rDocument), nEntryIndex(1), maNamedDBs(*this, rDocument) {}
1291 
1293  rDoc(r.rDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs, *this), maAnonDBs(r.maAnonDBs) {}
1294 
1295 const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
1296 {
1297  // First, search the global named db ranges.
1298  NamedDBs::DBsType::const_iterator itr = find_if(
1299  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1300  if (itr != maNamedDBs.end())
1301  return itr->get();
1302 
1303  // Check for the sheet-local anonymous db range.
1304  const ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1305  if (pNoNameData)
1306  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1307  return pNoNameData;
1308 
1309  // Check the global anonymous db ranges.
1310  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1311  if (pData)
1312  return pData;
1313 
1314  // Do NOT check for the document global temporary anonymous db range here.
1315 
1316  return nullptr;
1317 }
1318 
1320 {
1321  // First, search the global named db ranges.
1322  NamedDBs::DBsType::iterator itr = find_if(
1323  maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1324  if (itr != maNamedDBs.end())
1325  return itr->get();
1326 
1327  // Check for the sheet-local anonymous db range.
1328  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1329  if (pNoNameData)
1330  if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1331  return pNoNameData;
1332 
1333  // Check the global anonymous db ranges.
1334  const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1335  if (pData)
1336  return const_cast<ScDBData*>(pData);
1337 
1338  // Do NOT check for the document global temporary anonymous db range here.
1339 
1340  return nullptr;
1341 }
1342 
1343 const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
1344 {
1345  // First, search the global named db ranges.
1346  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1347  NamedDBs::DBsType::const_iterator itr = find_if(
1348  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1349  if (itr != maNamedDBs.end())
1350  return itr->get();
1351 
1352  // Check for the sheet-local anonymous db range.
1353  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1354  if (pNoNameData)
1355  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1356  return pNoNameData;
1357 
1358  // Lastly, check the global anonymous db ranges.
1359  const ScDBData* pData = maAnonDBs.findByRange(aRange);
1360  if (pData)
1361  return pData;
1362 
1363  // As a last resort, check for the document global temporary anonymous db range.
1364  pNoNameData = rDoc.GetAnonymousDBData();
1365  if (pNoNameData)
1366  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1367  return pNoNameData;
1368 
1369  return nullptr;
1370 }
1371 
1373 {
1374  // First, search the global named db ranges.
1375  ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1376  NamedDBs::DBsType::iterator itr = find_if(
1377  maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1378  if (itr != maNamedDBs.end())
1379  return itr->get();
1380 
1381  // Check for the sheet-local anonymous db range.
1382  ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1383  if (pNoNameData)
1384  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1385  return pNoNameData;
1386 
1387  // Lastly, check the global anonymous db ranges.
1388  const ScDBData* pData = getAnonDBs().findByRange(aRange);
1389  if (pData)
1390  return const_cast<ScDBData*>(pData);
1391 
1392  // As a last resort, check for the document global temporary anonymous db range.
1393  pNoNameData = rDoc.GetAnonymousDBData();
1394  if (pNoNameData)
1395  if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1396  return pNoNameData;
1397 
1398  return nullptr;
1399 }
1400 
1402 {
1403  for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
1404  {
1405  const ScRange & rRange = maNamedDBs.maDirtyTableColumnNames[i];
1406  for (auto const& it : maNamedDBs)
1407  {
1408  if (it->AreTableColumnNamesDirty())
1409  it->RefreshTableColumnNames( &maNamedDBs.mrDoc, rRange);
1410  }
1411  }
1413 }
1414 
1416 {
1417  FindByTable func(nTab);
1418  // First, collect the positions of all items that need to be deleted.
1419  ::std::vector<NamedDBs::DBsType::iterator> v;
1420  {
1421  NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
1422  for (; itr != itrEnd; ++itr)
1423  {
1424  if (func(*itr))
1425  v.push_back(itr);
1426  }
1427  }
1428 
1429  // Delete them all.
1430  for (const auto& rIter : v)
1431  maNamedDBs.erase(rIter);
1432 
1433  maAnonDBs.deleteOnTab(nTab);
1434 }
1435 
1437  SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1438  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1439  SCCOL nDx, SCROW nDy, SCTAB nDz )
1440 {
1442  if (pData)
1443  {
1444  if (nTab1 == nTab2 && nDz == 0)
1445  {
1446  pData->UpdateReference(
1447  &rDoc, eUpdateRefMode,
1448  nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
1449  }
1450  else
1451  {
1452  //this will perhaps break undo
1453  }
1454  }
1455 
1456  UpdateRefFunc func(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
1457  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1458  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1459 }
1460 
1462 {
1463  UpdateMoveTabFunc func(nOldPos, nNewPos);
1464  for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1465  for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1466 }
1467 
1469 {
1470  ScDBData* pNearData = nullptr;
1471  for (const auto& rxNamedDB : maNamedDBs)
1472  {
1473  SCTAB nAreaTab;
1474  SCCOL nStartCol, nEndCol;
1475  SCROW nStartRow, nEndRow;
1476  rxNamedDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1477  if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
1478  nRow+1 >= nStartRow && nRow <= nEndRow+1 )
1479  {
1480  if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
1481  {
1482  if (!pNearData)
1483  pNearData = rxNamedDB.get(); // remember first adjacent area
1484  }
1485  else
1486  return rxNamedDB.get(); // not "unbenannt"/"unnamed" and cursor within
1487  }
1488  }
1489  if (pNearData)
1490  return pNearData; // adjacent, if no direct hit
1491  return rDoc.GetAnonymousDBData(nTab); // "unbenannt"/"unnamed" only if nothing else
1492 }
1493 
1495 {
1496  return maNamedDBs.empty() && maAnonDBs.empty();
1497 }
1498 
1500 {
1501  return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
1503 }
1504 
1505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScDBData & operator=(const ScDBData &rData)
Definition: dbdata.cxx:159
ScDocument & mrDoc
Definition: dbdata.hxx:57
ScRefreshTimer & operator=(const ScRefreshTimer &r)
SCROW nRow1
Definition: sortparam.hxx:44
ScRange aAdvSource
source range
Definition: dbdata.hxx:88
ScRangeList maDirtyTableColumnNames
Definition: dbdata.hxx:58
bool insert(std::unique_ptr< ScDBData > p)
Takes ownership of p and attempts to insert it into the collection.
Definition: dbdata.cxx:1157
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:500
ScDBData * findByIndex(sal_uInt16 nIndex)
Definition: dbdata.cxx:1137
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:2127
void GetFilterSelCount(SCSIZE &nSelected, SCSIZE &nTotal)
Definition: dbdata.cxx:934
#define EMPTY_OUSTRING
Definition: global.hxx:216
SCCOL nCol2
Definition: sortparam.hxx:45
SCCOL nCol1
selected area
Container base class to provide selected access for ScDBData.
Definition: dbdata.hxx:48
SC_DLLPUBLIC ScDBData * GetAnonymousDBData(SCTAB nTab)
Definition: document.cxx:305
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:398
SCROW Row() const
Definition: address.hxx:262
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:1261
bool HasHeader() const
Definition: dbdata.hxx:130
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:386
bool bIsAdvanced
QueryParam.
Definition: dbdata.hxx:87
OUString GetSourceString() const
Definition: dbdata.cxx:258
long Long
const ScDBData * findByRange(const ScRange &rRange) const
Definition: dbdata.cxx:1228
sal_Int64 n
NamedDBs(ScDBCollection &rParent, ScDocument &rDoc)
Definition: dbdata.cxx:1074
sal_Int32 mnCol
aBuf
void InvalidateTableColumnNames(bool bSwapToEmptyNames)
Definition: dbdata.cxx:715
bool IsClipOrUndo() const
Definition: document.hxx:1525
SCCOLROW nField
Definition: queryentry.hxx:51
ScAddress aEnd
Definition: address.hxx:501
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:104
bool HasSubTotalParam() const
Definition: dbdata.cxx:527
SCROW nRow2
Definition: global.hxx:455
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:532
bool mbTableColumnNamesDirty
Definition: dbdata.hxx:97
SCCOL nStartCol
Definition: dbdata.hxx:75
bool bDoSize
Definition: dbdata.hxx:82
bool operator==(const ScDBData &rData) const
Definition: dbdata.cxx:211
bool has(const ScDBData *p) const
Definition: dbdata.cxx:1266
SfxHintId GetId() const
void ExtendDataArea(const ScDocument &rDoc)
Definition: dbdata.cxx:625
const ScAddress & GetAddress() const
Definition: brdcst.hxx:31
ScDBData * GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dbdata.cxx:1468
std::unique_ptr< ScSortParam > mpSortParam
Definition: dbdata.hxx:64
SCROW nRow2
Definition: sortparam.hxx:46
sal_uInt16 nEntryIndex
counter for unique indices
Definition: dbdata.hxx:307
bool IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:497
ScDBData * getByRange(const ScRange &rRange)
Definition: dbdata.cxx:1241
void SetModified(bool bMod)
Definition: dbdata.hxx:208
ScDocument & rDoc
Definition: dbdata.hxx:306
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:999
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:870
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:45
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
AnonDBs & getAnonDBs()
Definition: dbdata.hxx:318
bool hasString() const
Definition: cellvalue.cxx:617
int nCount
SCROW nStartRow
Definition: dbdata.hxx:76
void StartTableColumnNamesListener()
Definition: dbdata.cxx:644
SCCOL nCol2
Definition: global.hxx:454
SCTAB Tab() const
Definition: address.hxx:271
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:422
::std::vector< OUString > maTableColumnNames
names of table columns
Definition: dbdata.hxx:96
SCROW nRow1
Definition: global.hxx:453
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:1343
SCCOL nCol1
Definition: sortparam.hxx:43
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:1094
ScDBDataPortion
Enum used to indicate which portion of the DBArea is to be considered.
Definition: dbdata.hxx:41
void CalcSaveFilteredCount(SCSIZE nNonFilteredRowCount)
Definition: dbdata.cxx:926
bool bKeepFmt
Definition: dbdata.hxx:83
bool bAutoFilter
AutoFilter? (not saved)
Definition: dbdata.hxx:93
SCROW nEndRow
Definition: dbdata.hxx:78
SCCOL nEndCol
Definition: dbdata.hxx:77
const ScDBData * findAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1220
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:1436
const OUString aName
DBParam.
Definition: dbdata.hxx:72
int i
bool bHasTotals
Definition: dbdata.hxx:81
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:143
bool empty() const
Definition: dbdata.cxx:1494
bool operator==(const ScDBCollection &r) const
Definition: dbdata.cxx:1499
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:406
void insert(ScDBData *p)
Definition: dbdata.cxx:1256
sal_Int16 SCCOL
Definition: types.hxx:22
OUString aUpper
Definition: dbdata.hxx:73
bool HasSortParam() const
Definition: dbdata.cxx:520
bool operator==(const AnonDBs &r) const
Definition: dbdata.cxx:1271
SC_DLLPUBLIC void SetAdvancedQuerySource(const ScRange *pSource)
Definition: dbdata.cxx:431
SCSIZE nFilteredRowCount
Definition: dbdata.hxx:98
DBsType::iterator iterator
Definition: dbdata.hxx:250
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:90
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:65
void DeleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1415
SCTAB nTable
Definition: dbdata.hxx:74
void deleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1235
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:693
void initInserted(ScDBData *p)
Definition: dbdata.cxx:1094
bool In(const ScAddress &) const
is Address& in Range?
Definition: address.hxx:733
bool bByRow
Definition: dbdata.hxx:79
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:547
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:1190
void StopRefreshTimer()
Reference not affected, no change at all.
Definition: refupdat.hxx:32
SCCOL Col() const
Definition: address.hxx:267
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:1144
top left cell of area
DBsType::iterator iterator
Definition: dbdata.hxx:287
float v
Stores global named database ranges.
Definition: dbdata.hxx:235
UpdateRefMode
Definition: global.hxx:312
sal_Int32 SCROW
Definition: types.hxx:18
void RefreshDirtyTableColumnNames()
Definition: dbdata.cxx:1401
void erase(const iterator &itr)
Definition: dbdata.cxx:1180
bool bHasHeader
Definition: sortparam.hxx:48
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:69
#define SAL_WARN_IF(condition, area, stream)
ScRangeList & GetDirtyTableColumnNames()
Definition: dbdata.cxx:1069
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:164
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:288
#define STR_DB_GLOBAL_NONAME
Definition: globalnames.hxx:14
OUString aName
virtual ~NamedDBs() override
Definition: dbdata.cxx:1090
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:251
AnonDBs maAnonDBs
Definition: dbdata.hxx:309
static SC_DLLPUBLIC const CharClass * getCharClassPtr()
Definition: global.cxx:1009
bool empty() const
Definition: dbdata.cxx:1185
bool bDBSelection
not in Param: if selection, block update
Definition: dbdata.hxx:90
const ScDBData * GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1295
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:409
bool AreTableColumnNamesDirty() const
Definition: dbdata.hxx:150
void EndTableColumnNamesListener()
Definition: dbdata.cxx:654
std::unique_ptr< ScImportParam > mpImportParam
Definition: dbdata.hxx:67
bool bHasHeader
Definition: dbdata.hxx:80
bool bModified
is set/cleared for/by(?) UpdateReference
Definition: dbdata.hxx:94
ScDocument & GetDocument() const
Definition: dbdata.cxx:1064
iterator findByUpperName2(const OUString &rName)
Definition: dbdata.cxx:1151
SCCOL nCol1
Definition: global.hxx:452
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:1461
ScDBCollection(ScDocument &rDocument)
Definition: dbdata.cxx:1289
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:34
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:66
sal_Int32 mnRow
virtual SC_DLLPUBLIC ~ScDBData() override
Definition: dbdata.cxx:253
int mnIndex
bool bStripData
Definition: dbdata.hxx:84
BaseContainerNodeSharedPtr & mrParent
aStr
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
SC_DLLPUBLIC void SetTableColumnNames(const ::std::vector< OUString > &rNames)
Definition: dbdata.cxx:659
void RemoveAll()
Definition: rangelst.cxx:1106
bool HasImportParam() const
Definition: dbdata.cxx:504
sal_Int16 SCTAB
Definition: types.hxx:23
Link< Timer *, void > aRefreshHandler
Definition: dbdata.hxx:305
NamedDBs maNamedDBs
Definition: dbdata.hxx:308
sal_uInt16 nIndex
unique index formulas
Definition: dbdata.hxx:92
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:80
bool operator==(const NamedDBs &r) const
Definition: dbdata.cxx:1195