Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / data / documen3.cxx
blob3c95015874c0c25a800b80204ce8bf5910aefc67
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/types.h>
21 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
22 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
23 #include <scitems.hxx>
24 #include <editeng/langitem.hxx>
25 #include <svl/srchitem.hxx>
26 #include <sfx2/linkmgr.hxx>
27 #include <sfx2/bindings.hxx>
28 #include <sfx2/viewsh.hxx>
29 #include <vcl/svapp.hxx>
30 #include <osl/thread.hxx>
31 #include <osl/diagnose.h>
32 #include <tools/duration.hxx>
33 #include <document.hxx>
34 #include <attrib.hxx>
35 #include <table.hxx>
36 #include <rangenam.hxx>
37 #include <dbdata.hxx>
38 #include <docpool.hxx>
39 #include <docsh.hxx>
40 #include <poolhelp.hxx>
41 #include <rangelst.hxx>
42 #include <chartlock.hxx>
43 #include <refupdat.hxx>
44 #include <docoptio.hxx>
45 #include <scmod.hxx>
46 #include <clipoptions.hxx>
47 #include <viewopti.hxx>
48 #include <scextopt.hxx>
49 #include <tablink.hxx>
50 #include <externalrefmgr.hxx>
51 #include <markdata.hxx>
52 #include <validat.hxx>
53 #include <dociter.hxx>
54 #include <detdata.hxx>
55 #include <inputopt.hxx>
56 #include <chartlis.hxx>
57 #include <sc.hrc>
58 #include <globstr.hrc>
59 #include <scresid.hxx>
60 #include <hints.hxx>
61 #include <dpobject.hxx>
62 #include <drwlayer.hxx>
63 #include <unoreflist.hxx>
64 #include <listenercalls.hxx>
65 #include <tabprotection.hxx>
66 #include <formulaparserpool.hxx>
67 #include <clipparam.hxx>
68 #include <sheetevents.hxx>
69 #include <queryentry.hxx>
70 #include <formulacell.hxx>
71 #include <refupdatecontext.hxx>
72 #include <scopetools.hxx>
73 #include <filterentries.hxx>
74 #include <queryparam.hxx>
75 #include <progress.hxx>
76 #include <globalnames.hxx>
77 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
78 #include <comphelper/lok.hxx>
79 #include <config_fuzzers.h>
80 #include <memory>
82 using namespace com::sun::star;
84 namespace {
86 void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSens)
88 if (bCaseSens)
90 std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseSensitive());
91 std::vector<ScTypedStrData>::iterator it =
92 std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseSensitive());
93 rStrings.erase(it, rStrings.end());
94 std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseSensitive());
96 else
98 std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseInsensitive());
99 std::vector<ScTypedStrData>::iterator it =
100 std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseInsensitive());
101 rStrings.erase(it, rStrings.end());
102 std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessSortCaseInsensitive());
104 if (std::any_of(rStrings.begin(), rStrings.end(),
105 [](ScTypedStrData& rString) { return rString.IsHiddenByFilter(); })) {
106 std::stable_sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessHiddenRows());
112 void ScDocument::GetAllTabRangeNames(ScRangeName::TabNameCopyMap& rNames) const
114 ScRangeName::TabNameCopyMap aNames;
115 for (SCTAB i = 0; i < GetTableCount(); ++i)
117 if (!maTabs[i])
118 // no more tables to iterate through.
119 break;
121 const ScRangeName* p = maTabs[i]->mpRangeName.get();
122 if (!p || p->empty())
123 // ignore empty ones.
124 continue;
126 aNames.emplace(i, p);
128 rNames.swap(aNames);
131 void ScDocument::SetAllRangeNames(const std::map<OUString, ScRangeName>& rRangeMap)
133 for (const auto& [rName, rRangeName] : rRangeMap)
135 if (rName == STR_GLOBAL_RANGE_NAME)
137 pRangeName.reset();
138 if (!rRangeName.empty())
139 pRangeName.reset( new ScRangeName( rRangeName ) );
141 else
143 SCTAB nTab;
144 bool bFound = GetTable(rName, nTab);
145 assert(bFound); (void)bFound; // fouled up?
146 if (rRangeName.empty())
147 SetRangeName( nTab, nullptr );
148 else
149 SetRangeName( nTab, std::unique_ptr<ScRangeName>(new ScRangeName( rRangeName )) );
154 void ScDocument::GetRangeNameMap(std::map<OUString, ScRangeName*>& aRangeNameMap)
156 for (SCTAB i = 0; i < GetTableCount(); ++i)
158 if (!maTabs[i])
159 continue;
160 ScRangeName* p = maTabs[i]->GetRangeName();
161 if (!p )
163 p = new ScRangeName();
164 SetRangeName(i, std::unique_ptr<ScRangeName>(p));
166 OUString aTableName = maTabs[i]->GetName();
167 aRangeNameMap.insert(std::pair<OUString, ScRangeName*>(aTableName,p));
169 if (!pRangeName)
171 pRangeName.reset(new ScRangeName());
173 aRangeNameMap.insert(std::pair<OUString, ScRangeName*>(STR_GLOBAL_RANGE_NAME, pRangeName.get()));
176 ScRangeName* ScDocument::GetRangeName(SCTAB nTab) const
178 if (const ScTable* pTable = FetchTable(nTab))
179 return pTable->GetRangeName();
180 return nullptr;
183 ScRangeName* ScDocument::GetRangeName() const
185 if (!pRangeName)
186 pRangeName.reset(new ScRangeName);
187 return pRangeName.get();
190 void ScDocument::SetRangeName(SCTAB nTab, std::unique_ptr<ScRangeName> pNew)
192 if (ScTable* pTable = FetchTable(nTab))
193 pTable->SetRangeName(std::move(pNew));
196 void ScDocument::SetRangeName( std::unique_ptr<ScRangeName> pNewRangeName )
198 pRangeName = std::move(pNewRangeName);
201 bool ScDocument::IsAddressInRangeName( RangeNameScope eScope, const ScAddress& rAddress )
203 ScRangeName* pRangeNames;
204 ScRange aNameRange;
206 if (eScope == RangeNameScope::GLOBAL)
207 pRangeNames= GetRangeName();
208 else
209 pRangeNames= GetRangeName(rAddress.Tab());
211 for (const auto& rEntry : *pRangeNames)
213 if (rEntry.second->IsValidReference(aNameRange))
215 if (aNameRange.Contains(rAddress))
216 return true;
220 return false;
223 bool ScDocument::InsertNewRangeName( const OUString& rName, const ScAddress& rPos, const OUString& rExpr )
225 ScRangeName* pGlobalNames = GetRangeName();
226 if (!pGlobalNames)
227 return false;
229 ScRangeData* pName = new ScRangeData(*this, rName, rExpr, rPos, ScRangeData::Type::Name, GetGrammar());
230 return pGlobalNames->insert(pName);
233 bool ScDocument::InsertNewRangeName( SCTAB nTab, const OUString& rName, const ScAddress& rPos, const OUString& rExpr )
235 ScRangeName* pLocalNames = GetRangeName(nTab);
236 if (!pLocalNames)
237 return false;
239 ScRangeData* pName = new ScRangeData(*this, rName, rExpr, rPos, ScRangeData::Type::Name, GetGrammar());
240 return pLocalNames->insert(pName);
243 const ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, OUString& rName, bool* pSheetLocal ) const
245 const ScRangeData* pData = nullptr;
246 if (rBlock.aStart.Tab() == rBlock.aEnd.Tab())
248 const ScRangeName* pLocalNames = GetRangeName(rBlock.aStart.Tab());
249 if (pLocalNames)
251 pData = pLocalNames->findByRange( rBlock );
252 if (pData)
254 rName = pData->GetName();
255 if (pSheetLocal)
256 *pSheetLocal = true;
257 return pData;
261 if ( pRangeName )
263 pData = pRangeName->findByRange( rBlock );
264 if (pData)
266 rName = pData->GetName();
267 if (pSheetLocal)
268 *pSheetLocal = false;
271 return pData;
274 ScRangeData* ScDocument::FindRangeNameBySheetAndIndex( SCTAB nTab, sal_uInt16 nIndex ) const
276 const ScRangeName* pRN = (nTab < 0 ? GetRangeName() : GetRangeName(nTab));
277 return (pRN ? pRN->findByIndex( nIndex) : nullptr);
280 void ScDocument::SetDBCollection( std::unique_ptr<ScDBCollection> pNewDBCollection, bool bRemoveAutoFilter )
282 if (pDBCollection && bRemoveAutoFilter)
284 // remove auto filter attribute if new db data don't contain auto filter flag
285 // start position is also compared, so bRemoveAutoFilter must not be set from ref-undo!
287 ScDBCollection::NamedDBs& rNamedDBs = pDBCollection->getNamedDBs();
288 for (const auto& rxNamedDB : rNamedDBs)
290 const ScDBData& rOldData = *rxNamedDB;
291 if (!rOldData.HasAutoFilter())
292 continue;
294 ScRange aOldRange;
295 rOldData.GetArea(aOldRange);
297 bool bFound = false;
298 if (pNewDBCollection)
300 ScDBData* pNewData = pNewDBCollection->getNamedDBs().findByUpperName(rOldData.GetUpperName());
301 if (pNewData)
303 if (pNewData->HasAutoFilter())
305 ScRange aNewRange;
306 pNewData->GetArea(aNewRange);
307 if (aOldRange.aStart == aNewRange.aStart)
308 bFound = true;
313 if (!bFound)
315 aOldRange.aEnd.SetRow(aOldRange.aStart.Row());
316 RemoveFlagsTab( aOldRange.aStart.Col(), aOldRange.aStart.Row(),
317 aOldRange.aEnd.Col(), aOldRange.aEnd.Row(),
318 aOldRange.aStart.Tab(), ScMF::Auto );
319 RepaintRange( aOldRange );
324 pDBCollection = std::move(pNewDBCollection);
327 const ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
329 if (pDBCollection)
330 return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ePortion);
331 else
332 return nullptr;
335 ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion)
337 if (pDBCollection)
338 return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ePortion);
339 else
340 return nullptr;
343 const ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
345 if (pDBCollection)
346 return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
347 else
348 return nullptr;
351 ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
353 if (pDBCollection)
354 return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
355 else
356 return nullptr;
359 void ScDocument::RefreshDirtyTableColumnNames()
361 if (pDBCollection)
362 pDBCollection->RefreshDirtyTableColumnNames();
365 bool ScDocument::HasPivotTable() const
367 return pDPCollection && pDPCollection->GetCount();
370 ScDPCollection* ScDocument::GetDPCollection()
372 if (!pDPCollection)
373 pDPCollection.reset( new ScDPCollection(*this) );
374 return pDPCollection.get();
377 const ScDPCollection* ScDocument::GetDPCollection() const
379 return pDPCollection.get();
382 ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
384 if (!pDPCollection)
385 return nullptr;
387 sal_uInt16 nCount = pDPCollection->GetCount();
388 ScAddress aPos( nCol, nRow, nTab );
389 for (sal_uInt16 i=0; i<nCount; i++)
390 if ( (*pDPCollection)[i].GetOutRange().Contains( aPos ) )
391 return &(*pDPCollection)[i];
393 return nullptr;
396 ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
398 if (!pDPCollection)
399 return nullptr;
401 /* Walk the collection in reverse order to get something of an
402 * approximation of MS Excels 'most recent' effect. */
403 sal_uInt16 i = pDPCollection->GetCount();
404 while ( i-- > 0 )
405 if ( (*pDPCollection)[i].GetOutRange().Contains( rBlock ) )
406 return &(*pDPCollection)[i];
408 return nullptr;
411 void ScDocument::StopTemporaryChartLock()
413 if (apTemporaryChartLock)
414 apTemporaryChartLock->StopLocking();
417 void ScDocument::SetChartListenerCollection(
418 std::unique_ptr<ScChartListenerCollection> pNewChartListenerCollection,
419 bool bSetChartRangeLists )
421 std::unique_ptr<ScChartListenerCollection> pOld = std::move(pChartListenerCollection);
422 pChartListenerCollection = std::move(pNewChartListenerCollection);
423 if ( pChartListenerCollection )
425 if ( pOld )
426 pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
427 pChartListenerCollection->StartAllListeners();
431 void ScDocument::SetScenario( SCTAB nTab, bool bFlag )
433 if (ScTable* pTable = FetchTable(nTab))
434 pTable->SetScenario(bFlag);
437 bool ScDocument::IsScenario( SCTAB nTab ) const
439 const ScTable* pTable = FetchTable(nTab);
440 return pTable && pTable->IsScenario();
443 void ScDocument::SetScenarioData( SCTAB nTab, const OUString& rComment,
444 const Color& rColor, ScScenarioFlags nFlags )
446 if (ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
448 pTable->SetScenarioComment( rComment );
449 pTable->SetScenarioColor( rColor );
450 pTable->SetScenarioFlags( nFlags );
454 Color ScDocument::GetTabBgColor( SCTAB nTab ) const
456 if (const ScTable* pTable = FetchTable(nTab))
457 return pTable->GetTabBgColor();
458 return COL_AUTO;
461 void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
463 if (ScTable* pTable = FetchTable(nTab))
464 pTable->SetTabBgColor(rColor);
467 bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
469 if (const ScTable* pTable = FetchTable(nTab))
470 return pTable->GetTabBgColor() == COL_AUTO;
471 return true;
474 void ScDocument::GetScenarioData( SCTAB nTab, OUString& rComment,
475 Color& rColor, ScScenarioFlags& rFlags ) const
477 if (const ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
479 pTable->GetScenarioComment( rComment );
480 rColor = pTable->GetScenarioColor();
481 rFlags = pTable->GetScenarioFlags();
485 void ScDocument::GetScenarioFlags( SCTAB nTab, ScScenarioFlags& rFlags ) const
487 if (const ScTable* pTable = FetchTable(nTab); pTable && pTable->IsScenario())
488 rFlags = pTable->GetScenarioFlags();
491 bool ScDocument::IsLinked( SCTAB nTab ) const
493 const ScTable* pTable = FetchTable(nTab);
494 return pTable && pTable->IsLinked();
497 formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
499 return formula::FormulaGrammar::extractRefConvention(eGrammar);
502 void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
504 eGrammar = eGram;
507 ScLinkMode ScDocument::GetLinkMode( SCTAB nTab ) const
509 if (const ScTable* pTable = FetchTable(nTab))
510 return pTable->GetLinkMode();
511 return ScLinkMode::NONE;
514 OUString ScDocument::GetLinkDoc( SCTAB nTab ) const
516 if (const ScTable* pTable = FetchTable(nTab))
517 return pTable->GetLinkDoc();
518 return OUString();
521 OUString ScDocument::GetLinkFlt( SCTAB nTab ) const
523 if (const ScTable* pTable = FetchTable(nTab))
524 return pTable->GetLinkFlt();
525 return OUString();
528 OUString ScDocument::GetLinkOpt( SCTAB nTab ) const
530 if (const ScTable* pTable = FetchTable(nTab))
531 return pTable->GetLinkOpt();
532 return OUString();
535 OUString ScDocument::GetLinkTab( SCTAB nTab ) const
537 if (const ScTable* pTable = FetchTable(nTab))
538 return pTable->GetLinkTab();
539 return OUString();
542 sal_Int32 ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
544 if (const ScTable* pTable = FetchTable(nTab))
545 return pTable->GetLinkRefreshDelay();
546 return 0;
549 void ScDocument::SetLink( SCTAB nTab, ScLinkMode nMode, const OUString& rDoc,
550 const OUString& rFilter, const OUString& rOptions,
551 const OUString& rTabName, sal_Int32 nRefreshDelay )
553 if (ScTable* pTable = FetchTable(nTab))
554 pTable->SetLink(nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay);
557 bool ScDocument::HasLink( std::u16string_view rDoc,
558 std::u16string_view rFilter, std::u16string_view rOptions ) const
560 SCTAB nCount = GetTableCount();
561 for (SCTAB i=0; i<nCount; i++)
562 if (maTabs[i]->IsLinked()
563 && maTabs[i]->GetLinkDoc() == rDoc
564 && maTabs[i]->GetLinkFlt() == rFilter
565 && maTabs[i]->GetLinkOpt() == rOptions)
566 return true;
568 return false;
571 bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
572 const OUString& aFileName, const OUString& aTabName )
574 if ( IsClipboard() )
576 OSL_FAIL( "LinkExternalTab in Clipboard" );
577 return false;
579 rTab = 0;
580 #if ENABLE_FUZZERS
581 (void)aDocTab;
582 (void)aFileName;
583 (void)aTabName;
584 return false;
585 #else
586 OUString aFilterName; // Is filled by the Loader
587 OUString aOptions; // Filter options
588 sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
589 ScDocumentLoader aLoader( aFileName, aFilterName, aOptions, nLinkCnt + 1 );
590 if ( aLoader.IsError() )
591 return false;
592 ScDocument* pSrcDoc = aLoader.GetDocument();
594 // Copy table
595 SCTAB nSrcTab;
596 if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
598 if ( !InsertTab( SC_TAB_APPEND, aDocTab, true ) )
600 OSL_FAIL("can't insert external document table");
601 return false;
603 rTab = GetTableCount() - 1;
604 // Don't insert anew, just the results
605 TransferTab( *pSrcDoc, nSrcTab, rTab, false, true );
607 else
608 return false;
610 sal_Int32 nRefreshDelay = 0;
612 bool bWasThere = HasLink( aFileName, aFilterName, aOptions );
613 SetLink( rTab, ScLinkMode::VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
614 if ( !bWasThere ) // Add link only once per source document
616 ScTableLink* pLink = new ScTableLink( mpShell, aFileName, aFilterName, aOptions, nRefreshDelay );
617 pLink->SetInCreate( true );
618 OUString aFilName = aFilterName;
619 GetLinkManager()->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilName );
620 pLink->Update();
621 pLink->SetInCreate( false );
622 SfxBindings* pBindings = GetViewBindings();
623 if (pBindings)
624 pBindings->Invalidate( SID_LINKS );
626 return true;
627 #endif
630 ScExternalRefManager* ScDocument::GetExternalRefManager() const
632 ScDocument* pThis = const_cast<ScDocument*>(this);
633 if (!pExternalRefMgr)
634 pThis->pExternalRefMgr.reset( new ScExternalRefManager(*pThis));
636 return pExternalRefMgr.get();
639 bool ScDocument::IsInExternalReferenceMarking() const
641 return pExternalRefMgr && pExternalRefMgr->isInReferenceMarking();
644 void ScDocument::MarkUsedExternalReferences()
646 if (!pExternalRefMgr)
647 return;
648 if (!pExternalRefMgr->hasExternalData())
649 return;
650 // Charts.
651 pExternalRefMgr->markUsedByLinkListeners();
652 // Formula cells.
653 pExternalRefMgr->markUsedExternalRefCells();
655 /* NOTE: Conditional formats and validation objects are marked when
656 * collecting them during export. */
659 ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
661 if (!mxFormulaParserPool)
662 mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) );
663 return *mxFormulaParserPool;
666 const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
668 if (const ScTable* pTable = FetchTable(nTab))
669 return pTable->GetSheetEvents();
670 return nullptr;
673 void ScDocument::SetSheetEvents( SCTAB nTab, std::unique_ptr<ScSheetEvents> pNew )
675 if (ScTable* pTable = FetchTable(nTab))
676 pTable->SetSheetEvents( std::move(pNew) );
679 bool ScDocument::HasSheetEventScript( SCTAB nTab, ScSheetEventId nEvent, bool bWithVbaEvents ) const
681 if (const ScTable* pTable = FetchTable(nTab))
683 // check if any event handler script has been configured
684 const ScSheetEvents* pEvents = pTable->GetSheetEvents();
685 if ( pEvents && pEvents->GetScript( nEvent ) )
686 return true;
687 // check if VBA event handlers exist
688 if (bWithVbaEvents && mxVbaEvents.is()) try
690 uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
691 if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
692 mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
693 return true;
695 catch( uno::Exception& )
699 return false;
702 bool ScDocument::HasAnySheetEventScript( ScSheetEventId nEvent, bool bWithVbaEvents ) const
704 SCTAB nSize = GetTableCount();
705 for (SCTAB nTab = 0; nTab < nSize; nTab++)
706 if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
707 return true;
708 return false;
711 bool ScDocument::HasAnyCalcNotification() const
713 SCTAB nSize = GetTableCount();
714 for (SCTAB nTab = 0; nTab < nSize; nTab++)
715 if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
716 return true;
717 return false;
720 bool ScDocument::HasCalcNotification( SCTAB nTab ) const
722 if (const ScTable* pTable = FetchTable(nTab))
723 return pTable->GetCalcNotification();
724 return false;
727 void ScDocument::SetCalcNotification( SCTAB nTab )
729 // set only if not set before
730 if (ScTable* pTable = FetchTable(nTab) ; pTable && !pTable->GetCalcNotification())
731 pTable->SetCalcNotification(true);
734 void ScDocument::ResetCalcNotifications()
736 SCTAB nSize = GetTableCount();
737 for (SCTAB nTab = 0; nTab < nSize; nTab++)
738 if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
739 maTabs[nTab]->SetCalcNotification(false);
742 ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, bool bCreate )
744 ScOutlineTable* pVal = nullptr;
746 if (ScTable* pTable = FetchTable(nTab))
748 pVal = pTable->GetOutlineTable();
749 if (!pVal && bCreate)
751 pTable->StartOutlineTable();
752 pVal = pTable->GetOutlineTable();
756 return pVal;
759 bool ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
761 ScTable* pTable = FetchTable(nTab);
762 return pTable && pTable->SetOutlineTable(pNewOutline);
765 void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
766 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
768 if (ScTable* pTable = FetchTable(nTab))
769 pTable->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
772 bool ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
774 ScTable* pTable = FetchTable(nTab);
775 return pTable && pTable->TestRemoveSubTotals(rParam);
778 void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
780 if (ScTable* pTable = FetchTable(nTab))
781 pTable->RemoveSubTotals( rParam );
784 bool ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
786 ScTable* pTable = FetchTable(nTab);
787 return pTable && pTable->DoSubTotals(rParam);
790 bool ScDocument::HasSubTotalCells( const ScRange& rRange )
792 ScCellIterator aIter(*this, rRange);
793 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
795 if (aIter.getType() != CELLTYPE_FORMULA)
796 continue;
798 if (aIter.getFormulaCell()->IsSubTotal())
799 return true;
801 return false; // none found
805 * From this document this method copies the cells of positions at which
806 * there are also cells in pPosDoc to pDestDoc
808 void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
810 SCTAB nCount = GetTableCount();
811 for (SCTAB nTab=0; nTab<nCount; nTab++)
812 if (maTabs[nTab] && pPosDoc->maTabs[nTab] && pDestDoc->maTabs[nTab])
813 maTabs[nTab]->CopyUpdated( pPosDoc->maTabs[nTab].get(), pDestDoc->maTabs[nTab].get() );
816 void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, bool bNewScenario )
818 if (!HasTable(nSrcTab) || !HasTable(nDestTab))
819 return;
821 // Set flags correctly for active scenarios
822 // and write current values back to recently active scenarios
823 ScRangeList aRanges = *maTabs[nSrcTab]->GetScenarioRanges();
825 // nDestTab is the target table
826 for ( SCTAB nTab = nDestTab+1;
827 nTab < GetTableCount() && maTabs[nTab] && maTabs[nTab]->IsScenario();
828 nTab++ )
830 if ( maTabs[nTab]->IsActiveScenario() ) // Even if it's the same scenario
832 bool bTouched = false;
833 for ( size_t nR=0, nRangeCount = aRanges.size(); nR < nRangeCount && !bTouched; nR++ )
835 const ScRange& rRange = aRanges[ nR ];
836 if ( maTabs[nTab]->HasScenarioRange( rRange ) )
837 bTouched = true;
839 if (bTouched)
841 maTabs[nTab]->SetActiveScenario(false);
842 if ( maTabs[nTab]->GetScenarioFlags() & ScScenarioFlags::TwoWay )
843 maTabs[nTab]->CopyScenarioFrom( maTabs[nDestTab].get() );
848 maTabs[nSrcTab]->SetActiveScenario(true); // This is where it's from ...
849 if (!bNewScenario) // Copy data from the selected scenario
851 sc::AutoCalcSwitch aACSwitch(*this, false);
852 maTabs[nSrcTab]->CopyScenarioTo( maTabs[nDestTab].get() );
854 sc::SetFormulaDirtyContext aCxt;
855 SetAllFormulasDirty(aCxt);
859 void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
860 bool bResetMark, ScScenarioFlags nNeededBits ) const
862 if (bResetMark)
863 rDestMark.ResetMark();
865 if (const ScTable* pTable = FetchTable(nSrcTab))
866 pTable->MarkScenarioIn(rDestMark, nNeededBits);
868 rDestMark.SetAreaTab( nDestTab);
871 bool ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
873 const ScTable* pTable = FetchTable(nTab);
874 return pTable && pTable->HasScenarioRange(rRange);
877 const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
879 if (const ScTable* pTable = FetchTable(nTab))
880 return pTable->GetScenarioRanges();
882 return nullptr;
885 bool ScDocument::IsActiveScenario( SCTAB nTab ) const
887 const ScTable* pTable = FetchTable(nTab);
888 return pTable && pTable->IsActiveScenario();
891 void ScDocument::SetActiveScenario( SCTAB nTab, bool bActive )
893 if (ScTable* pTable = FetchTable(nTab))
894 pTable->SetActiveScenario( bActive );
897 bool ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
899 if (HasTable(nSrcTab) && HasTable(nDestTab))
900 return maTabs[nSrcTab]->TestCopyScenarioTo(maTabs[nDestTab].get());
902 OSL_FAIL("wrong table at TestCopyScenario");
903 return false;
906 void ScDocument::AddUnoObject( SfxListener& rObject )
908 if (!pUnoBroadcaster)
909 pUnoBroadcaster.reset( new SfxBroadcaster );
911 rObject.StartListening( *pUnoBroadcaster );
914 void ScDocument::RemoveUnoObject( SfxListener& rObject )
916 if (pUnoBroadcaster)
918 rObject.EndListening( *pUnoBroadcaster );
920 if ( bInUnoBroadcast )
922 // Broadcasts from ScDocument::BroadcastUno are the only way that
923 // uno object methods are called without holding a reference.
925 // If RemoveUnoObject is called from an object dtor in the finalizer thread
926 // while the main thread is calling BroadcastUno, the dtor thread must wait
927 // (or the object's Notify might try to access a deleted object).
928 // The SolarMutex can't be locked here because if a component is called from
929 // a VCL event, the main thread has the SolarMutex locked all the time.
931 // This check is done after calling EndListening, so a later BroadcastUno call
932 // won't touch this object.
934 vcl::SolarMutexTryAndBuyGuard g;
935 if (g.isAcquired())
937 // BroadcastUno is always called with the SolarMutex locked, so if it
938 // can be acquired, this is within the same thread (should not happen)
939 OSL_FAIL( "RemoveUnoObject called from BroadcastUno" );
941 else
943 // Let the thread that called BroadcastUno continue
944 while ( bInUnoBroadcast )
946 osl::Thread::yield();
951 else
953 OSL_FAIL("No Uno broadcaster");
957 void ScDocument::BroadcastUno( const SfxHint &rHint )
959 if (!pUnoBroadcaster)
960 return;
962 bInUnoBroadcast = true;
963 pUnoBroadcaster->Broadcast( rHint );
964 bInUnoBroadcast = false;
966 // During Broadcast notification, Uno objects can add to pUnoListenerCalls.
967 // The listener calls must be processed after completing the broadcast,
968 // because they can add or remove objects from pUnoBroadcaster.
970 if ( pUnoListenerCalls &&
971 rHint.GetId() == SfxHintId::DataChanged &&
972 !bInUnoListenerCall )
974 // Listener calls may lead to BroadcastUno calls again. The listener calls
975 // are not nested, instead the calls are collected in the list, and the
976 // outermost call executes them all.
978 ScChartLockGuard aChartLockGuard(this);
979 bInUnoListenerCall = true;
980 pUnoListenerCalls->ExecuteAndClear();
981 bInUnoListenerCall = false;
985 void ScDocument::AddUnoListenerCall( const uno::Reference<util::XModifyListener>& rListener,
986 const lang::EventObject& rEvent )
988 OSL_ENSURE( bInUnoBroadcast, "AddUnoListenerCall is supposed to be called from BroadcastUno only" );
990 if ( !pUnoListenerCalls )
991 pUnoListenerCalls.reset( new ScUnoListenerCalls );
992 pUnoListenerCalls->Add( rListener, rEvent );
995 void ScDocument::BeginUnoRefUndo()
997 OSL_ENSURE( !pUnoRefUndoList, "BeginUnoRefUndo twice" );
998 pUnoRefUndoList.reset( new ScUnoRefList );
1001 std::unique_ptr<ScUnoRefList> ScDocument::EndUnoRefUndo()
1003 return std::move(pUnoRefUndoList);
1004 // Must be deleted by caller!
1007 void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
1009 if ( pUnoRefUndoList )
1010 pUnoRefUndoList->Add( nId, rOldRanges );
1013 void ScDocument::UpdateReference(
1014 sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos )
1016 if (!ValidRange(rCxt.maRange) && !(rCxt.meMode == URM_INSDEL &&
1017 ((rCxt.mnColDelta < 0 && // convention from ScDocument::DeleteCol()
1018 rCxt.maRange.aStart.Col() == GetMaxColCount() && rCxt.maRange.aEnd.Col() == GetMaxColCount()) ||
1019 (rCxt.mnRowDelta < 0 && // convention from ScDocument::DeleteRow()
1020 rCxt.maRange.aStart.Row() == GetMaxRowCount() && rCxt.maRange.aEnd.Row() == GetMaxRowCount()))))
1021 return;
1023 std::unique_ptr<sc::ExpandRefsSwitch> pExpandRefsSwitch;
1024 if (rCxt.isInserted())
1025 pExpandRefsSwitch.reset(new sc::ExpandRefsSwitch(*this, ScModule::get()->GetInputOptions().GetExpandRefs()));
1027 size_t nFirstTab, nLastTab;
1028 if (rCxt.meMode == URM_COPY)
1030 nFirstTab = rCxt.maRange.aStart.Tab();
1031 nLastTab = rCxt.maRange.aEnd.Tab();
1033 else
1035 // TODO: Have these methods use the context object directly.
1036 ScRange aRange = rCxt.maRange;
1037 UpdateRefMode eUpdateRefMode = rCxt.meMode;
1038 SCCOL nDx = rCxt.mnColDelta;
1039 SCROW nDy = rCxt.mnRowDelta;
1040 SCTAB nDz = rCxt.mnTabDelta;
1041 SCCOL nCol1 = rCxt.maRange.aStart.Col(), nCol2 = rCxt.maRange.aEnd.Col();
1042 SCROW nRow1 = rCxt.maRange.aStart.Row(), nRow2 = rCxt.maRange.aEnd.Row();
1043 SCTAB nTab1 = rCxt.maRange.aStart.Tab(), nTab2 = rCxt.maRange.aEnd.Tab();
1045 xColNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
1046 xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
1047 pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
1048 if (pRangeName)
1049 pRangeName->UpdateReference(rCxt);
1050 if ( pDPCollection )
1051 pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
1052 UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
1053 UpdateRefAreaLinks( eUpdateRefMode, aRange, nDx, nDy, nDz );
1054 if ( pValidationList )
1056 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
1057 pValidationList->UpdateReference(rCxt);
1059 if ( pDetOpList )
1060 pDetOpList->UpdateReference( this, eUpdateRefMode, aRange, nDx, nDy, nDz );
1061 if ( pUnoBroadcaster )
1062 pUnoBroadcaster->Broadcast( ScUpdateRefHint(
1063 eUpdateRefMode, aRange, nDx, nDy, nDz ) );
1065 nFirstTab = 0;
1066 nLastTab = maTabs.size()-1;
1069 for (size_t i = nFirstTab, n = maTabs.size() ; i <= nLastTab && i < n; ++i)
1071 if (!maTabs[i])
1072 continue;
1074 maTabs[i]->UpdateReference(rCxt, pUndoDoc, bIncludeDraw, bUpdateNoteCaptionPos);
1077 if ( bIsEmbedded )
1079 SCCOL theCol1;
1080 SCROW theRow1;
1081 SCTAB theTab1;
1082 SCCOL theCol2;
1083 SCROW theRow2;
1084 SCTAB theTab2;
1085 theCol1 = aEmbedRange.aStart.Col();
1086 theRow1 = aEmbedRange.aStart.Row();
1087 theTab1 = aEmbedRange.aStart.Tab();
1088 theCol2 = aEmbedRange.aEnd.Col();
1089 theRow2 = aEmbedRange.aEnd.Row();
1090 theTab2 = aEmbedRange.aEnd.Tab();
1092 // TODO: Have ScRefUpdate::Update() use the context object directly.
1093 UpdateRefMode eUpdateRefMode = rCxt.meMode;
1094 SCCOL nDx = rCxt.mnColDelta;
1095 SCROW nDy = rCxt.mnRowDelta;
1096 SCTAB nDz = rCxt.mnTabDelta;
1097 SCCOL nCol1 = rCxt.maRange.aStart.Col(), nCol2 = rCxt.maRange.aEnd.Col();
1098 SCROW nRow1 = rCxt.maRange.aStart.Row(), nRow2 = rCxt.maRange.aEnd.Row();
1099 SCTAB nTab1 = rCxt.maRange.aStart.Tab(), nTab2 = rCxt.maRange.aEnd.Tab();
1101 if ( ScRefUpdate::Update( this, eUpdateRefMode, nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
1102 nDx,nDy,nDz, theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
1104 aEmbedRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
1108 // After moving, no clipboard move ref-updates are possible
1109 if (rCxt.meMode != URM_COPY && IsClipboardSource())
1111 ScDocument* pClipDoc = ScModule::GetClipDoc();
1112 if (pClipDoc)
1113 pClipDoc->GetClipParam().mbCutMode = false;
1117 void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
1118 const ScMarkData& rMark, ScDocument* pUndoDoc )
1120 OSL_ENSURE(pClipDoc->bIsClip, "UpdateTranspose: No Clip");
1122 ScRange aSource;
1123 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1124 if (!rClipParam.maRanges.empty())
1125 aSource = rClipParam.maRanges.front();
1126 ScAddress aDest = rDestPos;
1128 SCTAB nClipTab = 0;
1129 for (SCTAB nDestTab = 0; nDestTab < GetTableCount() && maTabs[nDestTab]; nDestTab++)
1130 if (rMark.GetTableSelect(nDestTab))
1132 while (!pClipDoc->maTabs[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1133 aSource.aStart.SetTab( nClipTab );
1134 aSource.aEnd.SetTab( nClipTab );
1135 aDest.SetTab( nDestTab );
1137 // Like UpdateReference
1138 if (pRangeName)
1139 pRangeName->UpdateTranspose( aSource, aDest ); // Before the cells!
1140 for (SCTAB i = 0; i < GetTableCount(); i++)
1141 if (maTabs[i])
1142 maTabs[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
1144 nClipTab = (nClipTab+1) % (MAXTAB+1);
1148 void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1150 //TODO: pDBCollection
1151 //TODO: pPivotCollection
1152 //TODO: UpdateChartRef
1154 if (pRangeName)
1155 pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
1157 for (SCTAB i = 0; i < GetTableCount() && maTabs[i]; i++)
1158 maTabs[i]->UpdateGrow( rArea, nGrowX, nGrowY );
1161 void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProgress* pProgress, const ScMarkData& rMark,
1162 sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1163 double nStepValue, double nMaxValue)
1165 PutInOrder( nCol1, nCol2 );
1166 PutInOrder( nRow1, nRow2 );
1167 const ScRange& aRange = rMark.GetMarkArea();
1168 SCTAB nMax = maTabs.size();
1169 for (const auto& rTab : rMark)
1171 if (rTab >= nMax)
1172 break;
1173 if (maTabs[rTab])
1175 maTabs[rTab]->Fill(nCol1, nRow1, nCol2, nRow2,
1176 nFillCount, eFillDir, eFillCmd, eFillDateCmd,
1177 nStepValue, tools::Duration(), nMaxValue, pProgress);
1178 RefreshAutoFilter(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rTab);
1183 OUString ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
1185 SCTAB nTab = rSource.aStart.Tab();
1186 if (nTab < GetTableCount() && maTabs[nTab])
1187 return maTabs[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
1189 return OUString();
1192 void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1193 sal_uInt16 nFormatNo, const ScMarkData& rMark )
1195 ScProgress aProgress(GetDocumentShell(), ScResId(STR_UNDO_AUTOFORMAT), nEndCol - nStartCol + 1, true);
1196 PutInOrder( nStartCol, nEndCol );
1197 PutInOrder( nStartRow, nEndRow );
1198 SCTAB nMax = maTabs.size();
1199 for (const auto& rTab : rMark)
1201 if (rTab >= nMax)
1202 break;
1203 if (maTabs[rTab])
1204 maTabs[rTab]->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, &aProgress );
1208 void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1209 ScAutoFormatData& rData)
1211 if (ScTable* pTable = FetchTable(nTab))
1213 PutInOrder(nStartCol, nEndCol);
1214 PutInOrder(nStartRow, nEndRow);
1215 pTable->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
1219 void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
1220 SCCOL& rCol, SCROW& rRow )
1222 SvxSearchCmd nCommand = rSearchItem.GetCommand();
1223 bool bReplace = ( nCommand == SvxSearchCmd::REPLACE ||
1224 nCommand == SvxSearchCmd::REPLACE_ALL );
1225 if ( rSearchItem.GetBackward() )
1227 if ( rSearchItem.GetRowDirection() )
1229 if ( rSearchItem.GetPattern() )
1231 rCol = MaxCol();
1232 rRow = MaxRow()+1;
1234 else if ( bReplace )
1236 rCol = MaxCol();
1237 rRow = MaxRow();
1239 else
1241 rCol = MaxCol()+1;
1242 rRow = MaxRow();
1245 else
1247 if ( rSearchItem.GetPattern() )
1249 rCol = MaxCol()+1;
1250 rRow = MaxRow();
1252 else if ( bReplace )
1254 rCol = MaxCol();
1255 rRow = MaxRow();
1257 else
1259 rCol = MaxCol();
1260 rRow = MaxRow()+1;
1264 else
1266 if ( rSearchItem.GetRowDirection() )
1268 if ( rSearchItem.GetPattern() )
1270 rCol = 0;
1271 rRow = SCROW(-1);
1273 else if ( bReplace )
1275 rCol = 0;
1276 rRow = 0;
1278 else
1280 rCol = SCCOL(-1);
1281 rRow = 0;
1284 else
1286 if ( rSearchItem.GetPattern() )
1288 rCol = SCCOL(-1);
1289 rRow = 0;
1291 else if ( bReplace )
1293 rCol = 0;
1294 rRow = 0;
1296 else
1298 rCol = 0;
1299 rRow = SCROW(-1);
1305 // static
1306 bool ScDocument::IsEmptyCellSearch( const SvxSearchItem& rSearchItem )
1308 return !rSearchItem.GetPattern() && (rSearchItem.GetCellType() != SvxSearchCellType::NOTE)
1309 && (rSearchItem.GetSearchOptions().searchString.isEmpty()
1310 || (rSearchItem.GetRegExp() && rSearchItem.GetSearchOptions().searchString == "^$"));
1313 bool ScDocument::SearchAndReplace(
1314 const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
1315 const ScMarkData& rMark, ScRangeList& rMatchedRanges,
1316 OUString& rUndoStr, ScDocument* pUndoDoc, bool& bMatchedRangesWereClamped)
1318 // FIXME: Manage separated marks per table!
1319 bool bFound = false;
1320 if (rTab >= GetTableCount())
1321 OSL_FAIL("table out of range");
1322 if (ValidTab(rTab))
1324 SCCOL nCol;
1325 SCROW nRow;
1326 SCTAB nTab;
1327 SvxSearchCmd nCommand = rSearchItem.GetCommand();
1328 if ( nCommand == SvxSearchCmd::FIND_ALL ||
1329 nCommand == SvxSearchCmd::REPLACE_ALL )
1331 SCTAB nMax = maTabs.size();
1332 for (const auto& rMarkedTab : rMark)
1334 if (rMarkedTab >= nMax)
1335 break;
1336 if (maTabs[rMarkedTab])
1338 nCol = 0;
1339 nRow = 0;
1340 bFound |= maTabs[rMarkedTab]->SearchAndReplace(
1341 rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
1345 // Mark is set completely inside already
1347 else
1349 nCol = rCol;
1350 nRow = rRow;
1351 if (rSearchItem.GetBackward())
1353 for (nTab = rTab; (nTab >= 0) && !bFound; nTab--)
1354 if (maTabs[nTab])
1356 if (rMark.GetTableSelect(nTab))
1358 bFound = maTabs[nTab]->SearchAndReplace(
1359 rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
1360 if (bFound)
1362 rCol = nCol;
1363 rRow = nRow;
1364 rTab = nTab;
1366 else
1368 ScDocument::GetSearchAndReplaceStart(
1369 rSearchItem, nCol, nRow );
1371 // notify LibreOfficeKit about changed page
1372 if (comphelper::LibreOfficeKit::isActive())
1374 OString aPayload = OString::number(nTab);
1375 if (SfxViewShell* pViewShell = SfxViewShell::Current())
1376 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
1382 else
1384 for (nTab = rTab; (nTab < GetTableCount()) && !bFound; nTab++)
1385 if (maTabs[nTab])
1387 if (rMark.GetTableSelect(nTab))
1389 bFound = maTabs[nTab]->SearchAndReplace(
1390 rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc, bMatchedRangesWereClamped);
1391 if (bFound)
1393 rCol = nCol;
1394 rRow = nRow;
1395 rTab = nTab;
1397 else
1399 ScDocument::GetSearchAndReplaceStart(
1400 rSearchItem, nCol, nRow );
1402 // notify LibreOfficeKit about changed page
1403 if (comphelper::LibreOfficeKit::isActive())
1405 OString aPayload = OString::number(nTab);
1406 if(SfxViewShell* pViewShell = SfxViewShell::Current())
1407 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload);
1415 return bFound;
1419 * Adapt Outline
1421 bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bShow )
1423 if (ScTable* pTable = FetchTable(nTab))
1424 return pTable->UpdateOutlineCol(nStartCol, nEndCol, bShow);
1426 OSL_FAIL("missing tab");
1427 return false;
1430 bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bShow )
1432 if (ScTable* pTable = FetchTable(nTab))
1433 return pTable->UpdateOutlineRow(nStartRow, nEndRow, bShow);
1435 OSL_FAIL("missing tab");
1436 return false;
1439 void ScDocument::Sort(
1440 SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
1441 ScProgress* pProgress, sc::ReorderParam* pUndo )
1443 if (ScTable* pTable = FetchTable(nTab))
1445 bool bOldEnableIdle = IsIdleEnabled();
1446 EnableIdle(false);
1447 pTable->Sort(rSortParam, bKeepQuery, bUpdateRefs, pProgress, pUndo);
1448 EnableIdle(bOldEnableIdle);
1452 void ScDocument::Reorder( const sc::ReorderParam& rParam )
1454 ScTable* pTable = FetchTable(rParam.maSortRange.aStart.Tab());
1455 if (!pTable)
1456 return;
1458 bool bOldEnableIdle = IsIdleEnabled();
1459 EnableIdle(false);
1460 pTable->Reorder(rParam);
1461 EnableIdle(bOldEnableIdle);
1464 void ScDocument::PrepareQuery( SCTAB nTab, ScQueryParam& rQueryParam )
1466 if (ScTable* pTable = FetchTable(nTab))
1467 pTable->PrepareQuery(rQueryParam);
1468 else
1470 OSL_FAIL("missing tab");
1474 SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub)
1476 if (ScTable* pTable = FetchTable(nTab))
1477 return pTable->Query(rQueryParam, bKeepSub);
1479 OSL_FAIL("missing tab");
1480 return 0;
1483 OUString ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab)
1485 if (ScTable* pTable = FetchTable(nTab))
1486 return pTable->GetUpperCellString( nCol, nRow );
1487 else
1488 return OUString();
1491 bool ScDocument::CreateQueryParam( const ScRange& rRange, ScQueryParam& rQueryParam )
1493 if (ScTable* pTable = FetchTable(rRange.aStart.Tab()))
1494 return pTable->CreateQueryParam(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rQueryParam);
1496 OSL_FAIL("missing tab");
1497 return false;
1500 bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
1502 const ScDBData* pDBData = GetDBAtCursor( nCurCol, nCurRow, nCurTab, ScDBDataPortion::AREA );
1503 bool bHasAutoFilter = (pDBData != nullptr);
1505 if ( pDBData )
1507 if ( pDBData->HasHeader() )
1509 SCCOL nCol;
1510 SCROW nRow;
1511 ScMF nFlag;
1513 ScQueryParam aParam;
1514 pDBData->GetQueryParam( aParam );
1515 nRow = aParam.nRow1;
1517 for ( nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAutoFilter; nCol++ )
1519 nFlag = GetAttr( nCol, nRow, nCurTab, ATTR_MERGE_FLAG )->GetValue();
1521 if ( !(nFlag & ScMF::Auto) )
1522 bHasAutoFilter = false;
1525 else
1526 bHasAutoFilter = false;
1529 return bHasAutoFilter;
1532 bool ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1533 SCTAB nTab )
1535 ScTable* pTable = FetchTable(nTab);
1536 return pTable && pTable->HasColHeader(nStartCol, nStartRow, nEndCol, nEndRow);
1539 bool ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1540 SCTAB nTab )
1542 ScTable* pTable = FetchTable(nTab);
1543 return pTable && pTable->HasRowHeader(nStartCol, nStartRow, nEndCol, nEndRow);
1546 void ScDocument::GetFilterSelCount( SCCOL nCol, SCROW nRow, SCTAB nTab, SCSIZE& nSelected, SCSIZE& nTotal )
1548 nSelected = 0;
1549 nTotal = 0;
1551 if (HasTable(nTab))
1553 ScDBData* pDBData = GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
1554 if( pDBData && pDBData->HasAutoFilter() )
1555 pDBData->GetFilterSelCount( nSelected, nTotal );
1560 * Entries for AutoFilter listbox
1562 void ScDocument::GetFilterEntries(
1563 SCCOL nCol, SCROW nRow, SCTAB nTab, ScFilterEntries& rFilterEntries )
1565 if (!HasTable(nTab) || !pDBCollection)
1566 return;
1568 ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA); //!??
1569 if (!pDBData)
1570 return;
1572 pDBData->ExtendBackColorArea(*this);
1573 pDBData->ExtendDataArea(*this);
1574 SCTAB nAreaTab;
1575 SCCOL nStartCol;
1576 SCROW nStartRow;
1577 SCCOL nEndCol;
1578 SCROW nEndRow;
1579 pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1581 if (pDBData->HasHeader())
1582 ++nStartRow;
1584 ScQueryParam aParam;
1585 pDBData->GetQueryParam( aParam );
1587 // Return all filter entries, if a filter condition is connected with a boolean OR
1588 bool bFilter = true;
1589 SCSIZE nEntryCount = aParam.GetEntryCount();
1590 for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
1592 ScQueryEntry& rEntry = aParam.GetEntry(i);
1593 if ( rEntry.eConnect != SC_AND )
1595 bFilter = false;
1596 break;
1600 if ( bFilter )
1602 maTabs[nTab]->GetFilteredFilterEntries( nCol, nStartRow, nEndRow, aParam, rFilterEntries, bFilter );
1604 else
1606 maTabs[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rFilterEntries );
1609 sortAndRemoveDuplicates( rFilterEntries.maStrData, aParam.bCaseSens);
1613 * Entries for Filter dialog
1615 void ScDocument::GetFilterEntriesArea(
1616 SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bCaseSens,
1617 ScFilterEntries& rFilterEntries )
1619 if (ScTable* pTable = FetchTable(nTab))
1621 pTable->GetFilterEntries(nCol, nStartRow, nEndRow, rFilterEntries, true);
1622 sortAndRemoveDuplicates(rFilterEntries.maStrData, bCaseSens);
1627 * Entries for selection list listbox (no numbers/formulas)
1629 void ScDocument::GetDataEntries(
1630 SCCOL nCol, SCROW nRow, SCTAB nTab,
1631 std::vector<ScTypedStrData>& rStrings, bool bValidation )
1633 if( bValidation )
1635 /* Try to generate the list from list validation. This part is skipped,
1636 if bValidation==false, because in that case this function is called to get
1637 cell values for auto completion on input. */
1638 sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
1639 if( nValidation )
1641 const ScValidationData* pData = GetValidationEntry( nValidation );
1642 if( pData && pData->FillSelectionList( rStrings, ScAddress( nCol, nRow, nTab ) ) )
1644 if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
1645 sortAndRemoveDuplicates(rStrings, true/*bCaseSens*/);
1647 return;
1652 if (!HasTable(nTab))
1653 return;
1655 std::set<ScTypedStrData> aStrings;
1656 if (maTabs[nTab]->GetDataEntries(nCol, nRow, aStrings))
1658 rStrings.insert(rStrings.end(), aStrings.begin(), aStrings.end());
1659 sortAndRemoveDuplicates(rStrings, true/*bCaseSens*/);
1664 * Entries for Formula auto input
1666 void ScDocument::GetFormulaEntries( ScTypedCaseStrSet& rStrings )
1669 // Range name
1670 if ( pRangeName )
1672 for (const auto& rEntry : *pRangeName)
1673 rStrings.insert(ScTypedStrData(rEntry.second->GetName(), 0.0, 0.0, ScTypedStrData::Name));
1676 // Database collection
1677 if ( pDBCollection )
1679 const ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
1680 for (const auto& rxDB : rDBs)
1681 rStrings.insert(ScTypedStrData(rxDB->GetName(), 0.0, 0.0, ScTypedStrData::DbName));
1684 // Content of name ranges
1685 ScRangePairList* pLists[2];
1686 pLists[0] = GetColNameRanges();
1687 pLists[1] = GetRowNameRanges();
1688 for (ScRangePairList* pList : pLists)
1690 if (!pList)
1691 continue;
1693 for ( size_t i = 0, nPairs = pList->size(); i < nPairs; ++i )
1695 const ScRangePair & rPair = (*pList)[i];
1696 const ScRange & rRange = rPair.GetRange(0);
1697 ScCellIterator aIter( *this, rRange );
1698 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
1700 if (!aIter.hasString())
1701 continue;
1703 OUString aStr = aIter.getString();
1704 rStrings.insert(ScTypedStrData(aStr, 0.0, 0.0, ScTypedStrData::Header));
1710 void ScDocument::GetEmbedded( ScRange& rRange ) const
1712 rRange = aEmbedRange;
1715 tools::Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
1717 tools::Rectangle aRect;
1718 ScTable* pTable = nullptr;
1719 if (aEmbedRange.aStart.Tab() < GetTableCount())
1720 pTable = maTabs[aEmbedRange.aStart.Tab()].get();
1721 else
1722 OSL_FAIL("table out of range");
1723 if (!pTable)
1725 OSL_FAIL("GetEmbeddedRect without a table");
1727 else
1729 SCCOL i;
1731 for (i=0; i<aEmbedRange.aStart.Col(); i++)
1732 aRect.AdjustLeft(pTable->GetColWidth(i) );
1733 aRect.AdjustTop(pTable->GetRowHeight( 0, aEmbedRange.aStart.Row() - 1) );
1734 aRect.SetRight( aRect.Left() );
1735 for (i=aEmbedRange.aStart.Col(); i<=aEmbedRange.aEnd.Col(); i++)
1736 aRect.AdjustRight(pTable->GetColWidth(i) );
1737 aRect.SetBottom( aRect.Top() );
1738 aRect.AdjustBottom(pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row()) );
1740 aRect = o3tl::convert(aRect, o3tl::Length::twip, o3tl::Length::mm100);
1742 return aRect;
1745 void ScDocument::SetEmbedded( const ScRange& rRange )
1747 bIsEmbedded = true;
1748 aEmbedRange = rRange;
1751 void ScDocument::ResetEmbedded()
1753 bIsEmbedded = false;
1754 aEmbedRange = ScRange();
1757 /** Similar to ScViewData::AddPixelsWhile(), but add height twips and only
1758 while result is less than nStopTwips.
1759 @return true if advanced at least one row.
1761 static bool lcl_AddTwipsWhile( tools::Long & rTwips, tools::Long nStopTwips, SCROW & rPosY, SCROW nEndRow, const ScTable * pTable, bool bHiddenAsZero )
1763 SCROW nRow = rPosY;
1764 bool bAdded = false;
1765 bool bStop = false;
1766 while (rTwips < nStopTwips && nRow <= nEndRow && !bStop)
1768 SCROW nHeightEndRow;
1769 sal_uInt16 nHeight = pTable->GetRowHeight( nRow, nullptr, &nHeightEndRow, bHiddenAsZero );
1770 if (nHeightEndRow > nEndRow)
1771 nHeightEndRow = nEndRow;
1772 if (!nHeight)
1773 nRow = nHeightEndRow + 1;
1774 else
1776 SCROW nRows = nHeightEndRow - nRow + 1;
1777 sal_Int64 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
1778 if (nAdd + rTwips >= nStopTwips)
1780 sal_Int64 nDiff = nAdd + rTwips - nStopTwips;
1781 nRows -= static_cast<SCROW>(nDiff / nHeight);
1782 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
1783 // We're looking for a value that satisfies loop condition.
1784 if (nAdd + rTwips >= nStopTwips)
1786 --nRows;
1787 nAdd -= nHeight;
1789 bStop = true;
1791 rTwips += static_cast<tools::Long>(nAdd);
1792 nRow += nRows;
1795 if (nRow > rPosY)
1797 --nRow;
1798 bAdded = true;
1800 rPosY = nRow;
1801 return bAdded;
1804 ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool bHiddenAsZero ) const
1806 ScTable* pTable = nullptr;
1807 if (nTab < GetTableCount())
1808 pTable = maTabs[nTab].get();
1809 else
1810 OSL_FAIL("table out of range");
1811 if (!pTable)
1813 OSL_FAIL("GetRange without a table");
1814 return ScRange();
1817 tools::Rectangle aPosRect = o3tl::convert(rMMRect, o3tl::Length::mm100, o3tl::Length::twip);
1818 if ( IsNegativePage( nTab ) )
1819 ScDrawLayer::MirrorRectRTL( aPosRect ); // Always with positive (LTR) values
1821 tools::Long nSize;
1822 tools::Long nTwips;
1823 tools::Long nAdd;
1824 bool bEnd;
1826 nSize = 0;
1827 nTwips = aPosRect.Left();
1829 SCCOL nX1 = 0;
1830 bEnd = false;
1831 while (!bEnd)
1833 nAdd = pTable->GetColWidth(nX1, bHiddenAsZero);
1834 if (nSize+nAdd <= nTwips+1 && nX1<MaxCol())
1836 nSize += nAdd;
1837 ++nX1;
1839 else
1840 bEnd = true;
1844 SCCOL nX2 = nX1;
1845 if (!aPosRect.IsEmpty())
1847 bEnd = false;
1848 nTwips = aPosRect.Right();
1849 while (!bEnd)
1851 nAdd = pTable->GetColWidth(nX2, bHiddenAsZero);
1852 if (nSize+nAdd < nTwips && nX2<MaxCol())
1854 nSize += nAdd;
1855 ++nX2;
1857 else
1858 bEnd = true;
1862 nSize = 0;
1863 nTwips = aPosRect.Top();
1865 SCROW nY1 = 0;
1866 // Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
1867 if (lcl_AddTwipsWhile( nSize, nTwips+2, nY1, MaxRow(), pTable, bHiddenAsZero) && nY1 < MaxRow())
1868 ++nY1; // original loop ended on last matched +1 unless that was rDoc.MaxRow()
1870 SCROW nY2 = nY1;
1871 if (!aPosRect.IsEmpty())
1873 nTwips = aPosRect.Bottom();
1874 // Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
1875 if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MaxRow(), pTable, bHiddenAsZero) && nY2 < MaxRow())
1876 ++nY2; // original loop ended on last matched +1 unless that was rDoc.MaxRow()
1879 return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
1882 void ScDocument::SetEmbedded( SCTAB nTab, const tools::Rectangle& rRect ) // From VisArea (1/100 mm)
1884 bIsEmbedded = true;
1885 aEmbedRange = GetRange( nTab, rRect );
1888 ScDocProtection* ScDocument::GetDocProtection() const
1890 return pDocProtection.get();
1893 void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
1895 if (pProtect)
1896 pDocProtection.reset(new ScDocProtection(*pProtect));
1897 else
1898 pDocProtection.reset();
1901 bool ScDocument::IsDocProtected() const
1903 return pDocProtection && pDocProtection->isProtected();
1906 bool ScDocument::IsDocEditable() const
1908 // Import into read-only document is possible
1909 return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !mpShell || !mpShell->IsReadOnly() );
1912 bool ScDocument::IsTabProtected( SCTAB nTab ) const
1914 if (const ScTable* pTable = FetchTable(nTab))
1915 return pTable->IsProtected();
1917 OSL_FAIL("Wrong table number");
1918 return false;
1921 const ScTableProtection* ScDocument::GetTabProtection(SCTAB nTab) const
1923 if (const ScTable* pTable = FetchTable(nTab))
1924 return pTable->GetProtection();
1926 return nullptr;
1929 void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
1931 if (ScTable* pTable = FetchTable(nTab))
1932 pTable->SetProtection(pProtect);
1935 void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
1937 if (!HasTable(nTabSrc) || !HasTable(nTabDest))
1938 return;
1940 maTabs[nTabDest]->SetProtection( maTabs[nTabSrc]->GetProtection() );
1943 const ScDocOptions& ScDocument::GetDocOptions() const
1945 assert(pDocOptions && "No DocOptions! :-(");
1946 return *pDocOptions;
1949 void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
1951 assert(pDocOptions && "No DocOptions! :-(");
1953 *pDocOptions = rOpt;
1954 if (mxPoolHelper)
1955 mxPoolHelper->SetFormTableOpt(rOpt);
1958 const ScViewOptions& ScDocument::GetViewOptions() const
1960 assert(pViewOptions && "No ViewOptions! :-(");
1961 return *pViewOptions;
1964 void ScDocument::SetViewOptions( const ScViewOptions& rOpt )
1966 assert(pViewOptions && "No ViewOptions! :-(");
1967 *pViewOptions = rOpt;
1970 void ScDocument::GetLanguage( LanguageType& rLatin, LanguageType& rCjk, LanguageType& rCtl ) const
1972 rLatin = eLanguage;
1973 rCjk = eCjkLanguage;
1974 rCtl = eCtlLanguage;
1977 void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageType eCtl )
1979 eLanguage = eLatin;
1980 eCjkLanguage = eCjk;
1981 eCtlLanguage = eCtl;
1982 if ( mxPoolHelper.is() )
1984 ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
1985 pPool->SetUserDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
1986 pPool->SetUserDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
1987 pPool->SetUserDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
1990 UpdateDrawLanguages(); // Set edit engine defaults in drawing layer pool
1993 tools::Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
1995 if (!HasTable(nTab))
1997 OSL_FAIL("GetMMRect: wrong table");
1998 return tools::Rectangle(0,0,0,0);
2001 SCCOL i;
2002 tools::Rectangle aRect;
2004 for (i=0; i<nStartCol; i++)
2005 aRect.AdjustLeft(GetColWidth(i,nTab, bHiddenAsZero ) );
2006 aRect.AdjustTop(GetRowHeight( 0, nStartRow-1, nTab, bHiddenAsZero ) );
2008 aRect.SetRight( aRect.Left() );
2009 aRect.SetBottom( aRect.Top() );
2011 for (i=nStartCol; i<=nEndCol; i++)
2012 aRect.AdjustRight(GetColWidth(i,nTab, bHiddenAsZero) );
2013 aRect.AdjustBottom(GetRowHeight( nStartRow, nEndRow, nTab, bHiddenAsZero ) );
2015 aRect = o3tl::convert(aRect, o3tl::Length::twip, o3tl::Length::mm100);
2017 if ( IsNegativePage( nTab ) )
2018 ScDrawLayer::MirrorRectRTL( aRect );
2020 return aRect;
2023 void ScDocument::SetExtDocOptions( std::unique_ptr<ScExtDocOptions> pNewOptions )
2025 pExtDocOptions = std::move(pNewOptions);
2028 void ScDocument::SetClipOptions(std::unique_ptr<ScClipOptions> pClipOptions)
2030 mpClipOptions = std::move(pClipOptions);
2033 void ScDocument::DoMergeContents( SCCOL nStartCol, SCROW nStartRow,
2034 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
2036 OUStringBuffer aTotal;
2037 OUString aCellStr;
2038 SCCOL nCol;
2039 SCROW nRow;
2040 ScCellValue aCell;
2041 for (nRow=nStartRow; nRow<=nEndRow; nRow++)
2042 for (nCol=nStartCol; nCol<=nEndCol; nCol++)
2044 aCellStr = GetString(nCol, nRow, nTab);
2045 if (!aCellStr.isEmpty())
2047 if (!aTotal.isEmpty())
2048 aTotal.append(' ');
2049 aTotal.append(aCellStr);
2050 ScAddress aPos(nCol, nRow, nTab);
2051 if ((GetCellType(aPos) == CELLTYPE_EDIT) && aCell.isEmpty())
2052 aCell = ScRefCellValue(*this, aPos);
2054 if (nCol != nStartCol || nRow != nStartRow)
2055 SetString(nCol,nRow,nTab,u""_ustr);
2058 if (aCell.isEmpty() || !GetString(nStartCol, nStartRow, nTab).isEmpty())
2059 SetString(nStartCol, nStartRow, nTab, aTotal.makeStringAndClear());
2060 else
2061 aCell.release(*this, ScAddress(nStartCol, nStartRow, nTab));
2064 void ScDocument::DoEmptyBlock( SCCOL nStartCol, SCROW nStartRow,
2065 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
2067 SCCOL nCol;
2068 SCROW nRow;
2069 for (nRow=nStartRow; nRow<=nEndRow; nRow++)
2070 for (nCol=nStartCol; nCol<=nEndCol; nCol++)
2071 { // empty block except first cell
2072 if (nCol != nStartCol || nRow != nStartRow)
2073 SetString(nCol,nRow,nTab,u""_ustr);
2077 void ScDocument::DoMerge( SCCOL nStartCol, SCROW nStartRow,
2078 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bDeleteCaptions )
2080 ScTable* pTab = FetchTable(nTab);
2081 if (!pTab)
2082 return;
2084 pTab->SetMergedCells(nStartCol, nStartRow, nEndCol, nEndRow);
2086 // Remove all covered notes (removed captions are collected by drawing undo if active)
2087 InsertDeleteFlags nDelFlag = InsertDeleteFlags::NOTE | (bDeleteCaptions ? InsertDeleteFlags::NONE : InsertDeleteFlags::NOCAPTIONS);
2088 if( nStartCol < nEndCol )
2089 DeleteAreaTab( nStartCol + 1, nStartRow, nEndCol, nStartRow, nTab, nDelFlag );
2090 if( nStartRow < nEndRow )
2091 DeleteAreaTab( nStartCol, nStartRow + 1, nEndCol, nEndRow, nTab, nDelFlag );
2094 void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
2096 const ScMergeAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE );
2098 if ( pAttr->GetColMerge() <= 1 && pAttr->GetRowMerge() <= 1 )
2099 return;
2101 SCCOL nEndCol = nCol + pAttr->GetColMerge() - 1;
2102 SCROW nEndRow = nRow + pAttr->GetRowMerge() - 1;
2104 RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
2106 const ScMergeAttr* pDefAttr = &mxPoolHelper->GetDocPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
2107 ApplyAttr( nCol, nRow, nTab, *pDefAttr );
2110 void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
2111 SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) const
2113 if (HasTable(nTab))
2114 maTabs[nTab]->ExtendPrintArea(pDev, nStartCol, nStartRow, rEndCol, nEndRow);
2117 SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol ) const
2119 if (const ScTable* pTable = FetchTable(nTab))
2120 return pTable->GetPatternCount( nCol );
2121 else
2122 return 0;
2125 SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
2127 if (const ScTable* pTable = FetchTable(nTab))
2128 return pTable->GetPatternCount(nCol, nRow1, nRow2);
2129 return 0;
2132 void ScDocument::ReservePatternCount( SCTAB nTab, SCCOL nCol, SCSIZE nReserve )
2134 if (ScTable* pTable = FetchTable(nTab))
2135 pTable->ReservePatternCount(nCol, nReserve);
2138 void ScDocument::GetSortParam( ScSortParam& rParam, SCTAB nTab )
2140 rParam = mSheetSortParams[ nTab ];
2143 void ScDocument::SetSortParam( const ScSortParam& rParam, SCTAB nTab )
2145 mSheetSortParams[ nTab ] = rParam;
2148 SCCOL ScDocument::ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const
2150 return maTabs[nTab]->ClampToAllocatedColumns(nCol);
2153 SCCOL ScDocument::GetAllocatedColumnsCount(SCTAB nTab) const
2155 return maTabs[nTab]->GetAllocatedColumnsCount();
2158 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */