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