1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <unotools/transliterationwrapper.hxx>
25 #include <unotools/charclass.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>
40 #include <comphelper/stl_types.hxx>
45 bool ScDBData::less::operator() (const std::unique_ptr
<ScDBData
>& left
, const std::unique_ptr
<ScDBData
>& right
) const
47 return ScGlobal::GetTransliteration().compareString(left
->GetUpperName(), right
->GetUpperName()) < 0;
50 ScDBData::ScDBData( const OUString
& rName
,
52 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
53 bool bByR
, bool bHasH
, bool bTotals
) :
54 // Listeners are to be setup by the "parent" container.
55 mpSortParam(new ScSortParam
),
56 mpQueryParam(new ScQueryParam
),
57 mpSubTotal(new ScSubTotalParam
),
58 mpImportParam(new ScImportParam
),
59 mpContainer (nullptr),
78 mbTableColumnNamesDirty(true),
79 nFilteredRowCount(SCSIZE_MAX
)
81 aUpper
= ScGlobal::getCharClass().uppercase(aUpper
);
84 ScDBData::ScDBData( const ScDBData
& rData
) :
85 // Listeners are to be setup by the "parent" container.
87 ScRefreshTimer ( rData
),
88 mpSortParam(new ScSortParam(*rData
.mpSortParam
)),
89 mpQueryParam(new ScQueryParam(*rData
.mpQueryParam
)),
90 mpSubTotal(new ScSubTotalParam(*rData
.mpSubTotal
)),
91 mpImportParam(new ScImportParam(*rData
.mpImportParam
)),
92 mpContainer (nullptr),
94 aUpper (rData
.aUpper
),
95 nTable (rData
.nTable
),
96 nStartCol (rData
.nStartCol
),
97 nStartRow (rData
.nStartRow
),
98 nEndCol (rData
.nEndCol
),
99 nEndRow (rData
.nEndRow
),
100 bByRow (rData
.bByRow
),
101 bHasHeader (rData
.bHasHeader
),
102 bHasTotals (rData
.bHasTotals
),
103 bDoSize (rData
.bDoSize
),
104 bKeepFmt (rData
.bKeepFmt
),
105 bStripData (rData
.bStripData
),
106 bIsAdvanced (rData
.bIsAdvanced
),
107 aAdvSource (rData
.aAdvSource
),
108 bDBSelection (rData
.bDBSelection
),
109 nIndex (rData
.nIndex
),
110 bAutoFilter (rData
.bAutoFilter
),
111 bModified (rData
.bModified
),
112 maTableColumnNames (rData
.maTableColumnNames
),
113 maTableColumnAttributes(rData
.maTableColumnAttributes
),
114 mbTableColumnNamesDirty(rData
.mbTableColumnNamesDirty
),
115 nFilteredRowCount (rData
.nFilteredRowCount
)
119 ScDBData::ScDBData( const OUString
& rName
, const ScDBData
& rData
) :
120 // Listeners are to be setup by the "parent" container.
122 ScRefreshTimer ( rData
),
123 mpSortParam(new ScSortParam(*rData
.mpSortParam
)),
124 mpQueryParam(new ScQueryParam(*rData
.mpQueryParam
)),
125 mpSubTotal(new ScSubTotalParam(*rData
.mpSubTotal
)),
126 mpImportParam(new ScImportParam(*rData
.mpImportParam
)),
127 mpContainer (nullptr),
130 nTable (rData
.nTable
),
131 nStartCol (rData
.nStartCol
),
132 nStartRow (rData
.nStartRow
),
133 nEndCol (rData
.nEndCol
),
134 nEndRow (rData
.nEndRow
),
135 bByRow (rData
.bByRow
),
136 bHasHeader (rData
.bHasHeader
),
137 bHasTotals (rData
.bHasTotals
),
138 bDoSize (rData
.bDoSize
),
139 bKeepFmt (rData
.bKeepFmt
),
140 bStripData (rData
.bStripData
),
141 bIsAdvanced (rData
.bIsAdvanced
),
142 aAdvSource (rData
.aAdvSource
),
143 bDBSelection (rData
.bDBSelection
),
144 nIndex (rData
.nIndex
),
145 bAutoFilter (rData
.bAutoFilter
),
146 bModified (rData
.bModified
),
147 maTableColumnNames (rData
.maTableColumnNames
),
148 maTableColumnAttributes(rData
.maTableColumnAttributes
),
149 mbTableColumnNamesDirty (rData
.mbTableColumnNamesDirty
),
150 nFilteredRowCount (rData
.nFilteredRowCount
)
152 aUpper
= ScGlobal::getCharClass().uppercase(aUpper
);
155 ScDBData
& ScDBData::operator= (const ScDBData
& rData
)
159 // Don't modify the name. The name is not mutable as it is used as a key
160 // in the container to keep the db ranges sorted by the name.
162 bool bHeaderRangeDiffers
= (nTable
!= rData
.nTable
|| nStartCol
!= rData
.nStartCol
||
163 nEndCol
!= rData
.nEndCol
|| nStartRow
!= rData
.nStartRow
);
164 bool bNeedsListening
= ((bHasHeader
&& bHeaderRangeDiffers
) || (!bHasHeader
&& rData
.bHasHeader
));
165 if (bHasHeader
&& (!rData
.bHasHeader
|| bHeaderRangeDiffers
))
167 EndTableColumnNamesListener();
169 ScRefreshTimer::operator=( rData
);
170 mpSortParam
.reset(new ScSortParam(*rData
.mpSortParam
));
171 mpQueryParam
.reset(new ScQueryParam(*rData
.mpQueryParam
));
172 mpSubTotal
.reset(new ScSubTotalParam(*rData
.mpSubTotal
));
173 mpImportParam
.reset(new ScImportParam(*rData
.mpImportParam
));
175 nTable
= rData
.nTable
;
176 nStartCol
= rData
.nStartCol
;
177 nStartRow
= rData
.nStartRow
;
178 nEndCol
= rData
.nEndCol
;
179 nEndRow
= rData
.nEndRow
;
180 bByRow
= rData
.bByRow
;
181 bHasHeader
= rData
.bHasHeader
;
182 bHasTotals
= rData
.bHasTotals
;
183 bDoSize
= rData
.bDoSize
;
184 bKeepFmt
= rData
.bKeepFmt
;
185 bStripData
= rData
.bStripData
;
186 bIsAdvanced
= rData
.bIsAdvanced
;
187 aAdvSource
= rData
.aAdvSource
;
188 bDBSelection
= rData
.bDBSelection
;
189 nIndex
= rData
.nIndex
;
190 bAutoFilter
= rData
.bAutoFilter
;
191 nFilteredRowCount
= rData
.nFilteredRowCount
;
193 if (bHeaderRangeDiffers
)
194 InvalidateTableColumnNames( true);
197 maTableColumnNames
= rData
.maTableColumnNames
;
198 maTableColumnAttributes
= rData
.maTableColumnAttributes
;
199 mbTableColumnNamesDirty
= rData
.mbTableColumnNamesDirty
;
203 StartTableColumnNamesListener();
208 bool ScDBData::operator== (const ScDBData
& rData
) const
210 // Data that is not in sort or query params.
212 if ( nTable
!= rData
.nTable
||
213 bDoSize
!= rData
.bDoSize
||
214 bKeepFmt
!= rData
.bKeepFmt
||
215 bIsAdvanced
!= rData
.bIsAdvanced
||
216 bStripData
!= rData
.bStripData
||
217 // SAB: I think this should be here, but I don't want to break something
218 // bAutoFilter!= rData.bAutoFilter||
219 ScRefreshTimer::operator!=( rData
)
223 if ( bIsAdvanced
&& aAdvSource
!= rData
.aAdvSource
)
226 ScSortParam aSort1
, aSort2
;
227 GetSortParam(aSort1
);
228 rData
.GetSortParam(aSort2
);
229 if (!(aSort1
== aSort2
))
232 ScQueryParam aQuery1
, aQuery2
;
233 GetQueryParam(aQuery1
);
234 rData
.GetQueryParam(aQuery2
);
235 if (!(aQuery1
== aQuery2
))
238 ScSubTotalParam aSubTotal1
, aSubTotal2
;
239 GetSubTotalParam(aSubTotal1
);
240 rData
.GetSubTotalParam(aSubTotal2
);
241 if (!(aSubTotal1
== aSubTotal2
))
244 ScImportParam aImport1
, aImport2
;
245 GetImportParam(aImport1
);
246 rData
.GetImportParam(aImport2
);
247 return aImport1
== aImport2
;
250 ScDBData::~ScDBData()
255 OUString
ScDBData::GetSourceString() const
257 if (mpImportParam
->bImport
)
258 return mpImportParam
->aDBName
+ "/" + mpImportParam
->aStatement
;
262 OUString
ScDBData::GetOperations() const
265 if (mpQueryParam
->GetEntryCount())
267 const ScQueryEntry
& rEntry
= mpQueryParam
->GetEntry(0);
269 aBuf
.append(ScResId(STR_OPERATION_FILTER
));
272 if (mpSortParam
->maKeyState
[0].bDoSort
)
276 aBuf
.append(ScResId(STR_OPERATION_SORT
));
279 if (mpSubTotal
->aGroups
[0].bActive
&& !mpSubTotal
->bRemoveOnly
)
283 aBuf
.append(ScResId(STR_OPERATION_SUBTOTAL
));
287 aBuf
.append(ScResId(STR_OPERATION_NONE
));
289 return aBuf
.makeStringAndClear();
292 void ScDBData::GetArea(SCTAB
& rTab
, SCCOL
& rCol1
, SCROW
& rRow1
, SCCOL
& rCol2
, SCROW
& rRow2
) const
301 void ScDBData::GetArea(ScRange
& rRange
) const
303 SCROW nNewEndRow
= nEndRow
;
304 rRange
= ScRange( nStartCol
, nStartRow
, nTable
, nEndCol
, nNewEndRow
, nTable
);
307 ScRange
ScDBData::GetHeaderArea() const
310 return ScRange( nStartCol
, nStartRow
, nTable
, nEndCol
, nStartRow
, nTable
);
311 return ScRange( ScAddress::INITIALIZE_INVALID
);
314 void ScDBData::SetArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
316 bool bHeaderRangeChange
= (nTab
!= nTable
|| nCol1
!= nStartCol
|| nCol2
!= nEndCol
|| nRow1
!= nStartRow
);
317 if (bHeaderRangeChange
)
318 EndTableColumnNamesListener();
326 if (bHeaderRangeChange
)
328 SAL_WARN_IF( !maTableColumnNames
.empty(), "sc.core", "ScDBData::SetArea - invalidating column names/offsets");
329 // Invalidate *after* new area has been set above to add the proper
330 // header range to dirty list.
331 InvalidateTableColumnNames( true);
332 StartTableColumnNamesListener();
336 void ScDBData::MoveTo(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
339 tools::Long nDifX
= static_cast<tools::Long
>(nCol1
) - static_cast<tools::Long
>(nStartCol
);
340 tools::Long nDifY
= static_cast<tools::Long
>(nRow1
) - static_cast<tools::Long
>(nStartRow
);
342 tools::Long nSortDif
= bByRow
? nDifX
: nDifY
;
343 tools::Long nSortEnd
= bByRow
? static_cast<tools::Long
>(nCol2
) : static_cast<tools::Long
>(nRow2
);
345 for (sal_uInt16 i
=0; i
<mpSortParam
->GetSortKeyCount(); i
++)
347 mpSortParam
->maKeyState
[i
].nField
+= nSortDif
;
348 if (mpSortParam
->maKeyState
[i
].nField
> nSortEnd
)
350 mpSortParam
->maKeyState
[i
].nField
= 0;
351 mpSortParam
->maKeyState
[i
].bDoSort
= false;
355 SCSIZE nCount
= mpQueryParam
->GetEntryCount();
356 for (SCSIZE i
= 0; i
< nCount
; ++i
)
358 ScQueryEntry
& rEntry
= mpQueryParam
->GetEntry(i
);
359 rEntry
.nField
+= nDifX
;
361 // tdf#48025, tdf#141946: update the column index of the filter criteria,
362 // when the deleted/inserted columns are inside the data range
363 if (nUpdateCol
!= -1)
367 = static_cast<tools::Long
>(nCol2
) - static_cast<tools::Long
>(nEndCol
);
368 if (rEntry
.nField
>= nUpdateCol
)
369 rEntry
.nField
+= nDifX2
;
370 else if (rEntry
.nField
>= nUpdateCol
+ nDifX2
)
374 if (rEntry
.nField
> nCol2
)
377 rEntry
.bDoQuery
= false;
380 for (auto& group
: mpSubTotal
->aGroups
)
382 group
.nField
+= nDifX
;
383 if (group
.nField
> nCol2
)
386 group
.bActive
= false;
390 SetArea( nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
393 void ScDBData::GetSortParam( ScSortParam
& rSortParam
) const
395 rSortParam
= *mpSortParam
;
396 rSortParam
.nCol1
= nStartCol
;
397 rSortParam
.nRow1
= nStartRow
;
398 rSortParam
.nCol2
= nEndCol
;
399 rSortParam
.nRow2
= nEndRow
;
400 rSortParam
.bByRow
= bByRow
;
401 rSortParam
.bHasHeader
= bHasHeader
;
402 /* TODO: add Totals to ScSortParam? */
405 void ScDBData::SetSortParam( const ScSortParam
& rSortParam
)
407 mpSortParam
.reset(new ScSortParam(rSortParam
));
408 bByRow
= rSortParam
.bByRow
;
411 void ScDBData::UpdateFromSortParam( const ScSortParam
& rSortParam
)
413 bHasHeader
= rSortParam
.bHasHeader
;
416 void ScDBData::GetQueryParam( ScQueryParam
& rQueryParam
) const
418 rQueryParam
= *mpQueryParam
;
419 rQueryParam
.nCol1
= nStartCol
;
420 rQueryParam
.nRow1
= nStartRow
;
421 rQueryParam
.nCol2
= nEndCol
;
422 rQueryParam
.nRow2
= nEndRow
;
423 rQueryParam
.nTab
= nTable
;
424 rQueryParam
.bByRow
= bByRow
;
425 rQueryParam
.bHasHeader
= bHasHeader
;
426 rQueryParam
.bHasTotals
= bHasTotals
;
429 void ScDBData::SetQueryParam(const ScQueryParam
& rQueryParam
)
431 mpQueryParam
.reset(new ScQueryParam(rQueryParam
));
433 // set bIsAdvanced to false for everything that is not from the
434 // advanced filter dialog
438 void ScDBData::SetAdvancedQuerySource(const ScRange
* pSource
)
442 aAdvSource
= *pSource
;
449 bool ScDBData::GetAdvancedQuerySource(ScRange
& rSource
) const
451 rSource
= aAdvSource
;
455 void ScDBData::GetSubTotalParam(ScSubTotalParam
& rSubTotalParam
) const
457 rSubTotalParam
= *mpSubTotal
;
459 // Share the data range with the parent db data. The range in the subtotal
460 // param struct is not used.
461 rSubTotalParam
.nCol1
= nStartCol
;
462 rSubTotalParam
.nRow1
= nStartRow
;
463 rSubTotalParam
.nCol2
= nEndCol
;
464 rSubTotalParam
.nRow2
= nEndRow
;
467 void ScDBData::SetSubTotalParam(const ScSubTotalParam
& rSubTotalParam
)
469 mpSubTotal
.reset(new ScSubTotalParam(rSubTotalParam
));
472 void ScDBData::GetImportParam(ScImportParam
& rImportParam
) const
474 rImportParam
= *mpImportParam
;
476 rImportParam
.nCol1
= nStartCol
;
477 rImportParam
.nRow1
= nStartRow
;
478 rImportParam
.nCol2
= nEndCol
;
479 rImportParam
.nRow2
= nEndRow
;
482 void ScDBData::SetImportParam(const ScImportParam
& rImportParam
)
484 // the range is ignored.
485 mpImportParam
.reset(new ScImportParam(rImportParam
));
488 bool ScDBData::IsDBAtCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
, ScDBDataPortion ePortion
) const
494 case ScDBDataPortion::TOP_LEFT
:
495 return nCol
== nStartCol
&& nRow
== nStartRow
;
496 case ScDBDataPortion::AREA
:
497 return nCol
>= nStartCol
&& nCol
<= nEndCol
&& nRow
>= nStartRow
&& nRow
<= nEndRow
;
504 bool ScDBData::IsDBAtArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
506 return (nTab
== nTable
)
507 && (nCol1
== nStartCol
) && (nRow1
== nStartRow
)
508 && (nCol2
== nEndCol
) && (nRow2
== nEndRow
);
511 bool ScDBData::HasImportParam() const
513 return mpImportParam
&& mpImportParam
->bImport
;
516 bool ScDBData::HasQueryParam() const
521 if (!mpQueryParam
->GetEntryCount())
524 return mpQueryParam
->GetEntry(0).bDoQuery
;
527 bool ScDBData::HasSortParam() const
529 return mpSortParam
&&
530 !mpSortParam
->maKeyState
.empty() &&
531 mpSortParam
->maKeyState
[0].bDoSort
;
534 bool ScDBData::HasSubTotalParam() const
536 return mpSubTotal
&& mpSubTotal
->aGroups
[0].bActive
;
539 void ScDBData::UpdateMoveTab(SCTAB nOldPos
, SCTAB nNewPos
)
543 SCTAB nTab
= aRange
.aStart
.Tab(); // a database range is only on one sheet
545 // customize as the current table as ScTablesHint (tabvwsh5.cxx)
547 if (nTab
== nOldPos
) // moved sheet
549 else if (nOldPos
< nNewPos
) // moved to the back
551 if (nTab
> nOldPos
&& nTab
<= nNewPos
) // move this sheet
554 else // moved to the front
556 if (nTab
>= nNewPos
&& nTab
< nOldPos
) // move this sheet
560 bool bChanged
= (nTab
!= aRange
.aStart
.Tab());
563 // SetArea() invalidates column names, but it is the same column range
564 // just on a different sheet; remember and set new.
565 ::std::vector
<OUString
> aNames(maTableColumnNames
);
566 bool bTableColumnNamesDirty
= mbTableColumnNamesDirty
;
567 // Same column range.
568 SetArea(nTab
, aRange
.aStart
.Col(), aRange
.aStart
.Row(), aRange
.aEnd
.Col(),
570 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
571 maTableColumnNames
= aNames
;
572 maTableColumnAttributes
.resize(aNames
.size());
573 mbTableColumnNamesDirty
= bTableColumnNamesDirty
;
576 // MoveTo() is not necessary if only the sheet changed.
578 SetModified(bChanged
);
581 bool ScDBData::UpdateReference(const ScDocument
* pDoc
, UpdateRefMode eUpdateRefMode
,
582 SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
583 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
,
584 SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
592 GetArea( theTab1
, theCol1
, theRow1
, theCol2
, theRow2
);
594 SCCOL nOldCol1
= theCol1
, nOldCol2
= theCol2
;
597 = ScRefUpdate::Update(pDoc
, eUpdateRefMode
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
, nDx
,
598 nDy
, nDz
, theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
600 bool bDoUpdate
= eRet
!= UR_NOTHING
;
602 if (bDoUpdate
&& eRet
!= UR_INVALID
)
604 // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
605 AdjustTableColumnAttributes( eUpdateRefMode
, nDx
, nCol1
, nOldCol1
, nOldCol2
, theCol1
, theCol2
);
606 ::std::vector
<OUString
> aNames( maTableColumnNames
);
607 bool bTableColumnNamesDirty
= mbTableColumnNamesDirty
;
608 // tdf#48025, tdf#141946: update the column index of the filter criteria,
609 // when the deleted/inserted columns are inside the data range
610 if (HasAutoFilter() && theCol1
- nOldCol1
!= theCol2
- nOldCol2
)
611 MoveTo(theTab1
, theCol1
, theRow1
, theCol2
, theRow2
, nCol1
);
613 MoveTo( theTab1
, theCol1
, theRow1
, theCol2
, theRow2
);
614 // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
615 maTableColumnNames
= aNames
;
616 maTableColumnAttributes
.resize(aNames
.size());
617 mbTableColumnNamesDirty
= bTableColumnNamesDirty
;
620 ScRange aRangeAdvSource
;
621 if ( GetAdvancedQuerySource(aRangeAdvSource
) )
623 aRangeAdvSource
.GetVars( theCol1
,theRow1
,theTab1
, theCol2
,theRow2
,theTab2
);
624 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
625 nCol1
,nRow1
,nTab1
, nCol2
,nRow2
,nTab2
, nDx
,nDy
,nDz
,
626 theCol1
,theRow1
,theTab1
, theCol2
,theRow2
,theTab2
) )
628 aRangeAdvSource
.aStart
.Set( theCol1
,theRow1
,theTab1
);
629 aRangeAdvSource
.aEnd
.Set( theCol2
,theRow2
,theTab2
);
630 SetAdvancedQuerySource( &aRangeAdvSource
);
632 bDoUpdate
= true; // DBData is modified
636 SetModified(bDoUpdate
);
638 return eRet
== UR_INVALID
;
640 //TODO: check if something was deleted/inserted with-in the range !!!
643 void ScDBData::ExtendDataArea(const ScDocument
& rDoc
)
645 // Extend the DB area to include data rows immediately below.
646 SCCOL nOldCol1
= nStartCol
, nOldCol2
= nEndCol
;
647 SCROW nOldEndRow
= nEndRow
;
648 rDoc
.GetDataArea(nTable
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, false, true);
649 // nOldEndRow==rDoc.MaxRow() may easily happen when selecting whole columns and
650 // setting an AutoFilter (i.e. creating an anonymous database-range). We
651 // certainly don't want to iterate over nearly a million empty cells, but
652 // keep only an intentionally user selected range.
653 if (nOldEndRow
< rDoc
.MaxRow() && nEndRow
< nOldEndRow
)
654 nEndRow
= nOldEndRow
;
655 if (nStartCol
!= nOldCol1
|| nEndCol
!= nOldCol2
)
657 SAL_WARN_IF( !maTableColumnNames
.empty(), "sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
658 InvalidateTableColumnNames( true);
662 void ScDBData::ExtendBackColorArea(const ScDocument
& rDoc
)
664 // Extend the DB area to include data rows immediately below.
665 SCCOL nOldCol1
= nStartCol
, nOldCol2
= nEndCol
;
666 SCROW nOldEndRow
= nEndRow
;
667 rDoc
.GetBackColorArea(nTable
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
669 if (nOldEndRow
< rDoc
.MaxRow() && nEndRow
< nOldEndRow
)
670 nEndRow
= nOldEndRow
;
672 if (nStartCol
!= nOldCol1
|| nEndCol
!= nOldCol2
)
674 SAL_WARN_IF( !maTableColumnNames
.empty(), "sc.core", "ScDBData::ExtendBackColorArea - invalidating column names/offsets");
675 InvalidateTableColumnNames( true);
679 void ScDBData::StartTableColumnNamesListener()
681 if (mpContainer
&& bHasHeader
)
683 ScDocument
& rDoc
= mpContainer
->GetDocument();
684 if (!rDoc
.IsClipOrUndo())
685 rDoc
.StartListeningArea( GetHeaderArea(), false, this);
689 void ScDBData::EndTableColumnNamesListener()
694 void ScDBData::SetTableColumnNames( ::std::vector
< OUString
>&& rNames
)
696 maTableColumnNames
= std::move(rNames
);
697 mbTableColumnNamesDirty
= false;
700 void ScDBData::SetTableColumnAttributes( ::std::vector
< TableColumnAttributes
>&& rAttributes
)
702 maTableColumnAttributes
= std::move(rAttributes
);
705 void ScDBData::AdjustTableColumnAttributes( UpdateRefMode eUpdateRefMode
, SCCOL nDx
, SCCOL nCol1
,
706 SCCOL nOldCol1
, SCCOL nOldCol2
, SCCOL nNewCol1
, SCCOL nNewCol2
)
708 if (maTableColumnNames
.empty())
711 SCCOL nDiff1
= nNewCol1
- nOldCol1
;
712 SCCOL nDiff2
= nNewCol2
- nOldCol2
;
713 if (nDiff1
== nDiff2
)
714 return; // not moved or entirely moved, nothing to do
716 ::std::vector
<OUString
> aNewNames
;
717 ::std::vector
<TableColumnAttributes
> aNewAttributes
;
718 if (eUpdateRefMode
== URM_INSDEL
)
721 mbTableColumnNamesDirty
= true; // inserted columns will have empty names
723 // nCol1 is the first column of the block that gets shifted, determine
724 // the head and tail elements that are to be copied for deletion or
726 size_t nHead
= static_cast<size_t>(::std::max( nCol1
+ std::min
<SCCOL
>(nDx
, 0) - nOldCol1
, 0));
727 size_t nTail
= static_cast<size_t>(::std::max( nOldCol2
- nCol1
+ 1, 0));
728 size_t n
= nHead
+ nTail
;
729 if (0 < n
&& n
<= maTableColumnNames
.size())
734 aNewAttributes
.resize(n
);
736 for (size_t i
= 0; i
< nHead
; ++i
)
738 aNewNames
[i
] = maTableColumnNames
[i
];
739 aNewAttributes
[i
] = maTableColumnAttributes
[i
];
741 // Copy tail, inserted middle range, if any, stays empty.
742 for (size_t i
= n
- nTail
, j
= maTableColumnNames
.size() - nTail
; i
< n
; ++i
, ++j
)
744 aNewNames
[i
] = maTableColumnNames
[j
];
745 aNewAttributes
[i
] = maTableColumnAttributes
[j
];
748 } // else empty aNewNames invalidates names/offsets
750 SAL_WARN_IF( !maTableColumnNames
.empty() && aNewNames
.empty(),
751 "sc.core", "ScDBData::AdjustTableColumnAttributes - invalidating column attributes/offsets");
752 aNewNames
.swap( maTableColumnNames
);
753 aNewAttributes
.swap(maTableColumnAttributes
);
754 if (maTableColumnNames
.empty())
755 mbTableColumnNamesDirty
= true;
756 if (mbTableColumnNamesDirty
)
757 InvalidateTableColumnNames( false); // preserve new column names array
760 void ScDBData::InvalidateTableColumnNames( bool bSwapToEmptyNames
)
762 mbTableColumnNamesDirty
= true;
763 if (bSwapToEmptyNames
&& !maTableColumnNames
.empty())
764 ::std::vector
<OUString
>().swap( maTableColumnNames
);
767 // Add header range to dirty list.
769 mpContainer
->GetDirtyTableColumnNames().Join( GetHeaderArea());
772 // We need *some* range in the dirty list even without header area,
773 // otherwise the container would not attempt to call a refresh.
774 mpContainer
->GetDirtyTableColumnNames().Join( ScRange( nStartCol
, nStartRow
, nTable
));
780 class TableColumnNameSearch
783 explicit TableColumnNameSearch( OUString aSearchName
) :
784 maSearchName(std::move( aSearchName
))
788 bool operator()( const OUString
& rName
) const
790 return ScGlobal::GetTransliteration().isEqual( maSearchName
, rName
);
794 OUString maSearchName
;
797 /** Set a numbered table column name at given nIndex, preventing duplicates,
798 numbering starting at nCount. If nCount==0 then the first attempt is made
799 with an unnumbered name and if already present the next attempt with
800 nCount=2, so "Original" and "Original2". No check whether nIndex is valid. */
801 void SetTableColumnName( ::std::vector
<OUString
>& rVec
, size_t nIndex
, const OUString
& rName
, size_t nCount
)
807 aStr
= rName
+ OUString::number( nCount
);
814 if (std::none_of( rVec
.begin(), rVec
.end(), TableColumnNameSearch( aStr
)))
824 void ScDBData::RefreshTableColumnNames( ScDocument
* pDoc
)
826 ::std::vector
<OUString
> aNewNames
;
827 aNewNames
.resize( nEndCol
- nStartCol
+ 1);
828 bool bHaveEmpty
= false;
829 if (!HasHeader() || !pDoc
)
830 bHaveEmpty
= true; // Assume we have empty ones and fill below.
833 ScHorizontalCellIterator
aIter(*pDoc
, nTable
, nStartCol
, nStartRow
, nEndCol
, nStartRow
); // header row only
834 ScRefCellValue
* pCell
;
835 SCCOL nCol
, nLastColFilled
= nStartCol
- 1;
837 while ((pCell
= aIter
.GetNext( nCol
, nRow
)) != nullptr)
839 if (pCell
->hasString())
841 const OUString aStr
= pCell
->getString( pDoc
);
846 SetTableColumnName( aNewNames
, nCol
-nStartCol
, aStr
, 0);
847 if (nLastColFilled
< nCol
-1)
850 nLastColFilled
= nCol
;
857 // Never leave us with empty names, try to remember previous name that
858 // might had been used to compile formulas, but only if same number of
859 // columns and no duplicates.
860 if (bHaveEmpty
&& aNewNames
.size() == maTableColumnNames
.size())
863 for (size_t i
=0, n
=aNewNames
.size(); i
< n
; ++i
)
865 if (aNewNames
[i
].isEmpty())
867 const OUString
& rStr
= maTableColumnNames
[i
];
871 SetTableColumnName( aNewNames
, i
, rStr
, 0);
876 // If we still have empty ones then fill those with "Column#" with #
877 // starting at the column offset number. Still no duplicates of course.
880 OUString
aColumn( ScResId(STR_COLUMN
));
881 for (size_t i
=0, n
=aNewNames
.size(); i
< n
; ++i
)
883 if (aNewNames
[i
].isEmpty())
884 SetTableColumnName( aNewNames
, i
, aColumn
, i
+1);
888 aNewNames
.swap( maTableColumnNames
);
889 maTableColumnAttributes
.resize(maTableColumnNames
.size());
890 mbTableColumnNamesDirty
= false;
893 void ScDBData::RefreshTableColumnNames( ScDocument
* pDoc
, const ScRange
& rRange
)
895 // Header-less tables get names generated, completely empty a full refresh.
896 if (mbTableColumnNamesDirty
&& (!HasHeader() || maTableColumnNames
.empty()))
898 RefreshTableColumnNames( pDoc
);
902 // Check if this is affected for the range requested.
903 ScRange
aIntersection( GetHeaderArea().Intersection( rRange
));
904 if (!aIntersection
.IsValid())
907 // Always fully refresh, only one cell of a range was broadcasted per area
908 // listener if multiple cells were affected. We don't know if there were
909 // more. Also, we need the full check anyway in case a duplicated name was
911 RefreshTableColumnNames( pDoc
);
914 sal_Int32
ScDBData::GetColumnNameOffset( const OUString
& rName
) const
916 if (maTableColumnNames
.empty())
919 ::std::vector
<OUString
>::const_iterator
it(
920 ::std::find_if( maTableColumnNames
.begin(), maTableColumnNames
.end(), TableColumnNameSearch( rName
)));
921 if (it
!= maTableColumnNames
.end())
922 return it
- maTableColumnNames
.begin();
927 const OUString
& ScDBData::GetTableColumnName( SCCOL nCol
) const
929 if (maTableColumnNames
.empty())
930 return EMPTY_OUSTRING
;
932 SCCOL nOffset
= nCol
- nStartCol
;
933 if (nOffset
< 0 || maTableColumnNames
.size() <= o3tl::make_unsigned(nOffset
))
934 return EMPTY_OUSTRING
;
936 return maTableColumnNames
[nOffset
];
939 void ScDBData::Notify( const SfxHint
& rHint
)
941 if (rHint
.GetId() != SfxHintId::ScDataChanged
)
943 const ScHint
* pScHint
= static_cast<const ScHint
*>(&rHint
);
945 mbTableColumnNamesDirty
= true;
947 assert(!"ScDBData::Notify - how did we end up here without container?");
950 // Only one cell of a range is broadcasted per area listener if
951 // multiple cells are affected. Expand the range to what this is
952 // listening to. Broadcasted address outside should not happen,
953 // but... let it trigger a refresh if.
954 const ScRange
aHeaderRange( GetHeaderArea());
955 ScAddress
aHintAddress( pScHint
->GetStartAddress());
956 if (aHeaderRange
.IsValid())
958 mpContainer
->GetDirtyTableColumnNames().Join( aHeaderRange
);
959 // Header range is one row.
960 // The ScHint's "range" is an address with row count.
961 // Though broadcasted is usually only one cell, check for the
962 // possible case of row block and for one cell in the same row.
963 if (aHintAddress
.Row() <= aHeaderRange
.aStart
.Row()
964 && aHeaderRange
.aStart
.Row() < aHintAddress
.Row() + pScHint
->GetRowCount())
966 aHintAddress
.SetRow( aHeaderRange
.aStart
.Row());
967 if (!aHeaderRange
.Contains( aHintAddress
))
968 mpContainer
->GetDirtyTableColumnNames().Join( ScRange(aHintAddress
) );
973 // We need *some* range in the dirty list even without header area,
974 // otherwise the container would not attempt to call a refresh.
975 aHintAddress
.SetRow( nStartRow
);
976 mpContainer
->GetDirtyTableColumnNames().Join( ScRange(aHintAddress
) );
980 // Do not refresh column names here, which might trigger unwanted
984 void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount
)
986 SCSIZE nTotal
= nEndRow
- nStartRow
+ 1;
989 nFilteredRowCount
= nTotal
- nNonFilteredRowCount
;
992 void ScDBData::GetFilterSelCount( SCSIZE
& nSelected
, SCSIZE
& nTotal
)
994 nTotal
= nEndRow
- nStartRow
+ 1;
997 if( nFilteredRowCount
!= SCSIZE_MAX
)
998 nSelected
= nTotal
- nFilteredRowCount
;
1000 nSelected
= nFilteredRowCount
;
1009 explicit FindByTable(SCTAB nTab
) : mnTab(nTab
) {}
1011 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
1015 return aRange
.aStart
.Tab() == mnTab
;
1019 class UpdateMoveTabFunc
1024 UpdateMoveTabFunc(SCTAB nOld
, SCTAB nNew
) : mnOldTab(nOld
), mnNewTab(nNew
) {}
1025 void operator() (std::unique_ptr
<ScDBData
> const& p
)
1027 p
->UpdateMoveTab(mnOldTab
, mnNewTab
);
1031 OUString
lcl_IncrementNumberInNamedRange(ScDBCollection::NamedDBs
& namedDBs
,
1032 std::u16string_view rOldName
)
1034 // Append or increment a numeric suffix and do not generate names that
1035 // could result in a cell reference by ensuring at least one underscore is
1038 // "aaaa1" => "aaaa1_2"
1039 // "aa_a" => "aa_a_2"
1040 // "aa_a_" => "aa_a__2"
1041 // "aa_a1" => "aa_a1_2"
1042 // "aa_1a" => "aa_1a_2"
1046 size_t nLastIndex
= rOldName
.rfind('_');
1047 sal_Int32 nOldNumber
= 1;
1049 if (nLastIndex
!= std::u16string_view::npos
)
1052 std::u16string_view
sLastPart(rOldName
.substr(nLastIndex
));
1053 nOldNumber
= o3tl::toInt32(sLastPart
);
1055 // If that number is exactly at the end then increment the number; else
1056 // append "_" and number.
1057 // toInt32() returns 0 on failure and also stops at trailing non-digit
1058 // characters (toInt32("1a")==1).
1059 if (OUString::number(nOldNumber
) == sLastPart
)
1060 aPrefix
= rOldName
.substr(0, nLastIndex
);
1063 aPrefix
= OUString::Concat(rOldName
) + "_";
1067 else // No "_" found, append "_" and number.
1068 aPrefix
= OUString::Concat(rOldName
) + "_";
1072 sNewName
= aPrefix
+ OUString::number(++nOldNumber
);
1073 } while (namedDBs
.findByName(sNewName
) != nullptr);
1082 ScDBDataPortion mePortion
;
1084 FindByCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
, ScDBDataPortion ePortion
) :
1085 mnCol(nCol
), mnRow(nRow
), mnTab(nTab
), mePortion(ePortion
) {}
1087 bool operator() (std::unique_ptr
<ScDBData
> const& p
)
1089 return p
->IsDBAtCursor(mnCol
, mnRow
, mnTab
, mePortion
);
1095 const ScRange
& mrRange
;
1097 explicit FindByRange(const ScRange
& rRange
) : mrRange(rRange
) {}
1099 bool operator() (std::unique_ptr
<ScDBData
> const& p
)
1101 return p
->IsDBAtArea(
1102 mrRange
.aStart
.Tab(), mrRange
.aStart
.Col(), mrRange
.aStart
.Row(), mrRange
.aEnd
.Col(), mrRange
.aEnd
.Row());
1110 explicit FindByIndex(sal_uInt16 nIndex
) : mnIndex(nIndex
) {}
1111 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
1113 return p
->GetIndex() == mnIndex
;
1117 class FindByUpperName
1119 const OUString
& mrName
;
1121 explicit FindByUpperName(const OUString
& rName
) : mrName(rName
) {}
1122 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
1124 return p
->GetUpperName() == mrName
;
1130 const OUString
& mrName
;
1132 explicit FindByName(const OUString
& rName
) : mrName(rName
) {}
1133 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
1135 return p
->GetName() == mrName
;
1141 const ScDBData
* mpDBData
;
1143 explicit FindByPointer(const ScDBData
* pDBData
) : mpDBData(pDBData
) {}
1144 bool operator() (std::unique_ptr
<ScDBData
> const& p
) const
1146 return p
.get() == mpDBData
;
1152 ScDocument
& ScDBDataContainerBase::GetDocument() const
1157 ScRangeList
& ScDBDataContainerBase::GetDirtyTableColumnNames()
1159 return maDirtyTableColumnNames
;
1162 ScDBCollection::NamedDBs::NamedDBs(ScDBCollection
& rParent
, ScDocument
& rDoc
) :
1163 ScDBDataContainerBase(rDoc
), mrParent(rParent
) {}
1165 ScDBCollection::NamedDBs::NamedDBs(const NamedDBs
& r
, ScDBCollection
& rParent
)
1166 : ScDBDataContainerBase(r
.mrDoc
)
1169 for (auto const& it
: r
.m_DBs
)
1171 ScDBData
* p
= new ScDBData(*it
);
1172 std::unique_ptr
<ScDBData
> pData(p
);
1173 if (m_DBs
.insert( std::move(pData
)).second
)
1178 ScDBCollection::NamedDBs::~NamedDBs()
1182 void ScDBCollection::NamedDBs::initInserted( ScDBData
* p
)
1184 p
->SetContainer( this);
1185 if (mrDoc
.IsClipOrUndo())
1188 p
->StartTableColumnNamesListener(); // needs the container be set already
1189 if (!p
->AreTableColumnNamesDirty())
1194 // Refresh table column names in next round.
1195 maDirtyTableColumnNames
.Join( p
->GetHeaderArea());
1199 // Header-less table can generate its column names
1200 // already without accessing the document.
1201 p
->RefreshTableColumnNames( nullptr);
1205 ScDBCollection::NamedDBs::iterator
ScDBCollection::NamedDBs::begin()
1207 return m_DBs
.begin();
1210 ScDBCollection::NamedDBs::iterator
ScDBCollection::NamedDBs::end()
1215 ScDBCollection::NamedDBs::const_iterator
ScDBCollection::NamedDBs::begin() const
1217 return m_DBs
.begin();
1220 ScDBCollection::NamedDBs::const_iterator
ScDBCollection::NamedDBs::end() const
1225 ScDBData
* ScDBCollection::NamedDBs::findByIndex(sal_uInt16 nIndex
)
1227 DBsType::iterator itr
= find_if(
1228 m_DBs
.begin(), m_DBs
.end(), FindByIndex(nIndex
));
1229 return itr
== m_DBs
.end() ? nullptr : itr
->get();
1232 ScDBData
* ScDBCollection::NamedDBs::findByUpperName(const OUString
& rName
)
1234 DBsType::iterator itr
= find_if(
1235 m_DBs
.begin(), m_DBs
.end(), FindByUpperName(rName
));
1236 return itr
== m_DBs
.end() ? nullptr : itr
->get();
1239 auto ScDBCollection::NamedDBs::findByUpperName2(const OUString
& rName
) -> iterator
1242 m_DBs
.begin(), m_DBs
.end(), FindByUpperName(rName
));
1245 ScDBData
* ScDBCollection::NamedDBs::findByName(const OUString
& rName
)
1247 DBsType::iterator itr
= find_if(m_DBs
.begin(), m_DBs
.end(), FindByName(rName
));
1248 return itr
== m_DBs
.end() ? nullptr : itr
->get();
1251 bool ScDBCollection::NamedDBs::insert(std::unique_ptr
<ScDBData
> pData
)
1253 auto p
= pData
.get();
1254 if (!pData
->GetIndex())
1255 pData
->SetIndex(mrParent
.nEntryIndex
++);
1257 std::pair
<DBsType::iterator
, bool> r
= m_DBs
.insert(std::move(pData
));
1263 /* TODO: shouldn't the import refresh not be setup for
1264 * clipboard/undo documents? It was already like this before... */
1265 if (p
->HasImportParam() && !p
->HasImportSelection())
1267 p
->SetRefreshHandler(mrParent
.GetRefreshHandler());
1268 p
->SetRefreshControl(&mrDoc
.GetRefreshTimerControlAddress());
1274 ScDBCollection::NamedDBs::iterator
ScDBCollection::NamedDBs::erase(const iterator
& itr
)
1276 return m_DBs
.erase(itr
);
1279 bool ScDBCollection::NamedDBs::empty() const
1281 return m_DBs
.empty();
1284 size_t ScDBCollection::NamedDBs::size() const
1286 return m_DBs
.size();
1289 bool ScDBCollection::NamedDBs::operator== (const NamedDBs
& r
) const
1291 return ::comphelper::ContainerUniquePtrEquals(m_DBs
, r
.m_DBs
);
1294 ScDBCollection::AnonDBs::iterator
ScDBCollection::AnonDBs::begin()
1296 return m_DBs
.begin();
1299 ScDBCollection::AnonDBs::iterator
ScDBCollection::AnonDBs::end()
1304 ScDBCollection::AnonDBs::const_iterator
ScDBCollection::AnonDBs::begin() const
1306 return m_DBs
.begin();
1309 ScDBCollection::AnonDBs::const_iterator
ScDBCollection::AnonDBs::end() const
1314 const ScDBData
* ScDBCollection::AnonDBs::findAtCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
1315 ScDBDataPortion ePortion
) const
1317 DBsType::const_iterator itr
= find_if(
1318 m_DBs
.begin(), m_DBs
.end(), FindByCursor(nCol
, nRow
, nTab
, ePortion
));
1319 return itr
== m_DBs
.end() ? nullptr : itr
->get();
1322 const ScDBData
* ScDBCollection::AnonDBs::findByRange(const ScRange
& rRange
) const
1324 DBsType::const_iterator itr
= find_if(
1325 m_DBs
.begin(), m_DBs
.end(), FindByRange(rRange
));
1326 return itr
== m_DBs
.end() ? nullptr : itr
->get();
1329 void ScDBCollection::AnonDBs::deleteOnTab(SCTAB nTab
)
1331 FindByTable
func(nTab
);
1332 std::erase_if(m_DBs
, func
);
1335 ScDBData
* ScDBCollection::AnonDBs::getByRange(const ScRange
& rRange
)
1337 const ScDBData
* pData
= findByRange(rRange
);
1340 // Insert a new db data. They all have identical names.
1341 ::std::unique_ptr
<ScDBData
> pNew(new ScDBData(
1342 STR_DB_GLOBAL_NONAME
, rRange
.aStart
.Tab(), rRange
.aStart
.Col(), rRange
.aStart
.Row(),
1343 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), true, false, false));
1345 m_DBs
.push_back(std::move(pNew
));
1347 return const_cast<ScDBData
*>(pData
);
1350 void ScDBCollection::AnonDBs::insert(ScDBData
* p
)
1352 m_DBs
.push_back(std::unique_ptr
<ScDBData
>(p
));
1355 ScDBCollection::AnonDBs::iterator
ScDBCollection::AnonDBs::erase(const iterator
& itr
)
1357 return m_DBs
.erase(itr
);
1360 bool ScDBCollection::AnonDBs::empty() const
1362 return m_DBs
.empty();
1365 bool ScDBCollection::AnonDBs::has( const ScDBData
* p
) const
1367 return any_of(m_DBs
.begin(), m_DBs
.end(), FindByPointer(p
));
1370 bool ScDBCollection::AnonDBs::operator== (const AnonDBs
& r
) const
1372 return ::comphelper::ContainerUniquePtrEquals(m_DBs
, r
.m_DBs
);
1375 ScDBCollection::AnonDBs::AnonDBs()
1379 ScDBCollection::AnonDBs::AnonDBs(AnonDBs
const& r
)
1381 m_DBs
.reserve(r
.m_DBs
.size());
1382 for (auto const& it
: r
.m_DBs
)
1384 m_DBs
.push_back(std::make_unique
<ScDBData
>(*it
));
1388 ScDBCollection::ScDBCollection(ScDocument
& rDocument
) :
1389 rDoc(rDocument
), nEntryIndex(1), maNamedDBs(*this, rDocument
) {}
1391 ScDBCollection::ScDBCollection(const ScDBCollection
& r
) :
1392 rDoc(r
.rDoc
), nEntryIndex(r
.nEntryIndex
), maNamedDBs(r
.maNamedDBs
, *this), maAnonDBs(r
.maAnonDBs
) {}
1394 const ScDBData
* ScDBCollection::GetDBAtCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
, ScDBDataPortion ePortion
) const
1396 // First, search the global named db ranges.
1397 NamedDBs::DBsType::const_iterator itr
= find_if(
1398 maNamedDBs
.begin(), maNamedDBs
.end(), FindByCursor(nCol
, nRow
, nTab
, ePortion
));
1399 if (itr
!= maNamedDBs
.end())
1402 // Check for the sheet-local anonymous db range.
1403 const ScDBData
* pNoNameData
= rDoc
.GetAnonymousDBData(nTab
);
1405 if (pNoNameData
->IsDBAtCursor(nCol
,nRow
,nTab
,ePortion
))
1408 // Check the global anonymous db ranges.
1409 const ScDBData
* pData
= getAnonDBs().findAtCursor(nCol
, nRow
, nTab
, ePortion
);
1413 // Do NOT check for the document global temporary anonymous db range here.
1418 ScDBData
* ScDBCollection::GetDBAtCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
, ScDBDataPortion ePortion
)
1420 // First, search the global named db ranges.
1421 NamedDBs::DBsType::iterator itr
= find_if(
1422 maNamedDBs
.begin(), maNamedDBs
.end(), FindByCursor(nCol
, nRow
, nTab
, ePortion
));
1423 if (itr
!= maNamedDBs
.end())
1426 // Check for the sheet-local anonymous db range.
1427 ScDBData
* pNoNameData
= rDoc
.GetAnonymousDBData(nTab
);
1429 if (pNoNameData
->IsDBAtCursor(nCol
,nRow
,nTab
,ePortion
))
1432 // Check the global anonymous db ranges.
1433 const ScDBData
* pData
= getAnonDBs().findAtCursor(nCol
, nRow
, nTab
, ePortion
);
1435 return const_cast<ScDBData
*>(pData
);
1437 // Do NOT check for the document global temporary anonymous db range here.
1442 const ScDBData
* ScDBCollection::GetDBAtArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
1444 // First, search the global named db ranges.
1445 ScRange
aRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
1446 NamedDBs::DBsType::const_iterator itr
= find_if(
1447 maNamedDBs
.begin(), maNamedDBs
.end(), FindByRange(aRange
));
1448 if (itr
!= maNamedDBs
.end())
1451 // Check for the sheet-local anonymous db range.
1452 ScDBData
* pNoNameData
= rDoc
.GetAnonymousDBData(nTab
);
1454 if (pNoNameData
->IsDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
))
1457 // Lastly, check the global anonymous db ranges.
1458 const ScDBData
* pData
= maAnonDBs
.findByRange(aRange
);
1462 // As a last resort, check for the document global temporary anonymous db range.
1463 pNoNameData
= rDoc
.GetAnonymousDBData();
1465 if (pNoNameData
->IsDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
))
1471 ScDBData
* ScDBCollection::GetDBAtArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
1473 // First, search the global named db ranges.
1474 ScRange
aRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
1475 NamedDBs::DBsType::iterator itr
= find_if(
1476 maNamedDBs
.begin(), maNamedDBs
.end(), FindByRange(aRange
));
1477 if (itr
!= maNamedDBs
.end())
1480 // Check for the sheet-local anonymous db range.
1481 ScDBData
* pNoNameData
= rDoc
.GetAnonymousDBData(nTab
);
1483 if (pNoNameData
->IsDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
))
1486 // Lastly, check the global anonymous db ranges.
1487 const ScDBData
* pData
= getAnonDBs().findByRange(aRange
);
1489 return const_cast<ScDBData
*>(pData
);
1491 // As a last resort, check for the document global temporary anonymous db range.
1492 pNoNameData
= rDoc
.GetAnonymousDBData();
1494 if (pNoNameData
->IsDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
))
1500 void ScDBCollection::RefreshDirtyTableColumnNames()
1502 for (size_t i
=0; i
< maNamedDBs
.maDirtyTableColumnNames
.size(); ++i
)
1504 const ScRange
& rRange
= maNamedDBs
.maDirtyTableColumnNames
[i
];
1505 for (auto const& it
: maNamedDBs
)
1507 if (it
->AreTableColumnNamesDirty())
1508 it
->RefreshTableColumnNames( &maNamedDBs
.mrDoc
, rRange
);
1511 maNamedDBs
.maDirtyTableColumnNames
.RemoveAll();
1514 void ScDBCollection::DeleteOnTab( SCTAB nTab
)
1516 FindByTable
func(nTab
);
1517 // First, collect the positions of all items that need to be deleted.
1518 ::std::vector
<NamedDBs::DBsType::iterator
> v
;
1520 NamedDBs::DBsType::iterator itr
= maNamedDBs
.begin(), itrEnd
= maNamedDBs
.end();
1521 for (; itr
!= itrEnd
; ++itr
)
1529 for (const auto& rIter
: v
)
1530 maNamedDBs
.erase(rIter
);
1532 maAnonDBs
.deleteOnTab(nTab
);
1535 void ScDBCollection::UpdateReference(UpdateRefMode eUpdateRefMode
,
1536 SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
1537 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
,
1538 SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
1540 ScDBData
* pData
= rDoc
.GetAnonymousDBData(nTab1
);
1543 if (nTab1
== nTab2
&& nDz
== 0)
1545 // Delete the database range, if some part of the reference became invalid.
1546 if (pData
->UpdateReference(&rDoc
, eUpdateRefMode
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
,
1547 nTab2
, nDx
, nDy
, nDz
))
1548 rDoc
.SetAnonymousDBData(nTab1
, nullptr);
1552 //this will perhaps break undo
1556 for (auto it
= maNamedDBs
.begin(); it
!= maNamedDBs
.end(); )
1558 // Delete the database range, if some part of the reference became invalid.
1559 if (it
->get()->UpdateReference(&rDoc
, eUpdateRefMode
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
,
1560 nTab2
, nDx
, nDy
, nDz
))
1561 it
= maNamedDBs
.erase(it
);
1565 for (auto it
= maAnonDBs
.begin(); it
!= maAnonDBs
.end(); )
1567 // Delete the database range, if some part of the reference became invalid.
1568 if (it
->get()->UpdateReference(&rDoc
, eUpdateRefMode
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
,
1569 nTab2
, nDx
, nDy
, nDz
))
1570 it
= maAnonDBs
.erase(it
);
1576 void ScDBCollection::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
)
1578 UpdateMoveTabFunc
func(nOldPos
, nNewPos
);
1579 for_each(maNamedDBs
.begin(), maNamedDBs
.end(), func
);
1580 for_each(maAnonDBs
.begin(), maAnonDBs
.end(), func
);
1583 void ScDBCollection::CopyToTable(SCTAB nOldPos
, SCTAB nNewPos
)
1585 // Create temporary copy of pointers to not insert in a set we are
1587 std::vector
<const ScDBData
*> aTemp
;
1588 aTemp
.reserve( maNamedDBs
.size());
1589 for (const auto& rxNamedDB
: maNamedDBs
)
1591 if (rxNamedDB
->GetTab() != nOldPos
)
1593 aTemp
.emplace_back( rxNamedDB
.get());
1595 for (const auto& rxNamedDB
: aTemp
)
1597 const OUString
newName( lcl_IncrementNumberInNamedRange( maNamedDBs
, rxNamedDB
->GetName()));
1598 std::unique_ptr
<ScDBData
> pDataCopy
= std::make_unique
<ScDBData
>(newName
, *rxNamedDB
);
1599 pDataCopy
->UpdateMoveTab(nOldPos
, nNewPos
);
1600 pDataCopy
->SetIndex(0);
1601 (void)maNamedDBs
.insert(std::move(pDataCopy
));
1605 ScDBData
* ScDBCollection::GetDBNearCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
1607 ScDBData
* pNearData
= nullptr;
1608 for (const auto& rxNamedDB
: maNamedDBs
)
1611 SCCOL nStartCol
, nEndCol
;
1612 SCROW nStartRow
, nEndRow
;
1613 rxNamedDB
->GetArea( nAreaTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
1614 if ( nTab
== nAreaTab
&& nCol
+1 >= nStartCol
&& nCol
<= nEndCol
+1 &&
1615 nRow
+1 >= nStartRow
&& nRow
<= nEndRow
+1 )
1617 if ( nCol
< nStartCol
|| nCol
> nEndCol
|| nRow
< nStartRow
|| nRow
> nEndRow
)
1620 pNearData
= rxNamedDB
.get(); // remember first adjacent area
1623 return rxNamedDB
.get(); // not "unbenannt"/"unnamed" and cursor within
1627 return pNearData
; // adjacent, if no direct hit
1628 return rDoc
.GetAnonymousDBData(nTab
); // "unbenannt"/"unnamed" only if nothing else
1631 std::vector
<ScDBData
*> ScDBCollection::GetAllDBsFromTab(SCTAB nTab
)
1633 std::vector
<ScDBData
*> pTabData
;
1634 for (const auto& rxNamedDB
: maNamedDBs
)
1636 if (rxNamedDB
->GetTab() == nTab
)
1637 pTabData
.emplace_back(rxNamedDB
.get());
1639 auto pAnonDBData
= rDoc
.GetAnonymousDBData(nTab
);
1641 pTabData
.emplace_back(pAnonDBData
);
1645 bool ScDBCollection::empty() const
1647 return maNamedDBs
.empty() && maAnonDBs
.empty();
1650 bool ScDBCollection::operator== (const ScDBCollection
& r
) const
1652 return maNamedDBs
== r
.maNamedDBs
&& maAnonDBs
== r
.maAnonDBs
&&
1653 nEntryIndex
== r
.nEntryIndex
&& &rDoc
== &r
.rDoc
&& aRefreshHandler
== r
.aRefreshHandler
;
1656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */