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 maTableColumnAttributes(rData.maTableColumnAttributes),
120 mbTableColumnNamesDirty(rData.mbTableColumnNamesDirty),
121 nFilteredRowCount (rData.nFilteredRowCount)
122{
123}
124
125ScDBData::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 maTableColumnAttributes(rData.maTableColumnAttributes),
155 mbTableColumnNamesDirty (rData.mbTableColumnNamesDirty),
156 nFilteredRowCount (rData.nFilteredRowCount)
157{
159}
160
162{
163 if (this != &rData)
164 {
165 // Don't modify the name. The name is not mutable as it is used as a key
166 // in the container to keep the db ranges sorted by the name.
167
168 bool bHeaderRangeDiffers = (nTable != rData.nTable || nStartCol != rData.nStartCol ||
169 nEndCol != rData.nEndCol || nStartRow != rData.nStartRow);
170 bool bNeedsListening = ((bHasHeader && bHeaderRangeDiffers) || (!bHasHeader && rData.bHasHeader));
171 if (bHasHeader && (!rData.bHasHeader || bHeaderRangeDiffers))
172 {
174 }
176 mpSortParam.reset(new ScSortParam(*rData.mpSortParam));
177 mpQueryParam.reset(new ScQueryParam(*rData.mpQueryParam));
178 mpSubTotal.reset(new ScSubTotalParam(*rData.mpSubTotal));
179 mpImportParam.reset(new ScImportParam(*rData.mpImportParam));
180 // Keep mpContainer.
181 nTable = rData.nTable;
182 nStartCol = rData.nStartCol;
183 nStartRow = rData.nStartRow;
184 nEndCol = rData.nEndCol;
185 nEndRow = rData.nEndRow;
186 bByRow = rData.bByRow;
187 bHasHeader = rData.bHasHeader;
188 bHasTotals = rData.bHasTotals;
189 bDoSize = rData.bDoSize;
190 bKeepFmt = rData.bKeepFmt;
191 bStripData = rData.bStripData;
192 bIsAdvanced = rData.bIsAdvanced;
193 aAdvSource = rData.aAdvSource;
195 nIndex = rData.nIndex;
196 bAutoFilter = rData.bAutoFilter;
198
199 if (bHeaderRangeDiffers)
201 else
202 {
206 }
207
208 if (bNeedsListening)
210 }
211 return *this;
212}
213
214bool ScDBData::operator== (const ScDBData& rData) const
215{
216 // Data that is not in sort or query params.
217
218 if ( nTable != rData.nTable ||
219 bDoSize != rData.bDoSize ||
220 bKeepFmt != rData.bKeepFmt ||
221 bIsAdvanced!= rData.bIsAdvanced||
222 bStripData != rData.bStripData ||
223// SAB: I think this should be here, but I don't want to break something
224// bAutoFilter!= rData.bAutoFilter||
225 ScRefreshTimer::operator!=( rData )
226 )
227 return false;
228
229 if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
230 return false;
231
232 ScSortParam aSort1, aSort2;
233 GetSortParam(aSort1);
234 rData.GetSortParam(aSort2);
235 if (!(aSort1 == aSort2))
236 return false;
237
238 ScQueryParam aQuery1, aQuery2;
239 GetQueryParam(aQuery1);
240 rData.GetQueryParam(aQuery2);
241 if (!(aQuery1 == aQuery2))
242 return false;
243
244 ScSubTotalParam aSubTotal1, aSubTotal2;
245 GetSubTotalParam(aSubTotal1);
246 rData.GetSubTotalParam(aSubTotal2);
247 if (!(aSubTotal1 == aSubTotal2))
248 return false;
249
250 ScImportParam aImport1, aImport2;
251 GetImportParam(aImport1);
252 rData.GetImportParam(aImport2);
253 return aImport1 == aImport2;
254}
255
257{
259}
260
262{
263 if (mpImportParam->bImport)
264 return mpImportParam->aDBName + "/" + mpImportParam->aStatement;
265 return OUString();
266}
267
269{
270 OUStringBuffer aBuf;
271 if (mpQueryParam->GetEntryCount())
272 {
273 const ScQueryEntry& rEntry = mpQueryParam->GetEntry(0);
274 if (rEntry.bDoQuery)
275 aBuf.append(ScResId(STR_OPERATION_FILTER));
276 }
277
278 if (mpSortParam->maKeyState[0].bDoSort)
279 {
280 if (!aBuf.isEmpty())
281 aBuf.append(", ");
282 aBuf.append(ScResId(STR_OPERATION_SORT));
283 }
284
285 if (mpSubTotal->bGroupActive[0] && !mpSubTotal->bRemoveOnly)
286 {
287 if (!aBuf.isEmpty())
288 aBuf.append(", ");
289 aBuf.append(ScResId(STR_OPERATION_SUBTOTAL));
290 }
291
292 if (aBuf.isEmpty())
293 aBuf.append(ScResId(STR_OPERATION_NONE));
294
295 return aBuf.makeStringAndClear();
296}
297
298void ScDBData::GetArea(SCTAB& rTab, SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2) const
299{
300 rTab = nTable;
301 rCol1 = nStartCol;
302 rRow1 = nStartRow;
303 rCol2 = nEndCol;
304 rRow2 = nEndRow;
305}
306
307void ScDBData::GetArea(ScRange& rRange) const
308{
309 SCROW nNewEndRow = nEndRow;
310 rRange = ScRange( nStartCol, nStartRow, nTable, nEndCol, nNewEndRow, nTable );
311}
312
314{
315 if (HasHeader())
318}
319
320void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
321{
322 bool bHeaderRangeChange = (nTab != nTable || nCol1 != nStartCol || nCol2 != nEndCol || nRow1 != nStartRow);
323 if (bHeaderRangeChange)
325
326 nTable = nTab;
327 nStartCol = nCol1;
328 nStartRow = nRow1;
329 nEndCol = nCol2;
330 nEndRow = nRow2;
331
332 if (bHeaderRangeChange)
333 {
334 SAL_WARN_IF( !maTableColumnNames.empty(), "sc.core", "ScDBData::SetArea - invalidating column names/offsets");
335 // Invalidate *after* new area has been set above to add the proper
336 // header range to dirty list.
339 }
340}
341
342void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
343 SCCOL nUpdateCol)
344{
345 tools::Long nDifX = static_cast<tools::Long>(nCol1) - static_cast<tools::Long>(nStartCol);
346 tools::Long nDifY = static_cast<tools::Long>(nRow1) - static_cast<tools::Long>(nStartRow);
347
348 tools::Long nSortDif = bByRow ? nDifX : nDifY;
349 tools::Long nSortEnd = bByRow ? static_cast<tools::Long>(nCol2) : static_cast<tools::Long>(nRow2);
350
351 for (sal_uInt16 i=0; i<mpSortParam->GetSortKeyCount(); i++)
352 {
353 mpSortParam->maKeyState[i].nField += nSortDif;
354 if (mpSortParam->maKeyState[i].nField > nSortEnd)
355 {
356 mpSortParam->maKeyState[i].nField = 0;
357 mpSortParam->maKeyState[i].bDoSort = false;
358 }
359 }
360
361 SCSIZE nCount = mpQueryParam->GetEntryCount();
362 for (SCSIZE i = 0; i < nCount; ++i)
363 {
364 ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
365 rEntry.nField += nDifX;
366
367 // tdf#48025, tdf#141946: update the column index of the filter criteria,
368 // when the deleted/inserted columns are inside the data range
369 if (nUpdateCol != -1)
370 {
371 nUpdateCol += nDifX;
372 tools::Long nDifX2
373 = static_cast<tools::Long>(nCol2) - static_cast<tools::Long>(nEndCol);
374 if (rEntry.nField >= nUpdateCol)
375 rEntry.nField += nDifX2;
376 else if (rEntry.nField >= nUpdateCol + nDifX2)
377 rEntry.Clear();
378 }
379
380 if (rEntry.nField > nCol2)
381 {
382 rEntry.nField = 0;
383 rEntry.bDoQuery = false;
384 }
385 }
386 for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
387 {
388 mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
389 if (mpSubTotal->nField[i] > nCol2)
390 {
391 mpSubTotal->nField[i] = 0;
392 mpSubTotal->bGroupActive[i] = false;
393 }
394 }
395
396 SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
397}
398
399void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
400{
401 rSortParam = *mpSortParam;
402 rSortParam.nCol1 = nStartCol;
403 rSortParam.nRow1 = nStartRow;
404 rSortParam.nCol2 = nEndCol;
405 rSortParam.nRow2 = nEndRow;
406 rSortParam.bByRow = bByRow;
407 rSortParam.bHasHeader = bHasHeader;
408 /* TODO: add Totals to ScSortParam? */
409}
410
411void ScDBData::SetSortParam( const ScSortParam& rSortParam )
412{
413 mpSortParam.reset(new ScSortParam(rSortParam));
414 bByRow = rSortParam.bByRow;
415}
416
418{
419 bHasHeader = rSortParam.bHasHeader;
420}
421
422void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
423{
424 rQueryParam = *mpQueryParam;
425 rQueryParam.nCol1 = nStartCol;
426 rQueryParam.nRow1 = nStartRow;
427 rQueryParam.nCol2 = nEndCol;
428 rQueryParam.nRow2 = nEndRow;
429 rQueryParam.nTab = nTable;
430 rQueryParam.bByRow = bByRow;
431 rQueryParam.bHasHeader = bHasHeader;
432 /* TODO: add Totals to ScQueryParam? */
433}
434
435void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
436{
437 mpQueryParam.reset(new ScQueryParam(rQueryParam));
438
439 // set bIsAdvanced to false for everything that is not from the
440 // advanced filter dialog
441 bIsAdvanced = false;
442}
443
445{
446 if (pSource)
447 {
448 aAdvSource = *pSource;
449 bIsAdvanced = true;
450 }
451 else
452 bIsAdvanced = false;
453}
454
456{
457 rSource = aAdvSource;
458 return bIsAdvanced;
459}
460
462{
463 rSubTotalParam = *mpSubTotal;
464
465 // Share the data range with the parent db data. The range in the subtotal
466 // param struct is not used.
467 rSubTotalParam.nCol1 = nStartCol;
468 rSubTotalParam.nRow1 = nStartRow;
469 rSubTotalParam.nCol2 = nEndCol;
470 rSubTotalParam.nRow2 = nEndRow;
471}
472
474{
475 mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
476}
477
479{
480 rImportParam = *mpImportParam;
481 // set the range.
482 rImportParam.nCol1 = nStartCol;
483 rImportParam.nRow1 = nStartRow;
484 rImportParam.nCol2 = nEndCol;
485 rImportParam.nRow2 = nEndRow;
486}
487
489{
490 // the range is ignored.
491 mpImportParam.reset(new ScImportParam(rImportParam));
492}
493
494bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
495{
496 if (nTab == nTable)
497 {
498 switch (ePortion)
499 {
501 return nCol == nStartCol && nRow == nStartRow;
503 return nCol >= nStartCol && nCol <= nEndCol && nRow >= nStartRow && nRow <= nEndRow;
504 }
505 }
506
507 return false;
508}
509
510bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
511{
512 return (nTab == nTable)
513 && (nCol1 == nStartCol) && (nRow1 == nStartRow)
514 && (nCol2 == nEndCol) && (nRow2 == nEndRow);
515}
516
518{
519 return mpImportParam && mpImportParam->bImport;
520}
521
523{
524 if (!mpQueryParam)
525 return false;
526
527 if (!mpQueryParam->GetEntryCount())
528 return false;
529
530 return mpQueryParam->GetEntry(0).bDoQuery;
531}
532
534{
535 return mpSortParam &&
536 !mpSortParam->maKeyState.empty() &&
537 mpSortParam->maKeyState[0].bDoSort;
538}
539
541{
542 return mpSubTotal && mpSubTotal->bGroupActive[0];
543}
544
545void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
546{
547 ScRange aRange;
548 GetArea(aRange);
549 SCTAB nTab = aRange.aStart.Tab(); // a database range is only on one sheet
550
551 // customize as the current table as ScTablesHint (tabvwsh5.cxx)
552
553 if (nTab == nOldPos) // moved sheet
554 nTab = nNewPos;
555 else if (nOldPos < nNewPos) // moved to the back
556 {
557 if (nTab > nOldPos && nTab <= nNewPos) // move this sheet
558 --nTab;
559 }
560 else // moved to the front
561 {
562 if (nTab >= nNewPos && nTab < nOldPos) // move this sheet
563 ++nTab;
564 }
565
566 bool bChanged = (nTab != aRange.aStart.Tab());
567 if (bChanged)
568 {
569 // SetArea() invalidates column names, but it is the same column range
570 // just on a different sheet; remember and set new.
571 ::std::vector<OUString> aNames(maTableColumnNames);
572 bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
573 // Same column range.
574 SetArea(nTab, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(),
575 aRange.aEnd.Row());
576 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
577 maTableColumnNames = aNames;
578 maTableColumnAttributes.resize(aNames.size());
579 mbTableColumnNamesDirty = bTableColumnNamesDirty;
580 }
581
582 // MoveTo() is not necessary if only the sheet changed.
583
584 SetModified(bChanged);
585}
586
587bool ScDBData::UpdateReference(const ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
588 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
589 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
590 SCCOL nDx, SCROW nDy, SCTAB nDz)
591{
592 SCCOL theCol1;
593 SCROW theRow1;
594 SCTAB theTab1;
595 SCCOL theCol2;
596 SCROW theRow2;
597 SCTAB theTab2;
598 GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
599 theTab2 = theTab1;
600 SCCOL nOldCol1 = theCol1, nOldCol2 = theCol2;
601
602 ScRefUpdateRes eRet
603 = ScRefUpdate::Update(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx,
604 nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
605
606 bool bDoUpdate = eRet != UR_NOTHING;
607
608 if (bDoUpdate && eRet != UR_INVALID)
609 {
610 // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
611 AdjustTableColumnAttributes( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
612 ::std::vector<OUString> aNames( maTableColumnNames);
613 bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
614 // tdf#48025, tdf#141946: update the column index of the filter criteria,
615 // when the deleted/inserted columns are inside the data range
616 if (HasAutoFilter() && theCol1 - nOldCol1 != theCol2 - nOldCol2)
617 MoveTo(theTab1, theCol1, theRow1, theCol2, theRow2, nCol1);
618 else
619 MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
620 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
621 maTableColumnNames = aNames;
622 maTableColumnAttributes.resize(aNames.size());
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);
724 // Copy head.
725 for (size_t i = 0; i < nHead; ++i)
726 {
727 aNewNames[i] = maTableColumnNames[i];
728 aNewAttributes[i] = maTableColumnAttributes[i];
729 }
730 // Copy tail, inserted middle range, if any, stays empty.
731 for (size_t i = n - nTail, j = maTableColumnNames.size() - nTail; i < n; ++i, ++j)
732 {
733 aNewNames[i] = maTableColumnNames[j];
734 aNewAttributes[i] = maTableColumnAttributes[j];
735 }
736 }
737 } // else empty aNewNames invalidates names/offsets
738
739 SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
740 "sc.core", "ScDBData::AdjustTableColumnAttributes - invalidating column attributes/offsets");
741 aNewNames.swap( maTableColumnNames);
742 aNewAttributes.swap(maTableColumnAttributes);
743 if (maTableColumnNames.empty())
746 InvalidateTableColumnNames( false); // preserve new column names array
747}
748
749void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames )
750{
752 if (bSwapToEmptyNames && !maTableColumnNames.empty())
753 ::std::vector<OUString>().swap( maTableColumnNames);
754 if (mpContainer)
755 {
756 // Add header range to dirty list.
757 if (HasHeader())
759 else
760 {
761 // We need *some* range in the dirty list even without header area,
762 // otherwise the container would not attempt to call a refresh.
764 }
765 }
766}
767
768namespace {
769class TableColumnNameSearch
770{
771public:
772 explicit TableColumnNameSearch( OUString aSearchName ) :
773 maSearchName(std::move( aSearchName ))
774 {
775 }
776
777 bool operator()( const OUString& rName ) const
778 {
779 return ScGlobal::GetTransliteration().isEqual( maSearchName, rName);
780 }
781
782private:
783 OUString maSearchName;
784};
785
790void SetTableColumnName( ::std::vector<OUString>& rVec, size_t nIndex, const OUString& rName, size_t nCount )
791{
792 OUString aStr;
793 do
794 {
795 if (nCount)
796 aStr = rName + OUString::number( nCount);
797 else
798 {
799 aStr = rName;
800 ++nCount;
801 }
802
803 if (std::none_of( rVec.begin(), rVec.end(), TableColumnNameSearch( aStr)))
804 {
805 rVec[nIndex] = aStr;
806 break; // do while
807 }
808 ++nCount;
809 } while(true);
810}
811}
812
814{
815 ::std::vector<OUString> aNewNames;
816 aNewNames.resize( nEndCol - nStartCol + 1);
817 bool bHaveEmpty = false;
818 if (!HasHeader() || !pDoc)
819 bHaveEmpty = true; // Assume we have empty ones and fill below.
820 else
821 {
822 ScHorizontalCellIterator aIter(*pDoc, nTable, nStartCol, nStartRow, nEndCol, nStartRow); // header row only
823 ScRefCellValue* pCell;
824 SCCOL nCol, nLastColFilled = nStartCol - 1;
825 SCROW nRow;
826 while ((pCell = aIter.GetNext( nCol, nRow)) != nullptr)
827 {
828 if (pCell->hasString())
829 {
830 const OUString& rStr = pCell->getString( pDoc);
831 if (rStr.isEmpty())
832 bHaveEmpty = true;
833 else
834 {
835 SetTableColumnName( aNewNames, nCol-nStartCol, rStr, 0);
836 if (nLastColFilled < nCol-1)
837 bHaveEmpty = true;
838 }
839 nLastColFilled = nCol;
840 }
841 else
842 bHaveEmpty = true;
843 }
844 }
845
846 // Never leave us with empty names, try to remember previous name that
847 // might had been used to compile formulas, but only if same number of
848 // columns and no duplicates.
849 if (bHaveEmpty && aNewNames.size() == maTableColumnNames.size())
850 {
851 bHaveEmpty = false;
852 for (size_t i=0, n=aNewNames.size(); i < n; ++i)
853 {
854 if (aNewNames[i].isEmpty())
855 {
856 const OUString& rStr = maTableColumnNames[i];
857 if (rStr.isEmpty())
858 bHaveEmpty = true;
859 else
860 SetTableColumnName( aNewNames, i, rStr, 0);
861 }
862 }
863 }
864
865 // If we still have empty ones then fill those with "Column#" with #
866 // starting at the column offset number. Still no duplicates of course.
867 if (bHaveEmpty)
868 {
869 OUString aColumn( ScResId(STR_COLUMN));
870 for (size_t i=0, n=aNewNames.size(); i < n; ++i)
871 {
872 if (aNewNames[i].isEmpty())
873 SetTableColumnName( aNewNames, i, aColumn, i+1);
874 }
875 }
876
877 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: */
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:478
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:342
SC_DLLPUBLIC bool HasQueryParam() const
Definition: dbdata.cxx:522
ScRange GetHeaderArea() const
Returns header row range if has headers, else invalid range.
Definition: dbdata.cxx:313
bool IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: dbdata.cxx:510
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:749
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:813
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:298
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:455
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:587
void CalcSaveFilteredCount(SCSIZE nNonFilteredRowCount)
Definition: dbdata.cxx:973
bool IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: dbdata.cxx:494
bool operator==(const ScDBData &rData) const
Definition: dbdata.cxx:214
bool bDBSelection
not in Param: if selection, block update
Definition: dbdata.hxx:94
void SetSubTotalParam(const ScSubTotalParam &rSubTotalParam)
Definition: dbdata.cxx:473
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:256
void SetImportParam(const ScImportParam &rImportParam)
Definition: dbdata.cxx:488
SC_DLLPUBLIC void SetAdvancedQuerySource(const ScRange *pSource)
Definition: dbdata.cxx:444
SCTAB nTable
Definition: dbdata.hxx:78
bool HasSubTotalParam() const
Definition: dbdata.cxx:540
SCROW nStartRow
Definition: dbdata.hxx:80
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:399
virtual void Notify(const SfxHint &rHint) override
Definition: dbdata.cxx:928
void StartTableColumnNamesListener()
Definition: dbdata.cxx:668
bool HasSortParam() const
Definition: dbdata.cxx:533
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:411
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:417
std::unique_ptr< ScQueryParam > mpQueryParam
Definition: dbdata.hxx:69
void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
Definition: dbdata.cxx:545
bool mbTableColumnNamesDirty
Definition: dbdata.hxx:102
OUString GetOperations() const
Definition: dbdata.cxx:268
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:422
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:161
SC_DLLPUBLIC void SetQueryParam(const ScQueryParam &rQueryParam)
Definition: dbdata.cxx:435
ScDBDataContainerBase * mpContainer
Definition: dbdata.hxx:73
SCSIZE nFilteredRowCount
Definition: dbdata.hxx:103
bool HasImportParam() const
Definition: dbdata.cxx:517
::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:461
OUString GetSourceString() const
Definition: dbdata.cxx:261
bool bDoSize
Definition: dbdata.hxx:86
void SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dbdata.cxx:320
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:893
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
bool IsClipOrUndo() const
Definition: document.hxx:1592
SC_DLLPUBLIC ScDBData * GetAnonymousDBData(SCTAB nTab)
Definition: document.cxx:290
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:1072
SC_DLLPUBLIC void SetAnonymousDBData(SCTAB nTab, std::unique_ptr< ScDBData > pDBData)
Definition: document.cxx:302
static SC_DLLPUBLIC ::utl::TransliterationWrapper & GetTransliteration()
Definition: global.cxx:1026
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1064
SCROW GetRowCount() const
Definition: brdcst.hxx:32
const ScAddress & GetStartAddress() const
Definition: brdcst.hxx:31
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:1096
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:301
@ URM_INSDEL
Definition: global.hxx:302
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:442
SCCOL nCol1
Definition: global.hxx:441
SCCOL nCol2
Definition: global.hxx:443
SCROW nRow2
Definition: global.hxx:444
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:120
SCCOL nCol1
selected area
sal_uInt32 mnIndex
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
sal_uInt64 left