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/.
11 #include <document.hxx>
12 #include <clipcontext.hxx>
13 #include <clipparam.hxx>
15 #include <tokenarray.hxx>
16 #include <listenercontext.hxx>
17 #include <tokenstringcontext.hxx>
18 #include <poolhelp.hxx>
19 #include <cellvalues.hxx>
20 #include <docpool.hxx>
21 #include <columniterator.hxx>
23 #include <refupdatecontext.hxx>
24 #include <sal/log.hxx>
25 #include <svx/DocumentColorHelper.hxx>
26 #include <scitems.hxx>
27 #include <datamapper.hxx>
29 #include <bcaslot.hxx>
30 #include <broadcast.hxx>
32 // Add totally brand-new methods to this source file.
34 bool ScDocument::IsMerged( const ScAddress
& rPos
) const
36 const ScTable
* pTab
= FetchTable(rPos
.Tab());
40 return pTab
->IsMerged(rPos
.Col(), rPos
.Row());
43 sc::MultiDataCellState
ScDocument::HasMultipleDataCells( const ScRange
& rRange
) const
45 if (rRange
.aStart
.Tab() != rRange
.aEnd
.Tab())
46 // Currently we only support a single-sheet range.
47 return sc::MultiDataCellState();
49 const ScTable
* pTab
= FetchTable(rRange
.aStart
.Tab());
51 return sc::MultiDataCellState(sc::MultiDataCellState::Empty
);
53 const ScAddress
& s
= rRange
.aStart
;
54 const ScAddress
& e
= rRange
.aEnd
;
55 return pTab
->HasMultipleDataCells(s
.Col(), s
.Row(), e
.Col(), e
.Row());
58 void ScDocument::DeleteBeforeCopyFromClip(
59 sc::CopyFromClipContext
& rCxt
, const ScMarkData
& rMark
, sc::ColumnSpanSet
& rBroadcastSpans
)
62 const TableContainer
& rClipTabs
= rCxt
.getClipDoc()->maTabs
;
63 SCTAB nClipTabCount
= rClipTabs
.size();
65 for (SCTAB nTab
= rCxt
.getTabStart(); nTab
<= rCxt
.getTabEnd(); ++nTab
)
67 ScTable
* pTab
= FetchTable(nTab
);
71 if (!rMark
.GetTableSelect(nTab
))
74 while (!rClipTabs
[nClipTab
])
75 nClipTab
= (nClipTab
+1) % nClipTabCount
;
77 pTab
->DeleteBeforeCopyFromClip(rCxt
, *rClipTabs
[nClipTab
], rBroadcastSpans
);
79 nClipTab
= (nClipTab
+1) % nClipTabCount
;
83 bool ScDocument::CopyOneCellFromClip(
84 sc::CopyFromClipContext
& rCxt
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
86 ScDocument
* pClipDoc
= rCxt
.getClipDoc();
87 if (pClipDoc
->GetClipParam().mbCutMode
)
88 // We don't handle cut and paste or moving of cells here.
91 ScRange aClipRange
= pClipDoc
->GetClipParam().getWholeRange();
92 if (aClipRange
.aStart
.Row() != aClipRange
.aEnd
.Row())
93 // The source is not really a single row. Bail out.
96 SCCOL nSrcColSize
= aClipRange
.aEnd
.Col() - aClipRange
.aStart
.Col() + 1;
97 SCCOL nDestColSize
= nCol2
- nCol1
+ 1;
98 if (nDestColSize
< nSrcColSize
)
101 if (pClipDoc
->maTabs
.size() > 1)
102 // Copying from multiple source sheets is not handled here.
105 ScAddress aSrcPos
= aClipRange
.aStart
;
107 for (SCCOL nCol
= aClipRange
.aStart
.Col(); nCol
<= aClipRange
.aEnd
.Col(); ++nCol
)
109 ScAddress aTestPos
= aSrcPos
;
110 aTestPos
.SetCol(nCol
);
111 if (pClipDoc
->IsMerged(aTestPos
))
112 // We don't handle merged source cell for this.
116 ScTable
* pSrcTab
= pClipDoc
->FetchTable(aSrcPos
.Tab());
120 rCxt
.setSingleCellColumnSize(nSrcColSize
);
122 for (SCCOL nColOffset
= 0; nColOffset
< nSrcColSize
; ++nColOffset
, aSrcPos
.IncCol())
124 const ScPatternAttr
* pAttr
= pClipDoc
->GetPattern(aSrcPos
);
125 rCxt
.setSingleCellPattern(nColOffset
, pAttr
);
127 if ((rCxt
.getInsertFlag() & (InsertDeleteFlags::NOTE
| InsertDeleteFlags::ADDNOTES
)) != InsertDeleteFlags::NONE
)
128 rCxt
.setSingleCellNote(nColOffset
, pClipDoc
->GetNote(aSrcPos
));
130 if ((rCxt
.getInsertFlag() & InsertDeleteFlags::SPARKLINES
) != InsertDeleteFlags::NONE
)
131 rCxt
.setSingleSparkline(nColOffset
, pClipDoc
->GetSparkline(aSrcPos
));
133 ScColumn
* pSrcCol
= pSrcTab
->FetchColumn(aSrcPos
.Col());
135 // Determine the script type of the copied single cell.
136 pSrcCol
->UpdateScriptTypes(aSrcPos
.Row(), aSrcPos
.Row());
137 rCxt
.setSingleCell(aSrcPos
, *pSrcCol
);
140 // All good. Proceed with the pasting.
142 SCTAB nTabEnd
= rCxt
.getTabEnd();
143 for (SCTAB i
= rCxt
.getTabStart(); i
<= nTabEnd
&& i
< GetTableCount(); ++i
)
145 maTabs
[i
]->CopyOneCellFromClip(rCxt
, nCol1
, nRow1
, nCol2
, nRow2
, aClipRange
.aStart
.Row(), pSrcTab
);
148 sc::RefUpdateContext
aRefCxt(*this);
149 aRefCxt
.maRange
= ScRange(nCol1
, nRow1
, rCxt
.getTabStart(), nCol2
, nRow2
, nTabEnd
);
150 aRefCxt
.mnColDelta
= nCol1
- aSrcPos
.Col();
151 aRefCxt
.mnRowDelta
= nRow1
- aSrcPos
.Row();
152 aRefCxt
.mnTabDelta
= rCxt
.getTabStart() - aSrcPos
.Tab();
153 // Only Copy&Paste, for Cut&Paste we already bailed out early.
154 aRefCxt
.meMode
= URM_COPY
;
155 UpdateReference(aRefCxt
, rCxt
.getUndoDoc(), false);
160 void ScDocument::SetValues( const ScAddress
& rPos
, const std::vector
<double>& rVals
)
162 ScTable
* pTab
= FetchTable(rPos
.Tab());
166 pTab
->SetValues(rPos
.Col(), rPos
.Row(), rVals
);
169 void ScDocument::TransferCellValuesTo( const ScAddress
& rTopPos
, size_t nLen
, sc::CellValues
& rDest
)
171 ScTable
* pTab
= FetchTable(rTopPos
.Tab());
175 pTab
->TransferCellValuesTo(rTopPos
.Col(), rTopPos
.Row(), nLen
, rDest
);
178 void ScDocument::CopyCellValuesFrom( const ScAddress
& rTopPos
, const sc::CellValues
& rSrc
)
180 ScTable
* pTab
= FetchTable(rTopPos
.Tab());
184 pTab
->CopyCellValuesFrom(rTopPos
.Col(), rTopPos
.Row(), rSrc
);
187 std::set
<Color
> ScDocument::GetDocColors()
189 std::set
<Color
> aDocColors
;
190 ScDocumentPool
*pPool
= GetPool();
192 svx::DocumentColorHelper::queryColors
<SvxBrushItem
>(ATTR_BACKGROUND
, pPool
, aDocColors
);
193 svx::DocumentColorHelper::queryColors
<SvxColorItem
>(ATTR_FONT_COLOR
, pPool
, aDocColors
);
198 void ScDocument::SetCalcConfig( const ScCalcConfig
& rConfig
)
200 ScMutationGuard
aGuard(*this, ScMutationGuardFlags::CORE
);
201 maCalcConfig
= rConfig
;
204 void ScDocument::ConvertFormulaToValue( const ScRange
& rRange
, sc::TableValues
* pUndo
)
206 sc::EndListeningContext
aCxt(*this);
208 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
210 ScTable
* pTab
= FetchTable(nTab
);
214 pTab
->ConvertFormulaToValue(
215 aCxt
, rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row(),
219 aCxt
.purgeEmptyBroadcasters();
222 void ScDocument::SwapNonEmpty( sc::TableValues
& rValues
)
224 const ScRange
& rRange
= rValues
.getRange();
225 if (!rRange
.IsValid())
228 const auto pPosSet
= std::make_shared
<sc::ColumnBlockPositionSet
>(*this);
229 sc::StartListeningContext
aStartCxt(*this, pPosSet
);
230 sc::EndListeningContext
aEndCxt(*this, pPosSet
);
232 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
234 ScTable
* pTab
= FetchTable(nTab
);
238 pTab
->SwapNonEmpty(rValues
, aStartCxt
, aEndCxt
);
241 aEndCxt
.purgeEmptyBroadcasters();
244 void ScDocument::PreprocessAllRangeNamesUpdate( const std::map
<OUString
, ScRangeName
>& rRangeMap
)
246 // Update all existing names with new names.
247 // The prerequisites are that the name dialog preserves ScRangeData index
248 // for changes and does not reuse free index slots for new names.
249 // ScDocument::SetAllRangeNames() hereafter then will replace the
250 // ScRangeName containers of ScRangeData instances with empty
251 // ScRangeData::maNewName.
252 std::map
<OUString
, ScRangeName
*> aRangeNameMap
;
253 GetRangeNameMap( aRangeNameMap
);
254 for (const auto& itTab
: aRangeNameMap
)
256 ScRangeName
* pOldRangeNames
= itTab
.second
;
260 const auto itNewTab( rRangeMap
.find( itTab
.first
));
261 if (itNewTab
== rRangeMap
.end())
264 const ScRangeName
& rNewRangeNames
= itNewTab
->second
;
266 for (const auto& rEntry
: *pOldRangeNames
)
268 ScRangeData
* pOldData
= rEntry
.second
.get();
272 const ScRangeData
* pNewData
= rNewRangeNames
.findByIndex( pOldData
->GetIndex());
274 pOldData
->SetNewName( pNewData
->GetName());
278 sc::EndListeningContext
aEndListenCxt(*this);
279 sc::CompileFormulaContext
aCompileCxt(*this);
281 for (const auto& rxTab
: maTabs
)
283 ScTable
* p
= rxTab
.get();
284 p
->PreprocessRangeNameUpdate(aEndListenCxt
, aCompileCxt
);
288 void ScDocument::PreprocessRangeNameUpdate()
290 sc::EndListeningContext
aEndListenCxt(*this);
291 sc::CompileFormulaContext
aCompileCxt(*this);
293 for (const auto& rxTab
: maTabs
)
295 ScTable
* p
= rxTab
.get();
296 p
->PreprocessRangeNameUpdate(aEndListenCxt
, aCompileCxt
);
300 void ScDocument::PreprocessDBDataUpdate()
302 sc::EndListeningContext
aEndListenCxt(*this);
303 sc::CompileFormulaContext
aCompileCxt(*this);
305 for (const auto& rxTab
: maTabs
)
307 ScTable
* p
= rxTab
.get();
308 p
->PreprocessDBDataUpdate(aEndListenCxt
, aCompileCxt
);
312 void ScDocument::CompileHybridFormula()
314 sc::StartListeningContext
aStartListenCxt(*this);
315 sc::CompileFormulaContext
aCompileCxt(*this);
316 for (const auto& rxTab
: maTabs
)
318 ScTable
* p
= rxTab
.get();
319 p
->CompileHybridFormula(aStartListenCxt
, aCompileCxt
);
323 void ScDocument::SharePooledResources( const ScDocument
* pSrcDoc
)
325 ScMutationGuard
aGuard(*this, ScMutationGuardFlags::CORE
);
326 mxPoolHelper
= pSrcDoc
->mxPoolHelper
;
327 mpCellStringPool
= pSrcDoc
->mpCellStringPool
;
329 // force lazy creation/existence in source document *before* sharing
330 pSrcDoc
->getCellAttributeHelper();
331 mpCellAttributeHelper
= pSrcDoc
->mpCellAttributeHelper
;
334 void ScDocument::UpdateScriptTypes( const ScAddress
& rPos
, SCCOL nColSize
, SCROW nRowSize
)
336 ScTable
* pTab
= FetchTable(rPos
.Tab());
340 pTab
->UpdateScriptTypes(rPos
.Col(), rPos
.Row(), rPos
.Col()+nColSize
-1, rPos
.Row()+nRowSize
-1);
343 bool ScDocument::HasUniformRowHeight( SCTAB nTab
, SCROW nRow1
, SCROW nRow2
) const
345 const ScTable
* pTab
= FetchTable(nTab
);
349 return pTab
->HasUniformRowHeight(nRow1
, nRow2
);
352 void ScDocument::UnshareFormulaCells( SCTAB nTab
, SCCOL nCol
, std::vector
<SCROW
>& rRows
)
354 ScTable
* pTab
= FetchTable(nTab
);
358 pTab
->UnshareFormulaCells(nCol
, rRows
);
361 void ScDocument::RegroupFormulaCells( SCTAB nTab
, SCCOL nCol
)
363 ScTable
* pTab
= FetchTable(nTab
);
367 pTab
->RegroupFormulaCells(nCol
);
370 void ScDocument::RegroupFormulaCells( const ScRange
& rRange
)
372 for( SCTAB tab
= rRange
.aStart
.Tab(); tab
<= rRange
.aEnd
.Tab(); ++tab
)
373 for( SCCOL col
= rRange
.aStart
.Col(); col
<= rRange
.aEnd
.Col(); ++col
)
374 RegroupFormulaCells( tab
, col
);
377 void ScDocument::DelayFormulaGrouping( bool delay
)
381 if( !pDelayedFormulaGrouping
)
382 pDelayedFormulaGrouping
.reset( new ScRange( ScAddress::INITIALIZE_INVALID
));
386 if( pDelayedFormulaGrouping
&& pDelayedFormulaGrouping
->IsValid())
387 RegroupFormulaCells( *pDelayedFormulaGrouping
);
388 pDelayedFormulaGrouping
.reset();
392 void ScDocument::AddDelayedFormulaGroupingCell( const ScFormulaCell
* cell
)
394 if( !pDelayedFormulaGrouping
->Contains( cell
->aPos
))
395 pDelayedFormulaGrouping
->ExtendTo( ScRange(cell
->aPos
) );
398 void ScDocument::EnableDelayStartListeningFormulaCells( ScColumn
* column
, bool delay
)
402 if( pDelayedStartListeningFormulaCells
.find( column
) == pDelayedStartListeningFormulaCells
.end())
403 pDelayedStartListeningFormulaCells
[ column
] = std::pair
<SCROW
, SCROW
>( -1, -1 );
407 auto it
= pDelayedStartListeningFormulaCells
.find( column
);
408 if( it
!= pDelayedStartListeningFormulaCells
.end())
410 if( it
->second
.first
!= -1 )
412 const auto pPosSet
= std::make_shared
<sc::ColumnBlockPositionSet
>(*this);
413 sc::StartListeningContext
aStartCxt(*this, pPosSet
);
414 sc::EndListeningContext
aEndCxt(*this, pPosSet
);
415 column
->StartListeningFormulaCells(aStartCxt
, aEndCxt
, it
->second
.first
, it
->second
.second
);
417 pDelayedStartListeningFormulaCells
.erase( it
);
422 bool ScDocument::IsEnabledDelayStartListeningFormulaCells( ScColumn
* column
) const
424 return pDelayedStartListeningFormulaCells
.find( column
) != pDelayedStartListeningFormulaCells
.end();
427 bool ScDocument::CanDelayStartListeningFormulaCells( ScColumn
* column
, SCROW row1
, SCROW row2
)
429 auto it
= pDelayedStartListeningFormulaCells
.find( column
);
430 if( it
== pDelayedStartListeningFormulaCells
.end())
431 return false; // not enabled
432 if( it
->second
.first
== -1 && it
->second
.second
== -1 ) // uninitialized
433 pDelayedStartListeningFormulaCells
[ column
] = std::make_pair( row1
, row2
);
436 if( row1
> it
->second
.second
+ 1 || row2
< it
->second
.first
- 1 )
437 { // two non-adjacent ranges, just bail out
440 it
->second
.first
= std::min( it
->second
.first
, row1
);
441 it
->second
.second
= std::max( it
->second
.second
, row2
);
446 void ScDocument::EnableDelayDeletingBroadcasters( bool set
)
448 if( bDelayedDeletingBroadcasters
== set
)
450 bDelayedDeletingBroadcasters
= set
;
451 if( !bDelayedDeletingBroadcasters
)
453 for (auto& rxTab
: maTabs
)
455 rxTab
->DeleteEmptyBroadcasters();
459 bool ScDocument::HasFormulaCell( const ScRange
& rRange
) const
461 if (!rRange
.IsValid())
464 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
466 const ScTable
* pTab
= FetchTable(nTab
);
470 if (pTab
->HasFormulaCell(rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row()))
477 void ScDocument::EndListeningIntersectedGroup(
478 sc::EndListeningContext
& rCxt
, const ScAddress
& rPos
, std::vector
<ScAddress
>* pGroupPos
)
480 ScTable
* pTab
= FetchTable(rPos
.Tab());
484 pTab
->EndListeningIntersectedGroup(rCxt
, rPos
.Col(), rPos
.Row(), pGroupPos
);
487 void ScDocument::EndListeningIntersectedGroups(
488 sc::EndListeningContext
& rCxt
, const ScRange
& rRange
, std::vector
<ScAddress
>* pGroupPos
)
490 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
492 ScTable
* pTab
= FetchTable(nTab
);
496 pTab
->EndListeningIntersectedGroups(
497 rCxt
, rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row(),
502 void ScDocument::EndListeningGroups( const std::vector
<ScAddress
>& rPosArray
)
504 sc::EndListeningContext
aCxt(*this);
505 for (const ScAddress
& rPos
: rPosArray
)
507 ScTable
* pTab
= FetchTable(rPos
.Tab());
511 pTab
->EndListeningGroup(aCxt
, rPos
.Col(), rPos
.Row());
514 aCxt
.purgeEmptyBroadcasters();
517 void ScDocument::SetNeedsListeningGroups( const std::vector
<ScAddress
>& rPosArray
)
519 for (const ScAddress
& rPos
: rPosArray
)
521 ScTable
* pTab
= FetchTable(rPos
.Tab());
525 pTab
->SetNeedsListeningGroup(rPos
.Col(), rPos
.Row());
531 class StartNeededListenersHandler
533 std::shared_ptr
<sc::StartListeningContext
> mpCxt
;
535 explicit StartNeededListenersHandler( ScDocument
& rDoc
) : mpCxt(std::make_shared
<sc::StartListeningContext
>(rDoc
)) {}
536 explicit StartNeededListenersHandler( ScDocument
& rDoc
, const std::shared_ptr
<const sc::ColumnSet
>& rpColSet
) :
537 mpCxt(std::make_shared
<sc::StartListeningContext
>(rDoc
))
539 mpCxt
->setColumnSet( rpColSet
);
542 void operator() (const ScTableUniquePtr
& p
)
545 p
->StartListeners(*mpCxt
, false);
551 void ScDocument::StartNeededListeners()
553 std::for_each(maTabs
.begin(), maTabs
.end(), StartNeededListenersHandler(*this));
556 void ScDocument::StartNeededListeners( const std::shared_ptr
<const sc::ColumnSet
>& rpColSet
)
558 std::for_each(maTabs
.begin(), maTabs
.end(), StartNeededListenersHandler(*this, rpColSet
));
561 void ScDocument::StartAllListeners( const ScRange
& rRange
)
563 if (IsClipOrUndo() || GetNoListening())
566 const auto pPosSet
= std::make_shared
<sc::ColumnBlockPositionSet
>(*this);
567 sc::StartListeningContext
aStartCxt(*this, pPosSet
);
568 sc::EndListeningContext
aEndCxt(*this, pPosSet
);
570 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
572 ScTable
* pTab
= FetchTable(nTab
);
576 pTab
->StartListeningFormulaCells(
578 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row());
582 void ScDocument::finalizeOutlineImport()
584 for (const auto& rxTab
: maTabs
)
586 ScTable
* p
= rxTab
.get();
587 p
->finalizeOutlineImport();
591 bool ScDocument::FindRangeNamesReferencingSheet( sc::UpdatedRangeNames
& rIndexes
,
592 SCTAB nTokenTab
, const sal_uInt16 nTokenIndex
,
593 SCTAB nGlobalRefTab
, SCTAB nLocalRefTab
, SCTAB nOldTokenTab
, SCTAB nOldTokenTabReplacement
,
594 bool bSameDoc
, int nRecursion
) const
598 SAL_WARN("sc.core", "ScDocument::FindRangeNamesReferencingSheet - nTokenTab < -1 : " <<
599 nTokenTab
<< ", nTokenIndex " << nTokenIndex
<< " Fix the creator!");
600 #if OSL_DEBUG_LEVEL > 0
601 const ScRangeData
* pData
= FindRangeNameBySheetAndIndex( nTokenTab
, nTokenIndex
);
602 SAL_WARN_IF( pData
, "sc.core", "ScDocument::FindRangeNamesReferencingSheet - named expression is: " << pData
->GetName());
606 SCTAB nRefTab
= nGlobalRefTab
;
607 if (nTokenTab
== nOldTokenTab
)
609 nTokenTab
= nOldTokenTabReplacement
;
610 nRefTab
= nLocalRefTab
;
612 else if (nTokenTab
== nOldTokenTabReplacement
)
614 nRefTab
= nLocalRefTab
;
617 if (rIndexes
.isNameUpdated( nTokenTab
, nTokenIndex
))
620 ScRangeData
* pData
= FindRangeNameBySheetAndIndex( nTokenTab
, nTokenIndex
);
624 ScTokenArray
* pCode
= pData
->GetCode();
628 bool bRef
= !bSameDoc
; // include every name used when copying to other doc
629 if (nRecursion
< 126) // whatever... 42*3
631 formula::FormulaTokenArrayPlainIterator
aIter(*pCode
);
632 for (const formula::FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
634 if (p
->GetOpCode() == ocName
)
636 bRef
|= FindRangeNamesReferencingSheet( rIndexes
, p
->GetSheet(), p
->GetIndex(),
637 nGlobalRefTab
, nLocalRefTab
, nOldTokenTab
, nOldTokenTabReplacement
, bSameDoc
, nRecursion
+1);
644 SCTAB nPosTab
= pData
->GetPos().Tab();
645 if (nPosTab
== nOldTokenTab
)
646 nPosTab
= nOldTokenTabReplacement
;
647 bRef
= pCode
->ReferencesSheet( nRefTab
, nPosTab
);
650 rIndexes
.setUpdatedName( nTokenTab
, nTokenIndex
);
657 enum MightReferenceSheet
665 MightReferenceSheet
mightRangeNameReferenceSheet( ScRangeData
* pData
, SCTAB nRefTab
)
667 ScTokenArray
* pCode
= pData
->GetCode();
669 return MightReferenceSheet::NONE
;
671 formula::FormulaTokenArrayPlainIterator
aIter(*pCode
);
672 for (const formula::FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
674 if (p
->GetOpCode() == ocName
)
675 return MightReferenceSheet::NAME
;
678 return pCode
->ReferencesSheet( nRefTab
, pData
->GetPos().Tab()) ?
679 MightReferenceSheet::CODE
: MightReferenceSheet::NONE
;
682 ScRangeData
* copyRangeName( const ScRangeData
* pOldRangeData
, ScDocument
& rNewDoc
, const ScDocument
& rOldDoc
,
683 const ScAddress
& rNewPos
, const ScAddress
& rOldPos
, bool bGlobalNamesToLocal
,
684 SCTAB nOldSheet
, const SCTAB nNewSheet
, bool bSameDoc
)
686 ScAddress
aRangePos( pOldRangeData
->GetPos());
688 aRangePos
.SetTab( nNewSheet
);
689 ScRangeData
* pRangeData
= new ScRangeData(*pOldRangeData
, &rNewDoc
, &aRangePos
);
690 pRangeData
->SetIndex(0); // needed for insert to assign a new index
691 ScTokenArray
* pRangeNameToken
= pRangeData
->GetCode();
692 if (bSameDoc
&& nNewSheet
>= 0)
694 if (bGlobalNamesToLocal
&& nOldSheet
< 0)
696 nOldSheet
= rOldPos
.Tab();
697 if (rNewPos
.Tab() <= nOldSheet
)
698 // Sheet was inserted before and references already updated.
701 pRangeNameToken
->AdjustSheetLocalNameReferences( nOldSheet
, nNewSheet
);
705 pRangeNameToken
->ReadjustAbsolute3DReferences(rOldDoc
, rNewDoc
, pRangeData
->GetPos(), true);
706 pRangeNameToken
->AdjustAbsoluteRefs(rOldDoc
, rOldPos
, rNewPos
, true);
711 bInserted
= rNewDoc
.GetRangeName()->insert(pRangeData
);
713 bInserted
= rNewDoc
.GetRangeName(nNewSheet
)->insert(pRangeData
);
715 return bInserted
? pRangeData
: nullptr;
723 SheetIndex( SCTAB nSheet
, sal_uInt16 nIndex
) : mnSheet(nSheet
< -1 ? -1 : nSheet
), mnIndex(nIndex
) {}
724 bool operator<( const SheetIndex
& r
) const
726 // Ascending order sheet, index
727 if (mnSheet
< r
.mnSheet
)
729 if (mnSheet
== r
.mnSheet
)
730 return mnIndex
< r
.mnIndex
;
734 typedef std::map
< SheetIndex
, SheetIndex
> SheetIndexMap
;
736 ScRangeData
* copyRangeNames( SheetIndexMap
& rSheetIndexMap
, std::vector
<ScRangeData
*>& rRangeDataVec
,
737 const sc::UpdatedRangeNames
& rReferencingNames
, SCTAB nTab
,
738 const ScRangeData
* pOldRangeData
, ScDocument
& rNewDoc
, const ScDocument
& rOldDoc
,
739 const ScAddress
& rNewPos
, const ScAddress
& rOldPos
, bool bGlobalNamesToLocal
,
740 const SCTAB nOldSheet
, const SCTAB nNewSheet
, bool bSameDoc
)
742 ScRangeData
* pRangeData
= nullptr;
743 const ScRangeName
* pOldRangeName
= (nTab
< 0 ? rOldDoc
.GetRangeName() : rOldDoc
.GetRangeName(nTab
));
746 const ScRangeName
* pNewRangeName
= (nNewSheet
< 0 ? rNewDoc
.GetRangeName() : rNewDoc
.GetRangeName(nNewSheet
));
747 sc::UpdatedRangeNames::NameIndicesType
aSet( rReferencingNames
.getUpdatedNames(nTab
));
748 for (auto const & rIndex
: aSet
)
750 const ScRangeData
* pCopyData
= pOldRangeName
->findByIndex(rIndex
);
753 // Match the original pOldRangeData to adapt the current
754 // token's values later. For that no check for an already
755 // copied name is needed as we only enter here if there was
757 if (pCopyData
== pOldRangeData
)
759 pRangeData
= copyRangeName( pCopyData
, rNewDoc
, rOldDoc
, rNewPos
, rOldPos
,
760 bGlobalNamesToLocal
, nOldSheet
, nNewSheet
, bSameDoc
);
763 rRangeDataVec
.push_back(pRangeData
);
764 rSheetIndexMap
.insert( std::make_pair( SheetIndex( nOldSheet
, pCopyData
->GetIndex()),
765 SheetIndex( nNewSheet
, pRangeData
->GetIndex())));
770 // First check if the name is already available as copy.
771 const ScRangeData
* pFoundData
= pNewRangeName
->findByUpperName( pCopyData
->GetUpperName());
774 // Just add the resulting sheet/index mapping.
775 rSheetIndexMap
.insert( std::make_pair( SheetIndex( nOldSheet
, pCopyData
->GetIndex()),
776 SheetIndex( nNewSheet
, pFoundData
->GetIndex())));
780 ScRangeData
* pTmpData
= copyRangeName( pCopyData
, rNewDoc
, rOldDoc
, rNewPos
, rOldPos
,
781 bGlobalNamesToLocal
, nOldSheet
, nNewSheet
, bSameDoc
);
784 rRangeDataVec
.push_back(pTmpData
);
785 rSheetIndexMap
.insert( std::make_pair( SheetIndex( nOldSheet
, pCopyData
->GetIndex()),
786 SheetIndex( nNewSheet
, pTmpData
->GetIndex())));
798 bool ScDocument::CopyAdjustRangeName( SCTAB
& rSheet
, sal_uInt16
& rIndex
, ScRangeData
*& rpRangeData
,
799 ScDocument
& rNewDoc
, const ScAddress
& rNewPos
, const ScAddress
& rOldPos
, const bool bGlobalNamesToLocal
,
800 const bool bUsedByFormula
) const
802 ScDocument
* pThis
= const_cast<ScDocument
*>(this);
803 const bool bSameDoc
= (rNewDoc
.GetPool() == pThis
->GetPool());
804 if (bSameDoc
&& ((rSheet
< 0 && !bGlobalNamesToLocal
) || (rSheet
>= 0
805 && (rSheet
!= rOldPos
.Tab() || (IsClipboard() && pThis
->IsCutMode())))))
806 // Same doc and global name, if not copied to local name, or
807 // sheet-local name on other sheet stays the same. Sheet-local on
808 // same sheet also in a clipboard cut&paste / move operation.
811 // Ensure we don't fiddle with the references until exit.
812 const SCTAB nOldSheet
= rSheet
;
813 const sal_uInt16 nOldIndex
= rIndex
;
815 SAL_WARN_IF( !bSameDoc
&& nOldSheet
>= 0 && nOldSheet
!= rOldPos
.Tab(),
816 "sc.core", "adjustCopyRangeName - sheet-local name was on other sheet in other document");
817 /* TODO: can we do something about that? e.g. loop over sheets? */
820 ScRangeData
* pOldRangeData
= nullptr;
822 // XXX bGlobalNamesToLocal is also a synonym for copied sheet.
823 bool bInsertingBefore
= (bGlobalNamesToLocal
&& bSameDoc
&& rNewPos
.Tab() <= rOldPos
.Tab());
825 // The Tab where an old local name is to be found or that a global name
826 // references. May differ below from nOldSheet if a sheet was inserted
827 // before the old position. Global names and local names other than on the
828 // old sheet or new sheet are already updated, local names on the old sheet
829 // or inserted sheet will be updated later. Confusing stuff. Watch out.
830 SCTAB nOldTab
= (nOldSheet
< 0 ? rOldPos
.Tab() : nOldSheet
);
831 if (bInsertingBefore
)
832 // Sheet was already inserted before old position.
835 // Search the name of the RangeName.
838 const ScRangeName
* pNames
= GetRangeName(nOldTab
);
839 pOldRangeData
= pNames
? pNames
->findByIndex(nOldIndex
) : nullptr;
841 return false; // might be an error in the formula array
842 aRangeName
= pOldRangeData
->GetUpperName();
846 pOldRangeData
= GetRangeName()->findByIndex(nOldIndex
);
848 return false; // might be an error in the formula array
849 aRangeName
= pOldRangeData
->GetUpperName();
852 // Find corresponding range name in new document.
853 // First search for local range name then global range names.
854 SCTAB nNewSheet
= rNewPos
.Tab();
855 ScRangeName
* pNewNames
= rNewDoc
.GetRangeName(nNewSheet
);
856 // Search local range names.
859 rpRangeData
= pNewNames
->findByUpperName(aRangeName
);
861 // Search global range names.
862 if (!rpRangeData
&& !bGlobalNamesToLocal
)
865 pNewNames
= rNewDoc
.GetRangeName();
867 rpRangeData
= pNewNames
->findByUpperName(aRangeName
);
869 // If no range name was found copy it.
872 // Do not copy global name if it doesn't reference sheet or is not used
873 // by a formula copied to another document.
874 bool bEarlyBailOut
= (nOldSheet
< 0 && (bSameDoc
|| !bUsedByFormula
));
875 MightReferenceSheet eMightReference
= mightRangeNameReferenceSheet( pOldRangeData
, nOldTab
);
876 if (bEarlyBailOut
&& eMightReference
== MightReferenceSheet::NONE
)
879 if (eMightReference
== MightReferenceSheet::NAME
)
881 // Name these to clarify what is passed where.
882 const SCTAB nGlobalRefTab
= nOldTab
;
883 const SCTAB nLocalRefTab
= (bInsertingBefore
? nOldTab
-1 : nOldTab
);
884 const SCTAB nOldTokenTab
= (nOldSheet
< 0 ? (bInsertingBefore
? nOldTab
-1 : nOldTab
) : nOldSheet
);
885 const SCTAB nOldTokenTabReplacement
= nOldTab
;
886 sc::UpdatedRangeNames aReferencingNames
;
887 FindRangeNamesReferencingSheet( aReferencingNames
, nOldSheet
, nOldIndex
,
888 nGlobalRefTab
, nLocalRefTab
, nOldTokenTab
, nOldTokenTabReplacement
, bSameDoc
, 0);
889 if (bEarlyBailOut
&& aReferencingNames
.isEmpty(-1) && aReferencingNames
.isEmpty(nOldTokenTabReplacement
))
892 SheetIndexMap aSheetIndexMap
;
893 std::vector
<ScRangeData
*> aRangeDataVec
;
894 if (!aReferencingNames
.isEmpty(nOldTokenTabReplacement
))
896 const SCTAB nTmpOldSheet
= (nOldSheet
< 0 ? nOldTab
: nOldSheet
);
897 nNewSheet
= rNewPos
.Tab();
898 rpRangeData
= copyRangeNames( aSheetIndexMap
, aRangeDataVec
, aReferencingNames
, nOldTab
,
899 pOldRangeData
, rNewDoc
, *this, rNewPos
, rOldPos
,
900 bGlobalNamesToLocal
, nTmpOldSheet
, nNewSheet
, bSameDoc
);
902 if ((bGlobalNamesToLocal
|| !bSameDoc
) && !aReferencingNames
.isEmpty(-1))
904 const SCTAB nTmpOldSheet
= -1;
905 const SCTAB nTmpNewSheet
= (bGlobalNamesToLocal
? rNewPos
.Tab() : -1);
906 ScRangeData
* pTmpData
= copyRangeNames( aSheetIndexMap
, aRangeDataVec
, aReferencingNames
, -1,
907 pOldRangeData
, rNewDoc
, *this, rNewPos
, rOldPos
,
908 bGlobalNamesToLocal
, nTmpOldSheet
, nTmpNewSheet
, bSameDoc
);
911 rpRangeData
= pTmpData
;
912 nNewSheet
= nTmpNewSheet
;
916 // Adjust copied nested names to new sheet/index.
917 for (auto & iRD
: aRangeDataVec
)
919 ScTokenArray
* pCode
= iRD
->GetCode();
922 formula::FormulaTokenArrayPlainIterator
aIter(*pCode
);
923 for (formula::FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
925 if (p
->GetOpCode() == ocName
)
927 auto it
= aSheetIndexMap
.find( SheetIndex( p
->GetSheet(), p
->GetIndex()));
928 if (it
!= aSheetIndexMap
.end())
930 p
->SetSheet( it
->second
.mnSheet
);
931 p
->SetIndex( it
->second
.mnIndex
);
935 SAL_WARN("sc.core","adjustCopyRangeName - mapping to new name in other doc missing");
936 p
->SetIndex(0); // #NAME? error instead of arbitrary name.
945 nNewSheet
= ((nOldSheet
< 0 && !bGlobalNamesToLocal
) ? -1 : rNewPos
.Tab());
946 rpRangeData
= copyRangeName( pOldRangeData
, rNewDoc
, *this, rNewPos
, rOldPos
, bGlobalNamesToLocal
,
947 nOldSheet
, nNewSheet
, bSameDoc
);
950 if (rpRangeData
&& !rNewDoc
.IsClipOrUndo())
952 ScDocShell
* pDocSh
= rNewDoc
.GetDocumentShell();
954 pDocSh
->SetAreasChangedNeedBroadcast();
959 rIndex
= rpRangeData
? rpRangeData
->GetIndex() : 0; // 0 means not inserted
963 bool ScDocument::IsEditActionAllowed(
964 sc::EditAction eAction
, SCTAB nTab
, SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
) const
966 const ScTable
* pTab
= FetchTable(nTab
);
970 return pTab
->IsEditActionAllowed(eAction
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
973 bool ScDocument::IsEditActionAllowed(
974 sc::EditAction eAction
, const ScMarkData
& rMark
, SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
) const
976 return std::all_of(rMark
.begin(), rMark
.end(),
977 [this, &eAction
, &nStartCol
, &nStartRow
, &nEndCol
, &nEndRow
](const SCTAB
& rTab
)
978 { return IsEditActionAllowed(eAction
, rTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
); });
981 std::optional
<sc::ColumnIterator
> ScDocument::GetColumnIterator( SCTAB nTab
, SCCOL nCol
, SCROW nRow1
, SCROW nRow2
) const
983 const ScTable
* pTab
= FetchTable(nTab
);
987 return pTab
->GetColumnIterator(nCol
, nRow1
, nRow2
);
990 void ScDocument::CreateColumnIfNotExists( SCTAB nTab
, SCCOL nCol
)
992 ScTable
* pTab
= FetchTable(nTab
);
996 pTab
->CreateColumnIfNotExists(nCol
);
999 bool ScDocument::EnsureFormulaCellResults( const ScRange
& rRange
, bool bSkipRunning
)
1001 bool bAnyDirty
= false;
1002 for (SCTAB nTab
= rRange
.aStart
.Tab(); nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
1004 ScTable
* pTab
= FetchTable(nTab
);
1008 bool bRet
= pTab
->EnsureFormulaCellResults(
1009 rRange
.aStart
.Col(), rRange
.aStart
.Row(), rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), bSkipRunning
);
1010 bAnyDirty
= bAnyDirty
|| bRet
;
1016 sc::ExternalDataMapper
& ScDocument::GetExternalDataMapper()
1019 mpDataMapper
.reset(new sc::ExternalDataMapper(*this));
1021 return *mpDataMapper
;
1024 void ScDocument::StoreTabToCache(SCTAB nTab
, SvStream
& rStrm
) const
1026 const ScTable
* pTab
= FetchTable(nTab
);
1030 pTab
->StoreToCache(rStrm
);
1033 void ScDocument::RestoreTabFromCache(SCTAB nTab
, SvStream
& rStrm
)
1035 ScTable
* pTab
= FetchTable(nTab
);
1039 pTab
->RestoreFromCache(rStrm
);
1042 OString
ScDocument::dumpSheetGeomData(SCTAB nTab
, bool bColumns
, SheetGeomType eGeomType
)
1044 ScTable
* pTab
= FetchTable(nTab
);
1048 return pTab
->dumpSheetGeomData(bColumns
, eGeomType
);
1051 SCCOL
ScDocument::GetLOKFreezeCol(SCTAB nTab
) const
1053 const ScTable
* pTab
= FetchTable(nTab
);
1057 return pTab
->GetLOKFreezeCol();
1059 SCROW
ScDocument::GetLOKFreezeRow(SCTAB nTab
) const
1061 const ScTable
* pTab
= FetchTable(nTab
);
1065 return pTab
->GetLOKFreezeRow();
1068 bool ScDocument::SetLOKFreezeCol(SCCOL nFreezeCol
, SCTAB nTab
)
1070 ScTable
* pTab
= FetchTable(nTab
);
1074 return pTab
->SetLOKFreezeCol(nFreezeCol
);
1077 bool ScDocument::SetLOKFreezeRow(SCROW nFreezeRow
, SCTAB nTab
)
1079 ScTable
* pTab
= FetchTable(nTab
);
1083 return pTab
->SetLOKFreezeRow(nFreezeRow
);
1086 std::set
<SCCOL
> ScDocument::QueryColumnsWithFormulaCells( SCTAB nTab
) const
1088 const ScTable
* pTab
= FetchTable(nTab
);
1090 return std::set
<SCCOL
>{};
1092 return pTab
->QueryColumnsWithFormulaCells();
1095 void ScDocument::CheckIntegrity( SCTAB nTab
) const
1097 const ScTable
* pTab
= FetchTable(nTab
);
1101 pTab
->CheckIntegrity();
1104 sc::BroadcasterState
ScDocument::GetBroadcasterState() const
1106 sc::BroadcasterState aState
;
1108 for (const auto& xTab
: maTabs
)
1109 xTab
->CollectBroadcasterState(aState
);
1112 pBASM
->CollectBroadcasterState(aState
);
1117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */