1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/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>
36 #include <rangenam.hxx>
38 #include <docpool.hxx>
40 #include <poolhelp.hxx>
41 #include <rangelst.hxx>
42 #include <chartlock.hxx>
43 #include <refupdat.hxx>
44 #include <docoptio.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>
58 #include <globstr.hrc>
59 #include <scresid.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>
82 using namespace com::sun::star
;
86 void sortAndRemoveDuplicates(std::vector
<ScTypedStrData
>& rStrings
, bool 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());
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
)
118 // no more tables to iterate through.
121 const ScRangeName
* p
= maTabs
[i
]->mpRangeName
.get();
122 if (!p
|| p
->empty())
123 // ignore empty ones.
126 aNames
.emplace(i
, p
);
131 void ScDocument::SetAllRangeNames(const std::map
<OUString
, ScRangeName
>& rRangeMap
)
133 for (const auto& [rName
, rRangeName
] : rRangeMap
)
135 if (rName
== STR_GLOBAL_RANGE_NAME
)
138 if (!rRangeName
.empty())
139 pRangeName
.reset( new ScRangeName( rRangeName
) );
144 bool bFound
= GetTable(rName
, nTab
);
145 assert(bFound
); (void)bFound
; // fouled up?
146 if (rRangeName
.empty())
147 SetRangeName( nTab
, nullptr );
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
)
160 ScRangeName
* p
= maTabs
[i
]->GetRangeName();
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
));
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();
183 ScRangeName
* ScDocument::GetRangeName() const
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
;
206 if (eScope
== RangeNameScope::GLOBAL
)
207 pRangeNames
= GetRangeName();
209 pRangeNames
= GetRangeName(rAddress
.Tab());
211 for (const auto& rEntry
: *pRangeNames
)
213 if (rEntry
.second
->IsValidReference(aNameRange
))
215 if (aNameRange
.Contains(rAddress
))
223 bool ScDocument::InsertNewRangeName( const OUString
& rName
, const ScAddress
& rPos
, const OUString
& rExpr
)
225 ScRangeName
* pGlobalNames
= GetRangeName();
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
);
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());
251 pData
= pLocalNames
->findByRange( rBlock
);
254 rName
= pData
->GetName();
263 pData
= pRangeName
->findByRange( rBlock
);
266 rName
= pData
->GetName();
268 *pSheetLocal
= false;
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())
295 rOldData
.GetArea(aOldRange
);
298 if (pNewDBCollection
)
300 ScDBData
* pNewData
= pNewDBCollection
->getNamedDBs().findByUpperName(rOldData
.GetUpperName());
303 if (pNewData
->HasAutoFilter())
306 pNewData
->GetArea(aNewRange
);
307 if (aOldRange
.aStart
== aNewRange
.aStart
)
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
330 return pDBCollection
->GetDBAtCursor(nCol
, nRow
, nTab
, ePortion
);
335 ScDBData
* ScDocument::GetDBAtCursor(SCCOL nCol
, SCROW nRow
, SCTAB nTab
, ScDBDataPortion ePortion
)
338 return pDBCollection
->GetDBAtCursor(nCol
, nRow
, nTab
, ePortion
);
343 const ScDBData
* ScDocument::GetDBAtArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
346 return pDBCollection
->GetDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
351 ScDBData
* ScDocument::GetDBAtArea(SCTAB nTab
, SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
354 return pDBCollection
->GetDBAtArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
359 void ScDocument::RefreshDirtyTableColumnNames()
362 pDBCollection
->RefreshDirtyTableColumnNames();
365 bool ScDocument::HasPivotTable() const
367 return pDPCollection
&& pDPCollection
->GetCount();
370 ScDPCollection
* ScDocument::GetDPCollection()
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
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
];
396 ScDPObject
* ScDocument::GetDPAtBlock( const ScRange
& rBlock
) const
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();
405 if ( (*pDPCollection
)[i
].GetOutRange().Contains( rBlock
) )
406 return &(*pDPCollection
)[i
];
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
)
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();
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
;
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
)
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();
521 OUString
ScDocument::GetLinkFlt( SCTAB nTab
) const
523 if (const ScTable
* pTable
= FetchTable(nTab
))
524 return pTable
->GetLinkFlt();
528 OUString
ScDocument::GetLinkOpt( SCTAB nTab
) const
530 if (const ScTable
* pTable
= FetchTable(nTab
))
531 return pTable
->GetLinkOpt();
535 OUString
ScDocument::GetLinkTab( SCTAB nTab
) const
537 if (const ScTable
* pTable
= FetchTable(nTab
))
538 return pTable
->GetLinkTab();
542 sal_Int32
ScDocument::GetLinkRefreshDelay( SCTAB nTab
) const
544 if (const ScTable
* pTable
= FetchTable(nTab
))
545 return pTable
->GetLinkRefreshDelay();
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
)
571 bool ScDocument::LinkExternalTab( SCTAB
& rTab
, const OUString
& aDocTab
,
572 const OUString
& aFileName
, const OUString
& aTabName
)
576 OSL_FAIL( "LinkExternalTab in Clipboard" );
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() )
592 ScDocument
* pSrcDoc
= aLoader
.GetDocument();
596 if ( pSrcDoc
->GetTable( aTabName
, nSrcTab
) )
598 if ( !InsertTab( SC_TAB_APPEND
, aDocTab
, true ) )
600 OSL_FAIL("can't insert external document table");
603 rTab
= GetTableCount() - 1;
604 // Don't insert anew, just the results
605 TransferTab( *pSrcDoc
, nSrcTab
, rTab
, false, true );
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
);
621 pLink
->SetInCreate( false );
622 SfxBindings
* pBindings
= GetViewBindings();
624 pBindings
->Invalidate( SID_LINKS
);
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
)
648 if (!pExternalRefMgr
->hasExternalData())
651 pExternalRefMgr
->markUsedByLinkListeners();
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();
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
) )
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
>() ))
695 catch( uno::Exception
& )
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
))
711 bool ScDocument::HasAnyCalcNotification() const
713 SCTAB nSize
= GetTableCount();
714 for (SCTAB nTab
= 0; nTab
< nSize
; nTab
++)
715 if (maTabs
[nTab
] && maTabs
[nTab
]->GetCalcNotification())
720 bool ScDocument::HasCalcNotification( SCTAB nTab
) const
722 if (const ScTable
* pTable
= FetchTable(nTab
))
723 return pTable
->GetCalcNotification();
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();
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
)
798 if (aIter
.getFormulaCell()->IsSubTotal())
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
))
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();
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
) )
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
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();
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");
906 void ScDocument::AddUnoObject( SfxListener
& rObject
)
908 if (!pUnoBroadcaster
)
909 pUnoBroadcaster
.reset( new SfxBroadcaster
);
911 rObject
.StartListening( *pUnoBroadcaster
);
914 void ScDocument::RemoveUnoObject( SfxListener
& rObject
)
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
;
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" );
943 // Let the thread that called BroadcastUno continue
944 while ( bInUnoBroadcast
)
946 osl::Thread::yield();
953 OSL_FAIL("No Uno broadcaster");
957 void ScDocument::BroadcastUno( const SfxHint
&rHint
)
959 if (!pUnoBroadcaster
)
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()))))
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();
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
);
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
);
1060 pDetOpList
->UpdateReference( this, eUpdateRefMode
, aRange
, nDx
, nDy
, nDz
);
1061 if ( pUnoBroadcaster
)
1062 pUnoBroadcaster
->Broadcast( ScUpdateRefHint(
1063 eUpdateRefMode
, aRange
, nDx
, nDy
, nDz
) );
1066 nLastTab
= maTabs
.size()-1;
1069 for (size_t i
= nFirstTab
, n
= maTabs
.size() ; i
<= nLastTab
&& i
< n
; ++i
)
1074 maTabs
[i
]->UpdateReference(rCxt
, pUndoDoc
, bIncludeDraw
, bUpdateNoteCaptionPos
);
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();
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");
1123 ScClipParam
& rClipParam
= pClipDoc
->GetClipParam();
1124 if (!rClipParam
.maRanges
.empty())
1125 aSource
= rClipParam
.maRanges
.front();
1126 ScAddress aDest
= rDestPos
;
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
1139 pRangeName
->UpdateTranspose( aSource
, aDest
); // Before the cells!
1140 for (SCTAB i
= 0; i
< GetTableCount(); 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
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
)
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
);
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
)
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() )
1234 else if ( bReplace
)
1247 if ( rSearchItem
.GetPattern() )
1252 else if ( bReplace
)
1266 if ( rSearchItem
.GetRowDirection() )
1268 if ( rSearchItem
.GetPattern() )
1273 else if ( bReplace
)
1286 if ( rSearchItem
.GetPattern() )
1291 else if ( bReplace
)
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");
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
)
1336 if (maTabs
[rMarkedTab
])
1340 bFound
|= maTabs
[rMarkedTab
]->SearchAndReplace(
1341 rSearchItem
, nCol
, nRow
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
, bMatchedRangesWereClamped
);
1345 // Mark is set completely inside already
1351 if (rSearchItem
.GetBackward())
1353 for (nTab
= rTab
; (nTab
>= 0) && !bFound
; nTab
--)
1356 if (rMark
.GetTableSelect(nTab
))
1358 bFound
= maTabs
[nTab
]->SearchAndReplace(
1359 rSearchItem
, nCol
, nRow
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
, bMatchedRangesWereClamped
);
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
);
1384 for (nTab
= rTab
; (nTab
< GetTableCount()) && !bFound
; nTab
++)
1387 if (rMark
.GetTableSelect(nTab
))
1389 bFound
= maTabs
[nTab
]->SearchAndReplace(
1390 rSearchItem
, nCol
, nRow
, rMark
, rMatchedRanges
, rUndoStr
, pUndoDoc
, bMatchedRangesWereClamped
);
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
);
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");
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");
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();
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());
1458 bool bOldEnableIdle
= IsIdleEnabled();
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
);
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");
1483 OUString
ScDocument::GetUpperCellString(SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
1485 if (ScTable
* pTable
= FetchTable(nTab
))
1486 return pTable
->GetUpperCellString( nCol
, nRow
);
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");
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);
1507 if ( pDBData
->HasHeader() )
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;
1526 bHasAutoFilter
= false;
1529 return bHasAutoFilter
;
1532 bool ScDocument::HasColHeader( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
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
,
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
)
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
)
1568 ScDBData
* pDBData
= pDBCollection
->GetDBAtCursor(nCol
, nRow
, nTab
, ScDBDataPortion::AREA
); //!??
1572 pDBData
->ExtendBackColorArea(*this);
1573 pDBData
->ExtendDataArea(*this);
1579 pDBData
->GetArea( nAreaTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
1581 if (pDBData
->HasHeader())
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
)
1602 maTabs
[nTab
]->GetFilteredFilterEntries( nCol
, nStartRow
, nEndRow
, aParam
, rFilterEntries
, bFilter
);
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
)
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();
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*/);
1652 if (!HasTable(nTab
))
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
)
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
)
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())
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();
1722 OSL_FAIL("table out of range");
1725 OSL_FAIL("GetEmbeddedRect without a table");
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
);
1745 void ScDocument::SetEmbedded( const ScRange
& rRange
)
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
)
1764 bool bAdded
= 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
;
1773 nRow
= nHeightEndRow
+ 1;
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
)
1791 rTwips
+= static_cast<tools::Long
>(nAdd
);
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();
1810 OSL_FAIL("table out of range");
1813 OSL_FAIL("GetRange without a table");
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
1827 nTwips
= aPosRect
.Left();
1833 nAdd
= pTable
->GetColWidth(nX1
, bHiddenAsZero
);
1834 if (nSize
+nAdd
<= nTwips
+1 && nX1
<MaxCol())
1845 if (!aPosRect
.IsEmpty())
1848 nTwips
= aPosRect
.Right();
1851 nAdd
= pTable
->GetColWidth(nX2
, bHiddenAsZero
);
1852 if (nSize
+nAdd
< nTwips
&& nX2
<MaxCol())
1863 nTwips
= aPosRect
.Top();
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()
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)
1885 aEmbedRange
= GetRange( nTab
, rRect
);
1888 ScDocProtection
* ScDocument::GetDocProtection() const
1890 return pDocProtection
.get();
1893 void ScDocument::SetDocProtection(const ScDocProtection
* pProtect
)
1896 pDocProtection
.reset(new ScDocProtection(*pProtect
));
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");
1921 const ScTableProtection
* ScDocument::GetTabProtection(SCTAB nTab
) const
1923 if (const ScTable
* pTable
= FetchTable(nTab
))
1924 return pTable
->GetProtection();
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
))
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
;
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
1973 rCjk
= eCjkLanguage
;
1974 rCtl
= eCtlLanguage
;
1977 void ScDocument::SetLanguage( LanguageType eLatin
, LanguageType eCjk
, LanguageType eCtl
)
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);
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
);
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
;
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())
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());
2061 aCell
.release(*this, ScAddress(nStartCol
, nStartRow
, nTab
));
2064 void ScDocument::DoEmptyBlock( SCCOL nStartCol
, SCROW nStartRow
,
2065 SCCOL nEndCol
, SCROW nEndRow
, SCTAB nTab
)
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
);
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 )
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
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
);
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
);
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: */