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