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>
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
41
42#include <memory>
43#include <utility>
44
45using ::std::unique_ptr;
46using ::std::for_each;
47using ::std::find_if;
48using ::std::remove_if;
49using ::std::pair;
50
51bool ScDBData::less::operator() (const std::unique_ptr<ScDBData>& left, const std::unique_ptr<ScDBData>& right) const
52{
53 return ScGlobal::GetTransliteration().compareString(left->GetUpperName(), right->GetUpperName()) < 0;
54}
55
56ScDBData::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
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
124ScDBData::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 }
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;
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
211bool 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
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
300void 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
309void 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
322void 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
344void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
345 SCCOL nUpdateCol)
346{
347 tools::Long nDifX = static_cast<tools::Long>(nCol1) - static_cast<tools::Long>(nStartCol);
348 tools::Long nDifY = static_cast<tools::Long>(nRow1) - static_cast<tools::Long>(nStartRow);
349
350 tools::Long nSortDif = bByRow ? nDifX : nDifY;
351 tools::Long nSortEnd = bByRow ? static_cast<tools::Long>(nCol2) : static_cast<tools::Long>(nRow2);
352
353 for (sal_uInt16 i=0; i<mpSortParam->GetSortKeyCount(); i++)
354 {
355 mpSortParam->maKeyState[i].nField += nSortDif;
356 if (mpSortParam->maKeyState[i].nField > nSortEnd)
357 {
358 mpSortParam->maKeyState[i].nField = 0;
359 mpSortParam->maKeyState[i].bDoSort = false;
360 }
361 }
362
363 SCSIZE nCount = mpQueryParam->GetEntryCount();
364 for (SCSIZE i = 0; i < nCount; ++i)
365 {
366 ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
367 rEntry.nField += nDifX;
368
369 // tdf#48025, tdf#141946: update the column index of the filter criteria,
370 // when the deleted/inserted columns are inside the data range
371 if (nUpdateCol != -1)
372 {
373 nUpdateCol += nDifX;
374 tools::Long nDifX2
375 = static_cast<tools::Long>(nCol2) - static_cast<tools::Long>(nEndCol);
376 if (rEntry.nField >= nUpdateCol)
377 rEntry.nField += nDifX2;
378 else if (rEntry.nField >= nUpdateCol + nDifX2)
379 rEntry.Clear();
380 }
381
382 if (rEntry.nField > nCol2)
383 {
384 rEntry.nField = 0;
385 rEntry.bDoQuery = false;
386 }
387 }
388 for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
389 {
390 mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
391 if (mpSubTotal->nField[i] > nCol2)
392 {
393 mpSubTotal->nField[i] = 0;
394 mpSubTotal->bGroupActive[i] = false;
395 }
396 }
397
398 SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
399}
400
401void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
402{
403 rSortParam = *mpSortParam;
404 rSortParam.nCol1 = nStartCol;
405 rSortParam.nRow1 = nStartRow;
406 rSortParam.nCol2 = nEndCol;
407 rSortParam.nRow2 = nEndRow;
408 rSortParam.bByRow = bByRow;
409 rSortParam.bHasHeader = bHasHeader;
410 /* TODO: add Totals to ScSortParam? */
411}
412
413void ScDBData::SetSortParam( const ScSortParam& rSortParam )
414{
415 mpSortParam.reset(new ScSortParam(rSortParam));
416 bByRow = rSortParam.bByRow;
417}
418
420{
421 bHasHeader = rSortParam.bHasHeader;
422}
423
424void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
425{
426 rQueryParam = *mpQueryParam;
427 rQueryParam.nCol1 = nStartCol;
428 rQueryParam.nRow1 = nStartRow;
429 rQueryParam.nCol2 = nEndCol;
430 rQueryParam.nRow2 = nEndRow;
431 rQueryParam.nTab = nTable;
432 rQueryParam.bByRow = bByRow;
433 rQueryParam.bHasHeader = bHasHeader;
434 /* TODO: add Totals to ScQueryParam? */
435}
436
437void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
438{
439 mpQueryParam.reset(new ScQueryParam(rQueryParam));
440
441 // set bIsAdvanced to false for everything that is not from the
442 // advanced filter dialog
443 bIsAdvanced = false;
444}
445
447{
448 if (pSource)
449 {
450 aAdvSource = *pSource;
451 bIsAdvanced = true;
452 }
453 else
454 bIsAdvanced = false;
455}
456
458{
459 rSource = aAdvSource;
460 return bIsAdvanced;
461}
462
464{
465 rSubTotalParam = *mpSubTotal;
466
467 // Share the data range with the parent db data. The range in the subtotal
468 // param struct is not used.
469 rSubTotalParam.nCol1 = nStartCol;
470 rSubTotalParam.nRow1 = nStartRow;
471 rSubTotalParam.nCol2 = nEndCol;
472 rSubTotalParam.nRow2 = nEndRow;
473}
474
476{
477 mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
478}
479
481{
482 rImportParam = *mpImportParam;
483 // set the range.
484 rImportParam.nCol1 = nStartCol;
485 rImportParam.nRow1 = nStartRow;
486 rImportParam.nCol2 = nEndCol;
487 rImportParam.nRow2 = nEndRow;
488}
489
491{
492 // the range is ignored.
493 mpImportParam.reset(new ScImportParam(rImportParam));
494}
495
496bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
497{
498 if (nTab == nTable)
499 {
500 switch (ePortion)
501 {
503 return nCol == nStartCol && nRow == nStartRow;
505 return nCol >= nStartCol && nCol <= nEndCol && nRow >= nStartRow && nRow <= nEndRow;
506 }
507 }
508
509 return false;
510}
511
512bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
513{
514 return (nTab == nTable)
515 && (nCol1 == nStartCol) && (nRow1 == nStartRow)
516 && (nCol2 == nEndCol) && (nRow2 == nEndRow);
517}
518
520{
521 return mpImportParam && mpImportParam->bImport;
522}
523
525{
526 if (!mpQueryParam)
527 return false;
528
529 if (!mpQueryParam->GetEntryCount())
530 return false;
531
532 return mpQueryParam->GetEntry(0).bDoQuery;
533}
534
536{
537 return mpSortParam &&
538 !mpSortParam->maKeyState.empty() &&
539 mpSortParam->maKeyState[0].bDoSort;
540}
541
543{
544 return mpSubTotal && mpSubTotal->bGroupActive[0];
545}
546
547void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
548{
549 ScRange aRange;
550 GetArea(aRange);
551 SCTAB nTab = aRange.aStart.Tab(); // a database range is only on one sheet
552
553 // customize as the current table as ScTablesHint (tabvwsh5.cxx)
554
555 if (nTab == nOldPos) // moved sheet
556 nTab = nNewPos;
557 else if (nOldPos < nNewPos) // moved to the back
558 {
559 if (nTab > nOldPos && nTab <= nNewPos) // move this sheet
560 --nTab;
561 }
562 else // moved to the front
563 {
564 if (nTab >= nNewPos && nTab < nOldPos) // move this sheet
565 ++nTab;
566 }
567
568 bool bChanged = (nTab != aRange.aStart.Tab());
569 if (bChanged)
570 {
571 // SetArea() invalidates column names, but it is the same column range
572 // just on a different sheet; remember and set new.
573 ::std::vector<OUString> aNames(maTableColumnNames);
574 bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
575 // Same column range.
576 SetArea(nTab, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(),
577 aRange.aEnd.Row());
578 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
579 maTableColumnNames = aNames;
580 mbTableColumnNamesDirty = bTableColumnNamesDirty;
581 }
582
583 // MoveTo() is not necessary if only the sheet changed.
584
585 SetModified(bChanged);
586}
587
588bool ScDBData::UpdateReference(const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
589 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
590 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
591 SCCOL nDx, SCROW nDy, SCTAB nDz)
592{
593 SCCOL theCol1;
594 SCROW theRow1;
595 SCTAB theTab1;
596 SCCOL theCol2;
597 SCROW theRow2;
598 SCTAB theTab2;
599 GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
600 theTab2 = theTab1;
601 SCCOL nOldCol1 = theCol1, nOldCol2 = theCol2;
602
603 ScRefUpdateRes eRet
604 = ScRefUpdate::Update(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx,
605 nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
606
607 bool bDoUpdate = eRet != UR_NOTHING;
608
609 if (bDoUpdate && eRet != UR_INVALID)
610 {
611 // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
612 AdjustTableColumnAttributes( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
613 ::std::vector<OUString> aNames( maTableColumnNames);
614 bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
615 // tdf#48025, tdf#141946: update the column index of the filter criteria,
616 // when the deleted/inserted columns are inside the data range
617 if (HasAutoFilter() && theCol1 - nOldCol1 != theCol2 - nOldCol2)
618 MoveTo(theTab1, theCol1, theRow1, theCol2, theRow2, nCol1);
619 else
620 MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
621 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
622 maTableColumnNames = aNames;
623 mbTableColumnNamesDirty = bTableColumnNamesDirty;
624 }
625
626 ScRange aRangeAdvSource;
627 if ( GetAdvancedQuerySource(aRangeAdvSource) )
628 {
629 aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
630 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
631 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
632 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
633 {
634 aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
635 aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
636 SetAdvancedQuerySource( &aRangeAdvSource );
637
638 bDoUpdate = true; // DBData is modified
639 }
640 }
641
642 SetModified(bDoUpdate);
643
644 return eRet == UR_INVALID;
645
646 //TODO: check if something was deleted/inserted with-in the range !!!
647}
648
650{
651 // Extend the DB area to include data rows immediately below.
652 SCCOL nOldCol1 = nStartCol, nOldCol2 = nEndCol;
653 SCROW nOldEndRow = nEndRow;
654 rDoc.GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
655 // nOldEndRow==rDoc.MaxRow() may easily happen when selecting whole columns and
656 // setting an AutoFilter (i.e. creating an anonymous database-range). We
657 // certainly don't want to iterate over nearly a million empty cells, but
658 // keep only an intentionally user selected range.
659 if (nOldEndRow < rDoc.MaxRow() && nEndRow < nOldEndRow)
660 nEndRow = nOldEndRow;
661 if (nStartCol != nOldCol1 || nEndCol != nOldCol2)
662 {
663 SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
665 }
666}
667
669{
670 if (mpContainer && bHasHeader)
671 {
673 if (!rDoc.IsClipOrUndo())
674 rDoc.StartListeningArea( GetHeaderArea(), false, this);
675 }
676}
677
679{
681}
682
683void ScDBData::SetTableColumnNames( ::std::vector< OUString >&& rNames )
684{
685 maTableColumnNames = std::move(rNames);
687}
688
689void ScDBData::SetTableColumnAttributes( ::std::vector< TableColumnAttributes >&& rAttributes )
690{
691 maTableColumnAttributes = std::move(rAttributes);
692}
693
695 SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2 )
696{
697 if (maTableColumnNames.empty())
698 return;
699
700 SCCOL nDiff1 = nNewCol1 - nOldCol1;
701 SCCOL nDiff2 = nNewCol2 - nOldCol2;
702 if (nDiff1 == nDiff2)
703 return; // not moved or entirely moved, nothing to do
704
705 ::std::vector<OUString> aNewNames;
706 ::std::vector<TableColumnAttributes> aNewAttributes;
707 if (eUpdateRefMode == URM_INSDEL)
708 {
709 if (nDx > 0)
710 mbTableColumnNamesDirty = true; // inserted columns will have empty names
711
712 // nCol1 is the first column of the block that gets shifted, determine
713 // the head and tail elements that are to be copied for deletion or
714 // insertion.
715 size_t nHead = static_cast<size_t>(::std::max( nCol1 + std::min<SCCOL>(nDx, 0) - nOldCol1, 0));
716 size_t nTail = static_cast<size_t>(::std::max( nOldCol2 - nCol1 + 1, 0));
717 size_t n = nHead + nTail;
718 if (0 < n && n <= maTableColumnNames.size())
719 {
720 if (nDx > 0)
721 n += nDx;
722 aNewNames.resize(n);
723 aNewAttributes.resize(n);
725 // Copy head.
726 for (size_t i = 0; i < nHead; ++i)
727 {
728 aNewNames[i] = maTableColumnNames[i];
729 aNewAttributes[i] = maTableColumnAttributes[i];
730 }
731 // Copy tail, inserted middle range, if any, stays empty.
732 for (size_t i = n - nTail, j = maTableColumnNames.size() - nTail; i < n; ++i, ++j)
733 {
734 aNewNames[i] = maTableColumnNames[j];
735 aNewAttributes[i] = maTableColumnAttributes[j];
736 }
737 }
738 } // else empty aNewNames invalidates names/offsets
739
740 SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
741 "sc.core", "ScDBData::AdjustTableColumnAttributes - invalidating column attributes/offsets");
742 aNewNames.swap( maTableColumnNames);
743 aNewAttributes.swap(maTableColumnAttributes);
744 if (maTableColumnNames.empty())
747 InvalidateTableColumnNames( false); // preserve new column names array
748}
749
750void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames )
751{
753 if (bSwapToEmptyNames && !maTableColumnNames.empty())
754 ::std::vector<OUString>().swap( maTableColumnNames);
755 if (mpContainer)
756 {
757 // Add header range to dirty list.
758 if (HasHeader())
760 else
761 {
762 // We need *some* range in the dirty list even without header area,
763 // otherwise the container would not attempt to call a refresh.
765 }
766 }
767}
768
769namespace {
770class TableColumnNameSearch
771{
772public:
773 explicit TableColumnNameSearch( OUString aSearchName ) :
774 maSearchName(std::move( aSearchName ))
775 {
776 }
777
778 bool operator()( const OUString& rName ) const
779 {
780 return ScGlobal::GetTransliteration().isEqual( maSearchName, rName);
781 }
782
783private:
784 OUString maSearchName;
785};
786
791void SetTableColumnName( ::std::vector<OUString>& rVec, size_t nIndex, const OUString& rName, size_t nCount )
792{
793 OUString aStr;
794 do
795 {
796 if (nCount)
797 aStr = rName + OUString::number( nCount);
798 else
799 {
800 aStr = rName;
801 ++nCount;
802 }
803
804 if (std::none_of( rVec.begin(), rVec.end(), TableColumnNameSearch( aStr)))
805 {
806 rVec[nIndex] = aStr;
807 break; // do while
808 }
809 ++nCount;
810 } while(true);
811}
812}
813
815{
816 ::std::vector<OUString> aNewNames;
817 aNewNames.resize( nEndCol - nStartCol + 1);
818 bool bHaveEmpty = false;
819 if (!HasHeader() || !pDoc)
820 bHaveEmpty = true; // Assume we have empty ones and fill below.
821 else
822 {
823 ScHorizontalCellIterator aIter(*pDoc, nTable, nStartCol, nStartRow, nEndCol, nStartRow); // header row only
824 ScRefCellValue* pCell;
825 SCCOL nCol, nLastColFilled = nStartCol - 1;
826 SCROW nRow;
827 while ((pCell = aIter.GetNext( nCol, nRow)) != nullptr)
828 {
829 if (pCell->hasString())
830 {
831 const OUString& rStr = pCell->getString( pDoc);
832 if (rStr.isEmpty())
833 bHaveEmpty = true;
834 else
835 {
836 SetTableColumnName( aNewNames, nCol-nStartCol, rStr, 0);
837 if (nLastColFilled < nCol-1)
838 bHaveEmpty = true;
839 }
840 nLastColFilled = nCol;
841 }
842 else
843 bHaveEmpty = true;
844 }
845 }
846
847 // Never leave us with empty names, try to remember previous name that
848 // might had been used to compile formulas, but only if same number of
849 // columns and no duplicates.
850 if (bHaveEmpty && aNewNames.size() == maTableColumnNames.size())
851 {
852 bHaveEmpty = false;
853 for (size_t i=0, n=aNewNames.size(); i < n; ++i)
854 {
855 if (aNewNames[i].isEmpty())
856 {
857 const OUString& rStr = maTableColumnNames[i];
858 if (rStr.isEmpty())
859 bHaveEmpty = true;
860 else
861 SetTableColumnName( aNewNames, i, rStr, 0);
862 }
863 }
864 }
865
866 // If we still have empty ones then fill those with "Column#" with #
867 // starting at the column offset number. Still no duplicates of course.
868 if (bHaveEmpty)
869 {
870 OUString aColumn( ScResId(STR_COLUMN));
871 for (size_t i=0, n=aNewNames.size(); i < n; ++i)
872 {
873 if (aNewNames[i].isEmpty())
874 SetTableColumnName( aNewNames, i, aColumn, i+1);
875 }
876 }
877
878 aNewNames.swap( maTableColumnNames);
880}
881
883{
884 // Header-less tables get names generated, completely empty a full refresh.
886 {
888 return;
889 }
890
891 // Check if this is affected for the range requested.
892 ScRange aIntersection( GetHeaderArea().Intersection( rRange));
893 if (!aIntersection.IsValid())
894 return;
895
896 // Always fully refresh, only one cell of a range was broadcasted per area
897 // listener if multiple cells were affected. We don't know if there were
898 // more. Also, we need the full check anyway in case a duplicated name was
899 // entered.
901}
902
903sal_Int32 ScDBData::GetColumnNameOffset( const OUString& rName ) const
904{
905 if (maTableColumnNames.empty())
906 return -1;
907
908 ::std::vector<OUString>::const_iterator it(
909 ::std::find_if( maTableColumnNames.begin(), maTableColumnNames.end(), TableColumnNameSearch( rName)));
910 if (it != maTableColumnNames.end())
911 return it - maTableColumnNames.begin();
912
913 return -1;
914}
915
917{
918 if (maTableColumnNames.empty())
919 return OUString();
920
921 SCCOL nOffset = nCol - nStartCol;
922 if (nOffset < 0 || maTableColumnNames.size() <= o3tl::make_unsigned(nOffset))
923 return OUString();
924
925 return maTableColumnNames[nOffset];
926}
927
928void ScDBData::Notify( const SfxHint& rHint )
929{
930 if (rHint.GetId() != SfxHintId::ScDataChanged)
931 return;
932 const ScHint* pScHint = static_cast<const ScHint*>(&rHint);
933
935 if (!mpContainer)
936 assert(!"ScDBData::Notify - how did we end up here without container?");
937 else
938 {
939 // Only one cell of a range is broadcasted per area listener if
940 // multiple cells are affected. Expand the range to what this is
941 // listening to. Broadcasted address outside should not happen,
942 // but... let it trigger a refresh if.
943 const ScRange aHeaderRange( GetHeaderArea());
944 ScAddress aHintAddress( pScHint->GetStartAddress());
945 if (aHeaderRange.IsValid())
946 {
947 mpContainer->GetDirtyTableColumnNames().Join( aHeaderRange);
948 // Header range is one row.
949 // The ScHint's "range" is an address with row count.
950 // Though broadcasted is usually only one cell, check for the
951 // possible case of row block and for one cell in the same row.
952 if (aHintAddress.Row() <= aHeaderRange.aStart.Row()
953 && aHeaderRange.aStart.Row() < aHintAddress.Row() + pScHint->GetRowCount())
954 {
955 aHintAddress.SetRow( aHeaderRange.aStart.Row());
956 if (!aHeaderRange.Contains( aHintAddress))
957 mpContainer->GetDirtyTableColumnNames().Join( aHintAddress);
958 }
959 }
960 else
961 {
962 // We need *some* range in the dirty list even without header area,
963 // otherwise the container would not attempt to call a refresh.
964 aHintAddress.SetRow( nStartRow);
965 mpContainer->GetDirtyTableColumnNames().Join( aHintAddress);
966 }
967 }
968
969 // Do not refresh column names here, which might trigger unwanted
970 // recalculation.
971}
972
973void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount )
974{
975 SCSIZE nTotal = nEndRow - nStartRow + 1;
976 if ( bHasHeader )
977 nTotal -= 1;
978 nFilteredRowCount = nTotal - nNonFilteredRowCount;
979}
980
981void ScDBData::GetFilterSelCount( SCSIZE& nSelected, SCSIZE& nTotal )
982{
983 nTotal = nEndRow - nStartRow + 1;
984 if ( bHasHeader )
985 nTotal -= 1;
987 nSelected = nTotal - nFilteredRowCount;
988 else
989 nSelected = nFilteredRowCount;
990}
991
992namespace {
993
994class FindByTable
995{
996 SCTAB mnTab;
997public:
998 explicit FindByTable(SCTAB nTab) : mnTab(nTab) {}
999
1000 bool operator() (std::unique_ptr<ScDBData> const& p) const
1001 {
1002 ScRange aRange;
1003 p->GetArea(aRange);
1004 return aRange.aStart.Tab() == mnTab;
1005 }
1006};
1007
1008class UpdateMoveTabFunc
1009{
1010 SCTAB mnOldTab;
1011 SCTAB mnNewTab;
1012public:
1013 UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
1014 void operator() (std::unique_ptr<ScDBData> const& p)
1015 {
1016 p->UpdateMoveTab(mnOldTab, mnNewTab);
1017 }
1018};
1019
1020OUString lcl_IncrementNumberInNamedRange(ScDBCollection::NamedDBs& namedDBs,
1021 std::u16string_view rOldName)
1022{
1023 // Append or increment a numeric suffix and do not generate names that
1024 // could result in a cell reference by ensuring at least one underscore is
1025 // present.
1026 // "aa" => "aa_2"
1027 // "aaaa1" => "aaaa1_2"
1028 // "aa_a" => "aa_a_2"
1029 // "aa_a_" => "aa_a__2"
1030 // "aa_a1" => "aa_a1_2"
1031 // "aa_1a" => "aa_1a_2"
1032 // "aa_1" => "aa_2"
1033 // "aa_2" => "aa_3"
1034
1035 size_t nLastIndex = rOldName.rfind('_');
1036 sal_Int32 nOldNumber = 1;
1037 OUString aPrefix;
1038 if (nLastIndex != std::u16string_view::npos)
1039 {
1040 ++nLastIndex;
1041 std::u16string_view sLastPart(rOldName.substr(nLastIndex));
1042 nOldNumber = o3tl::toInt32(sLastPart);
1043
1044 // If that number is exactly at the end then increment the number; else
1045 // append "_" and number.
1046 // toInt32() returns 0 on failure and also stops at trailing non-digit
1047 // characters (toInt32("1a")==1).
1048 if (OUString::number(nOldNumber) == sLastPart)
1049 aPrefix = rOldName.substr(0, nLastIndex);
1050 else
1051 {
1052 aPrefix = OUString::Concat(rOldName) + "_";
1053 nOldNumber = 1;
1054 }
1055 }
1056 else // No "_" found, append "_" and number.
1057 aPrefix = OUString::Concat(rOldName) + "_";
1058 OUString sNewName;
1059 do
1060 {
1061 sNewName = aPrefix + OUString::number(++nOldNumber);
1062 } while (namedDBs.findByName(sNewName) != nullptr);
1063 return sNewName;
1064}
1065
1066class FindByCursor
1067{
1068 SCCOL mnCol;
1069 SCROW mnRow;
1070 SCTAB mnTab;
1071 ScDBDataPortion mePortion;
1072public:
1073 FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) :
1074 mnCol(nCol), mnRow(nRow), mnTab(nTab), mePortion(ePortion) {}
1075
1076 bool operator() (std::unique_ptr<ScDBData> const& p)
1077 {
1078 return p->IsDBAtCursor(mnCol, mnRow, mnTab, mePortion);
1079 }
1080};
1081
1082class FindByRange
1083{
1084 const ScRange& mrRange;
1085public:
1086 explicit FindByRange(const ScRange& rRange) : mrRange(rRange) {}
1087
1088 bool operator() (std::unique_ptr<ScDBData> const& p)
1089 {
1090 return p->IsDBAtArea(
1091 mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
1092 }
1093};
1094
1095class FindByIndex
1096{
1097 sal_uInt16 mnIndex;
1098public:
1099 explicit FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
1100 bool operator() (std::unique_ptr<ScDBData> const& p) const
1101 {
1102 return p->GetIndex() == mnIndex;
1103 }
1104};
1105
1106class FindByUpperName
1107{
1108 const OUString& mrName;
1109public:
1110 explicit FindByUpperName(const OUString& rName) : mrName(rName) {}
1111 bool operator() (std::unique_ptr<ScDBData> const& p) const
1112 {
1113 return p->GetUpperName() == mrName;
1114 }
1115};
1116
1117class FindByName
1118{
1119 const OUString& mrName;
1120public:
1121 explicit FindByName(const OUString& rName) : mrName(rName) {}
1122 bool operator() (std::unique_ptr<ScDBData> const& p) const
1123 {
1124 return p->GetName() == mrName;
1125 }
1126};
1127
1128class FindByPointer
1129{
1130 const ScDBData* mpDBData;
1131public:
1132 explicit FindByPointer(const ScDBData* pDBData) : mpDBData(pDBData) {}
1133 bool operator() (std::unique_ptr<ScDBData> const& p) const
1134 {
1135 return p.get() == mpDBData;
1136 }
1137};
1138
1139}
1140
1142{
1143 return mrDoc;
1144}
1145
1147{
1149}
1150
1152 ScDBDataContainerBase(rDoc), mrParent(rParent) {}
1153
1155 : ScDBDataContainerBase(r.mrDoc)
1156 , mrParent(rParent)
1157{
1158 for (auto const& it : r.m_DBs)
1159 {
1160 ScDBData* p = new ScDBData(*it);
1161 std::unique_ptr<ScDBData> pData(p);
1162 if (m_DBs.insert( std::move(pData)).second)
1163 initInserted(p);
1164 }
1165}
1166
1168{
1169}
1170
1172{
1173 p->SetContainer( this);
1174 if (mrDoc.IsClipOrUndo())
1175 return;
1176
1177 p->StartTableColumnNamesListener(); // needs the container be set already
1178 if (!p->AreTableColumnNamesDirty())
1179 return;
1180
1181 if (p->HasHeader())
1182 {
1183 // Refresh table column names in next round.
1184 maDirtyTableColumnNames.Join( p->GetHeaderArea());
1185 }
1186 else
1187 {
1188 // Header-less table can generate its column names
1189 // already without accessing the document.
1190 p->RefreshTableColumnNames( nullptr);
1191 }
1192}
1193
1195{
1196 return m_DBs.begin();
1197}
1198
1200{
1201 return m_DBs.end();
1202}
1203
1205{
1206 return m_DBs.begin();
1207}
1208
1210{
1211 return m_DBs.end();
1212}
1213
1215{
1216 DBsType::iterator itr = find_if(
1217 m_DBs.begin(), m_DBs.end(), FindByIndex(nIndex));
1218 return itr == m_DBs.end() ? nullptr : itr->get();
1219}
1220
1222{
1223 DBsType::iterator itr = find_if(
1224 m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1225 return itr == m_DBs.end() ? nullptr : itr->get();
1226}
1227
1229{
1230 return find_if(
1231 m_DBs.begin(), m_DBs.end(), FindByUpperName(rName));
1232}
1233
1235{
1236 DBsType::iterator itr = find_if(m_DBs.begin(), m_DBs.end(), FindByName(rName));
1237 return itr == m_DBs.end() ? nullptr : itr->get();
1238}
1239
1240bool ScDBCollection::NamedDBs::insert(std::unique_ptr<ScDBData> pData)
1241{
1242 auto p = pData.get();
1243 if (!pData->GetIndex())
1244 pData->SetIndex(mrParent.nEntryIndex++);
1245
1246 pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
1247
1248 if (r.second)
1249 {
1250 initInserted(p);
1251
1252 /* TODO: shouldn't the import refresh not be setup for
1253 * clipboard/undo documents? It was already like this before... */
1254 if (p->HasImportParam() && !p->HasImportSelection())
1255 {
1256 p->SetRefreshHandler(mrParent.GetRefreshHandler());
1257 p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
1258 }
1259 }
1260 return r.second;
1261}
1262
1264{
1265 return m_DBs.erase(itr);
1266}
1267
1269{
1270 return m_DBs.empty();
1271}
1272
1274{
1275 return m_DBs.size();
1276}
1277
1279{
1280 return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1281}
1282
1284{
1285 return m_DBs.begin();
1286}
1287
1289{
1290 return m_DBs.end();
1291}
1292
1294{
1295 return m_DBs.begin();
1296}
1297
1299{
1300 return m_DBs.end();
1301}
1302
1304 ScDBDataPortion ePortion) const
1305{
1306 DBsType::const_iterator itr = find_if(
1307 m_DBs.begin(), m_DBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1308 return itr == m_DBs.end() ? nullptr : itr->get();
1309}
1310
1312{
1313 DBsType::const_iterator itr = find_if(
1314 m_DBs.begin(), m_DBs.end(), FindByRange(rRange));
1315 return itr == m_DBs.end() ? nullptr : itr->get();
1316}
1317
1319{
1320 FindByTable func(nTab);
1321 m_DBs.erase(std::remove_if(m_DBs.begin(), m_DBs.end(), func), m_DBs.end());
1322}
1323
1325{
1326 const ScDBData* pData = findByRange(rRange);
1327 if (!pData)
1328 {
1329 // Insert a new db data. They all have identical names.
1330 ::std::unique_ptr<ScDBData> pNew(new ScDBData(
1331 STR_DB_GLOBAL_NONAME, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
1332 rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
1333 pData = pNew.get();
1334 m_DBs.push_back(std::move(pNew));
1335 }
1336 return const_cast<ScDBData*>(pData);
1337}
1338
1340{
1341 m_DBs.push_back(std::unique_ptr<ScDBData>(p));
1342}
1343
1345{
1346 return m_DBs.erase(itr);
1347}
1348
1350{
1351 return m_DBs.empty();
1352}
1353
1355{
1356 return any_of(m_DBs.begin(), m_DBs.end(), FindByPointer(p));
1357}
1358
1360{
1361 return ::comphelper::ContainerUniquePtrEquals(m_DBs, r.m_DBs);
1362}
1363
1365{
1366}
1367
1369{
1370 m_DBs.reserve(r.m_DBs.size());
1371 for (auto const& it : r.m_DBs)
1372 {
1373 m_DBs.push_back(std::make_unique<ScDBData>(*it));
1374 }
1375}
1376
1378 rDoc(rDocument), nEntryIndex(1), maNamedDBs(*this, rDocument) {}
1379
1381 rDoc(r.rDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs, *this), maAnonDBs(r.maAnonDBs) {}
1382
1384{
1385 // First, search the global named db ranges.
1386 NamedDBs::DBsType::const_iterator itr = find_if(
1387 maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1388 if (itr != maNamedDBs.end())
1389 return itr->get();
1390
1391 // Check for the sheet-local anonymous db range.
1392 const ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1393 if (pNoNameData)
1394 if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1395 return pNoNameData;
1396
1397 // Check the global anonymous db ranges.
1398 const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1399 if (pData)
1400 return pData;
1401
1402 // Do NOT check for the document global temporary anonymous db range here.
1403
1404 return nullptr;
1405}
1406
1408{
1409 // First, search the global named db ranges.
1410 NamedDBs::DBsType::iterator itr = find_if(
1411 maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, ePortion));
1412 if (itr != maNamedDBs.end())
1413 return itr->get();
1414
1415 // Check for the sheet-local anonymous db range.
1416 ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1417 if (pNoNameData)
1418 if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,ePortion))
1419 return pNoNameData;
1420
1421 // Check the global anonymous db ranges.
1422 const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, ePortion);
1423 if (pData)
1424 return const_cast<ScDBData*>(pData);
1425
1426 // Do NOT check for the document global temporary anonymous db range here.
1427
1428 return nullptr;
1429}
1430
1431const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
1432{
1433 // First, search the global named db ranges.
1434 ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1435 NamedDBs::DBsType::const_iterator itr = find_if(
1436 maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1437 if (itr != maNamedDBs.end())
1438 return itr->get();
1439
1440 // Check for the sheet-local anonymous db range.
1441 ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1442 if (pNoNameData)
1443 if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1444 return pNoNameData;
1445
1446 // Lastly, check the global anonymous db ranges.
1447 const ScDBData* pData = maAnonDBs.findByRange(aRange);
1448 if (pData)
1449 return pData;
1450
1451 // As a last resort, check for the document global temporary anonymous db range.
1452 pNoNameData = rDoc.GetAnonymousDBData();
1453 if (pNoNameData)
1454 if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1455 return pNoNameData;
1456
1457 return nullptr;
1458}
1459
1461{
1462 // First, search the global named db ranges.
1463 ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1464 NamedDBs::DBsType::iterator itr = find_if(
1465 maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
1466 if (itr != maNamedDBs.end())
1467 return itr->get();
1468
1469 // Check for the sheet-local anonymous db range.
1470 ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
1471 if (pNoNameData)
1472 if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1473 return pNoNameData;
1474
1475 // Lastly, check the global anonymous db ranges.
1476 const ScDBData* pData = getAnonDBs().findByRange(aRange);
1477 if (pData)
1478 return const_cast<ScDBData*>(pData);
1479
1480 // As a last resort, check for the document global temporary anonymous db range.
1481 pNoNameData = rDoc.GetAnonymousDBData();
1482 if (pNoNameData)
1483 if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
1484 return pNoNameData;
1485
1486 return nullptr;
1487}
1488
1490{
1491 for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
1492 {
1493 const ScRange & rRange = maNamedDBs.maDirtyTableColumnNames[i];
1494 for (auto const& it : maNamedDBs)
1495 {
1496 if (it->AreTableColumnNamesDirty())
1497 it->RefreshTableColumnNames( &maNamedDBs.mrDoc, rRange);
1498 }
1499 }
1501}
1502
1504{
1505 FindByTable func(nTab);
1506 // First, collect the positions of all items that need to be deleted.
1507 ::std::vector<NamedDBs::DBsType::iterator> v;
1508 {
1509 NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
1510 for (; itr != itrEnd; ++itr)
1511 {
1512 if (func(*itr))
1513 v.push_back(itr);
1514 }
1515 }
1516
1517 // Delete them all.
1518 for (const auto& rIter : v)
1519 maNamedDBs.erase(rIter);
1520
1521 maAnonDBs.deleteOnTab(nTab);
1522}
1523
1525 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1526 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1527 SCCOL nDx, SCROW nDy, SCTAB nDz )
1528{
1530 if (pData)
1531 {
1532 if (nTab1 == nTab2 && nDz == 0)
1533 {
1534 // Delete the database range, if some part of the reference became invalid.
1535 if (pData->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1536 nTab2, nDx, nDy, nDz))
1537 rDoc.SetAnonymousDBData(nTab1, nullptr);
1538 }
1539 else
1540 {
1541 //this will perhaps break undo
1542 }
1543 }
1544
1545 for (auto it = maNamedDBs.begin(); it != maNamedDBs.end(); )
1546 {
1547 // Delete the database range, if some part of the reference became invalid.
1548 if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1549 nTab2, nDx, nDy, nDz))
1550 it = maNamedDBs.erase(it);
1551 else
1552 ++it;
1553 }
1554 for (auto it = maAnonDBs.begin(); it != maAnonDBs.end(); )
1555 {
1556 // Delete the database range, if some part of the reference became invalid.
1557 if (it->get()->UpdateReference(&rDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2,
1558 nTab2, nDx, nDy, nDz))
1559 it = maAnonDBs.erase(it);
1560 else
1561 ++it;
1562 }
1563}
1564
1566{
1567 UpdateMoveTabFunc func(nOldPos, nNewPos);
1568 for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
1569 for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
1570}
1571
1573{
1574 // Create temporary copy of pointers to not insert in a set we are
1575 // iterating over.
1576 std::vector<const ScDBData*> aTemp;
1577 aTemp.reserve( maNamedDBs.size());
1578 for (const auto& rxNamedDB : maNamedDBs)
1579 {
1580 if (rxNamedDB->GetTab() != nOldPos)
1581 continue;
1582 aTemp.emplace_back( rxNamedDB.get());
1583 }
1584 for (const auto& rxNamedDB : aTemp)
1585 {
1586 const OUString newName( lcl_IncrementNumberInNamedRange( maNamedDBs, rxNamedDB->GetName()));
1587 std::unique_ptr<ScDBData> pDataCopy = std::make_unique<ScDBData>(newName, *rxNamedDB);
1588 pDataCopy->UpdateMoveTab(nOldPos, nNewPos);
1589 pDataCopy->SetIndex(0);
1590 maNamedDBs.insert(std::move(pDataCopy));
1591 }
1592}
1593
1595{
1596 ScDBData* pNearData = nullptr;
1597 for (const auto& rxNamedDB : maNamedDBs)
1598 {
1599 SCTAB nAreaTab;
1600 SCCOL nStartCol, nEndCol;
1601 SCROW nStartRow, nEndRow;
1602 rxNamedDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1603 if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
1604 nRow+1 >= nStartRow && nRow <= nEndRow+1 )
1605 {
1606 if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
1607 {
1608 if (!pNearData)
1609 pNearData = rxNamedDB.get(); // remember first adjacent area
1610 }
1611 else
1612 return rxNamedDB.get(); // not "unbenannt"/"unnamed" and cursor within
1613 }
1614 }
1615 if (pNearData)
1616 return pNearData; // adjacent, if no direct hit
1617 return rDoc.GetAnonymousDBData(nTab); // "unbenannt"/"unnamed" only if nothing else
1618}
1619
1620std::vector<ScDBData*> ScDBCollection::GetAllDBsFromTab(SCTAB nTab)
1621{
1622 std::vector<ScDBData*> pTabData;
1623 for (const auto& rxNamedDB : maNamedDBs)
1624 {
1625 if (rxNamedDB->GetTab() == nTab)
1626 pTabData.emplace_back(rxNamedDB.get());
1627 }
1628 auto pAnonDBData = rDoc.GetAnonymousDBData(nTab);
1629 if (pAnonDBData)
1630 pTabData.emplace_back(pAnonDBData);
1631 return pTabData;
1632}
1633
1635{
1636 return maNamedDBs.empty() && maAnonDBs.empty();
1637}
1638
1640{
1641 return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
1643}
1644
1645/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
int mnIndex
const SCSIZE SCSIZE_MAX
Definition: address.hxx:59
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
BaseContainerNodeSharedPtr & mrParent
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
SCTAB Tab() const
Definition: address.hxx:283
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
@ INITIALIZE_INVALID
Definition: address.hxx:221
SCCOL Col() const
Definition: address.hxx:279
Stores global anonymous database ranges.
Definition: dbdata.hxx:285
const ScDBData * findAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1303
bool has(const ScDBData *p) const
Definition: dbdata.cxx:1354
void insert(ScDBData *p)
Definition: dbdata.cxx:1339
ScDBData * getByRange(const ScRange &rRange)
Definition: dbdata.cxx:1324
iterator erase(const iterator &itr)
Definition: dbdata.cxx:1344
void deleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1318
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:296
DBsType::iterator iterator
Definition: dbdata.hxx:295
bool operator==(const AnonDBs &r) const
Definition: dbdata.cxx:1359
bool empty() const
Definition: dbdata.cxx:1349
const ScDBData * findByRange(const ScRange &rRange) const
Definition: dbdata.cxx:1311
Stores global named database ranges.
Definition: dbdata.hxx:243
DBsType::const_iterator const_iterator
Definition: dbdata.hxx:258
NamedDBs(ScDBCollection &rParent, ScDocument &rDoc)
Definition: dbdata.cxx:1151
iterator erase(const iterator &itr)
Definition: dbdata.cxx:1263
void initInserted(ScDBData *p)
Definition: dbdata.cxx:1171
bool insert(std::unique_ptr< ScDBData > p)
Takes ownership of p and attempts to insert it into the collection.
Definition: dbdata.cxx:1240
bool operator==(const NamedDBs &r) const
Definition: dbdata.cxx:1278
ScDBData * findByName(const OUString &rName)
Definition: dbdata.cxx:1234
ScDBData * findByIndex(sal_uInt16 nIndex)
Definition: dbdata.cxx:1214
iterator findByUpperName2(const OUString &rName)
Definition: dbdata.cxx:1228
virtual ~NamedDBs() override
Definition: dbdata.cxx:1167
size_t size() const
Definition: dbdata.cxx:1273
DBsType::iterator iterator
Definition: dbdata.hxx:257
ScDBData * findByUpperName(const OUString &rName)
Definition: dbdata.cxx:1221
void CopyToTable(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:1572
ScDBData * GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dbdata.cxx:1594
AnonDBs maAnonDBs
Definition: dbdata.hxx:318
Link< Timer *, void > aRefreshHandler
Definition: dbdata.hxx:314
NamedDBs maNamedDBs
Definition: dbdata.hxx:317
void DeleteOnTab(SCTAB nTab)
Definition: dbdata.cxx:1503
const ScDBData * GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:1431
void RefreshDirtyTableColumnNames()
Definition: dbdata.cxx:1489
std::vector< ScDBData * > GetAllDBsFromTab(SCTAB nTab)
Definition: dbdata.cxx:1620
const ScDBData * GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:1383
bool operator==(const ScDBCollection &r) const
Definition: dbdata.cxx:1639
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:1565
bool empty() const
Definition: dbdata.cxx:1634
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:1524
sal_uInt16 nEntryIndex
counter for unique indices
Definition: dbdata.hxx:316
AnonDBs & getAnonDBs()
Definition: dbdata.hxx:327
ScDBCollection(ScDocument &rDocument)
Definition: dbdata.cxx:1377
ScDocument & rDoc
Definition: dbdata.hxx:315
Container base class to provide selected access for ScDBData.
Definition: dbdata.hxx:53
ScDocument & mrDoc
Definition: dbdata.hxx:61
ScRangeList & GetDirtyTableColumnNames()
Definition: dbdata.cxx:1146
ScRangeList maDirtyTableColumnNames
Definition: dbdata.hxx:62
ScDocument & GetDocument() const
Definition: dbdata.cxx:1141
std::unique_ptr< ScSortParam > mpSortParam
Definition: dbdata.hxx:68
void GetImportParam(ScImportParam &rImportParam) const
Definition: dbdata.cxx:480
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:916
bool HasAutoFilter() const
Definition: dbdata.hxx:212
SC_DLLPUBLIC void SetTableColumnAttributes(::std::vector< TableColumnAttributes > &&rAttributes)
Definition: dbdata.cxx:689
bool HasHeader() const
Definition: dbdata.hxx:136
void MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCCOL nUpdateCol=-1)
Definition: dbdata.cxx:344
SC_DLLPUBLIC bool HasQueryParam() const
Definition: dbdata.cxx:524
ScRange GetHeaderArea() const
Returns header row range if has headers, else invalid range.
Definition: dbdata.cxx:315
bool IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:512
std::unique_ptr< ScImportParam > mpImportParam
Definition: dbdata.hxx:71
bool bModified
is set/cleared for/by(?) UpdateReference
Definition: dbdata.hxx:98
SCROW nEndRow
Definition: dbdata.hxx:82
void GetFilterSelCount(SCSIZE &nSelected, SCSIZE &nTotal)
Definition: dbdata.cxx:981
SCCOL nEndCol
Definition: dbdata.hxx:81
void InvalidateTableColumnNames(bool bSwapToEmptyNames)
Definition: dbdata.cxx:750
void AdjustTableColumnAttributes(UpdateRefMode eUpdateRefMode, SCCOL nDx, SCCOL nCol1, SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2)
Definition: dbdata.cxx:694
sal_Int32 GetColumnNameOffset(const OUString &rName) const
Finds the column named rName and returns the corresponding offset within the table.
Definition: dbdata.cxx:903
SC_DLLPUBLIC void RefreshTableColumnNames(ScDocument *pDoc)
Refresh/update the column names with the header row's cell contents.
Definition: dbdata.cxx:814
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:300
SC_DLLPUBLIC void SetTableColumnNames(::std::vector< OUString > &&rNames)
Definition: dbdata.cxx:683
bool bByRow
Definition: dbdata.hxx:83
SC_DLLPUBLIC bool GetAdvancedQuerySource(ScRange &rSource) const
Definition: dbdata.cxx:457
bool UpdateReference(const ScDocument *pDoc, UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: dbdata.cxx:588
void CalcSaveFilteredCount(SCSIZE nNonFilteredRowCount)
Definition: dbdata.cxx:973
bool IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:496
bool operator==(const ScDBData &rData) const
Definition: dbdata.cxx:211
bool bDBSelection
not in Param: if selection, block update
Definition: dbdata.hxx:94
void SetSubTotalParam(const ScSubTotalParam &rSubTotalParam)
Definition: dbdata.cxx:475
const OUString aName
DBParam.
Definition: dbdata.hxx:76
ScRange aAdvSource
source range
Definition: dbdata.hxx:92
bool bAutoFilter
AutoFilter? (not saved)
Definition: dbdata.hxx:97
void EndTableColumnNamesListener()
Definition: dbdata.cxx:678
bool bHasHeader
Definition: dbdata.hxx:84
virtual SC_DLLPUBLIC ~ScDBData() override
Definition: dbdata.cxx:253
void SetImportParam(const ScImportParam &rImportParam)
Definition: dbdata.cxx:490
SC_DLLPUBLIC void SetAdvancedQuerySource(const ScRange *pSource)
Definition: dbdata.cxx:446
SCTAB nTable
Definition: dbdata.hxx:78
bool HasSubTotalParam() const
Definition: dbdata.cxx:542
SCROW nStartRow
Definition: dbdata.hxx:80
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:401
virtual void Notify(const SfxHint &rHint) override
Definition: dbdata.cxx:928
void StartTableColumnNamesListener()
Definition: dbdata.cxx:668
bool HasSortParam() const
Definition: dbdata.cxx:535
std::unique_ptr< ScSubTotalParam > mpSubTotal
Definition: dbdata.hxx:70
void SetModified(bool bMod)
Definition: dbdata.hxx:216
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:413
bool bIsAdvanced
QueryParam.
Definition: dbdata.hxx:91
void UpdateFromSortParam(const ScSortParam &rSortParam)
Remember some more settings of ScSortParam, only to be called at anonymous DB ranges as it at least o...
Definition: dbdata.cxx:419
std::unique_ptr< ScQueryParam > mpQueryParam
Definition: dbdata.hxx:69
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:547
bool mbTableColumnNamesDirty
Definition: dbdata.hxx:102
OUString GetOperations() const
Definition: dbdata.cxx:270
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:424
SCCOL nStartCol
Definition: dbdata.hxx:79
bool bKeepFmt
Definition: dbdata.hxx:87
::std::vector< TableColumnAttributes > maTableColumnAttributes
attributes of table columns
Definition: dbdata.hxx:101
bool bHasTotals
Definition: dbdata.hxx:85
sal_uInt16 nIndex
unique index formulas
Definition: dbdata.hxx:96
ScDBData & operator=(const ScDBData &rData)
Definition: dbdata.cxx:159
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:437
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:73
SCSIZE nFilteredRowCount
Definition: dbdata.hxx:103
bool HasImportParam() const
Definition: dbdata.cxx:519
::std::vector< OUString > maTableColumnNames
names of table columns
Definition: dbdata.hxx:100
bool bStripData
Definition: dbdata.hxx:88
void ExtendDataArea(const ScDocument &rDoc)
Definition: dbdata.cxx:649
void GetSubTotalParam(ScSubTotalParam &rSubTotalParam) const
Definition: dbdata.cxx:463
OUString GetSourceString() const
Definition: dbdata.cxx:258
bool bDoSize
Definition: dbdata.hxx:86
void SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dbdata.cxx:322
OUString aUpper
Definition: dbdata.hxx:77
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
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
bool IsClipOrUndo() const
Definition: document.hxx:1590
SC_DLLPUBLIC ScDBData * GetAnonymousDBData(SCTAB nTab)
Definition: document.cxx:310
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:1100
SC_DLLPUBLIC void SetAnonymousDBData(SCTAB nTab, std::unique_ptr< ScDBData > pDBData)
Definition: document.cxx:322
static SC_DLLPUBLIC ::utl::TransliterationWrapper & GetTransliteration()
Definition: global.cxx:1024
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1062
SCROW GetRowCount() const
Definition: brdcst.hxx:32
const ScAddress & GetStartAddress() const
Definition: brdcst.hxx:31
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:1092
void RemoveAll()
Definition: rangelst.cxx:1101
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
size_t size() const
Definition: rangelst.hxx:89
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
ScAddress aEnd
Definition: address.hxx:498
bool Contains(const ScAddress &) const
is Address& fully in Range?
Definition: address.hxx:718
bool IsValid() const
Definition: address.hxx:544
ScAddress aStart
Definition: address.hxx:497
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
void StopRefreshTimer()
ScRefreshTimer & operator=(const ScRefreshTimer &r)
SfxHintId GetId() const
void EndListeningAll()
sal_Int32 compareString(const OUString &rStr1, const OUString &rStr2) const
bool isEqual(const OUString &rStr1, const OUString &rStr2) const
int nCount
ScDBDataPortion
Enum used to indicate which portion of the DBArea is to be considered.
Definition: dbdata.hxx:41
@ AREA
entire area
@ TOP_LEFT
top left cell of area
sal_Int32 mnRow
sal_Int32 mnCol
OString right
float v
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:82
UpdateRefMode
Definition: global.hxx:300
@ URM_INSDEL
Definition: global.hxx:301
constexpr OUStringLiteral STR_DB_GLOBAL_NONAME
Definition: globalnames.hxx:15
sal_Int32 nIndex
OUString aName
void * p
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
aStr
aBuf
std::unique_ptr< sal_Int32[]> pData
OUString newName(std::u16string_view aNewPrefix, std::u16string_view aOldPrefix, std::u16string_view old_Name)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
long Long
ScRefUpdateRes
Definition: refupdat.hxx:30
@ UR_INVALID
Some part of the reference became invalid.
Definition: refupdat.hxx:33
@ UR_NOTHING
Reference not affected, no change at all.
Definition: refupdat.hxx:31
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
bool operator()(const std::unique_ptr< ScDBData > &left, const std::unique_ptr< ScDBData > &right) const
Definition: dbdata.cxx:51
SCROW nRow1
Definition: global.hxx:441
SCCOL nCol1
Definition: global.hxx:440
SCCOL nCol2
Definition: global.hxx:442
SCROW nRow2
Definition: global.hxx:443
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:34
SCCOLROW nField
Definition: queryentry.hxx:61
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:657
bool hasString() const
Definition: cellvalue.cxx:614
bool bHasHeader
Definition: sortparam.hxx:111
SCCOL nCol1
selected area
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
sal_uInt64 left