fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / document.cxx
blobbb6431a84783b41e7a27f0f12e434642c0209960
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 "scitems.hxx"
21 #include <editeng/eeitem.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <editeng/frmdiritem.hxx>
25 #include <editeng/editobj.hxx>
26 #include <svx/pageitem.hxx>
27 #include <editeng/editeng.hxx>
28 #include <svx/sdrundomanager.hxx>
29 #include <svx/svditer.hxx>
30 #include <svx/svdpage.hxx>
31 #include <svx/svdocapt.hxx>
32 #include <sfx2/app.hxx>
33 #include <sfx2/objsh.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <svl/poolcach.hxx>
36 #include <unotools/saveopt.hxx>
37 #include <svl/zforlist.hxx>
38 #include <unotools/charclass.hxx>
39 #include <unotools/transliterationwrapper.hxx>
40 #include <tools/tenccvt.hxx>
41 #include <tools/urlobj.hxx>
43 #include <com/sun/star/text/WritingMode2.hpp>
44 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
45 #include <com/sun/star/sheet/TablePageBreakData.hpp>
46 #include <com/sun/star/lang/NotInitializedException.hpp>
48 #include "document.hxx"
49 #include "table.hxx"
50 #include "attrib.hxx"
51 #include "attarray.hxx"
52 #include "markarr.hxx"
53 #include "patattr.hxx"
54 #include "rangenam.hxx"
55 #include "poolhelp.hxx"
56 #include "docpool.hxx"
57 #include "stlpool.hxx"
58 #include "stlsheet.hxx"
59 #include "globstr.hrc"
60 #include "rechead.hxx"
61 #include "dbdata.hxx"
62 #include "pivot.hxx"
63 #include "chartlis.hxx"
64 #include "rangelst.hxx"
65 #include "markdata.hxx"
66 #include "drwlayer.hxx"
67 #include "conditio.hxx"
68 #include "colorscale.hxx"
69 #include "validat.hxx"
70 #include "prnsave.hxx"
71 #include "chgtrack.hxx"
72 #include "sc.hrc"
73 #include "scresid.hxx"
74 #include "hints.hxx"
75 #include "detdata.hxx"
76 #include "dpobject.hxx"
77 #include "detfunc.hxx"
78 #include "scmod.hxx"
79 #include "dociter.hxx"
80 #include "progress.hxx"
81 #include "autonamecache.hxx"
82 #include "bcaslot.hxx"
83 #include "postit.hxx"
84 #include "externalrefmgr.hxx"
85 #include "tabprotection.hxx"
86 #include "clipparam.hxx"
87 #include "defaultsoptions.hxx"
88 #include "editutil.hxx"
89 #include "stringutil.hxx"
90 #include "formulaiter.hxx"
91 #include "formulacell.hxx"
92 #include "clipcontext.hxx"
93 #include "listenercontext.hxx"
94 #include "scopetools.hxx"
95 #include "refupdatecontext.hxx"
96 #include "formulagroup.hxx"
97 #include <tokenarray.hxx>
98 #include <tokenstringcontext.hxx>
100 #include <formula/vectortoken.hxx>
102 #include <map>
103 #include <limits>
104 #include <boost/checked_delete.hpp>
105 #include <boost/scoped_ptr.hpp>
107 #include "mtvelements.hxx"
109 using ::editeng::SvxBorderLine;
110 using namespace ::com::sun::star;
112 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
113 using ::com::sun::star::uno::Sequence;
114 using ::com::sun::star::sheet::TablePageBreakData;
115 using ::std::set;
117 namespace {
119 std::pair<SCTAB,SCTAB> getMarkedTableRange(const std::vector<ScTable*>& rTables, const ScMarkData& rMark)
121 SCTAB nTabStart = MAXTAB;
122 SCTAB nTabEnd = 0;
123 SCTAB nMax = static_cast<SCTAB>(rTables.size());
124 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
125 for (; itr != itrEnd && *itr < nMax; ++itr)
127 if (!rTables[*itr])
128 continue;
130 if (*itr < nTabStart)
131 nTabStart = *itr;
132 nTabEnd = *itr;
135 return std::pair<SCTAB,SCTAB>(nTabStart,nTabEnd);
140 struct ScDefaultAttr
142 const ScPatternAttr* pAttr;
143 SCROW nFirst;
144 SCSIZE nCount;
145 ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
148 struct ScLessDefaultAttr
150 bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
152 return rValue1.pAttr < rValue2.pAttr;
156 typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
158 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
160 if ( ValidTab(nTab) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab]) )
162 // Get Custom prefix
163 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
164 OUString aString = rOpt.GetInitTabPrefix();
166 aString += OUString::number(nTab+1);
167 if ( _bNeedsNameCheck )
168 CreateValidTabName( aString ); // no doubles
169 if (nTab < static_cast<SCTAB>(maTabs.size()))
171 maTabs[nTab] = new ScTable(this, nTab, aString);
173 else
175 while(nTab > static_cast<SCTAB>(maTabs.size()))
176 maTabs.push_back(NULL);
177 maTabs.push_back( new ScTable(this, nTab, aString) );
179 maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
183 bool ScDocument::HasTable( SCTAB nTab ) const
185 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
186 if (maTabs[nTab])
187 return true;
189 return false;
192 bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
194 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
196 if (maTabs[nTab])
198 maTabs[nTab]->GetName( rName );
199 return true;
202 rName.clear();
203 return false;
206 OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
208 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabNames.size()))
209 return maTabNames[nTab];
210 return OUString();
213 bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
215 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
217 if (maTabs[nTab])
219 maTabs[nTab]->SetCodeName( rName );
220 return true;
223 OSL_TRACE( "**** can't set code name %s", OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
224 return false;
227 bool ScDocument::GetCodeName( SCTAB nTab, OUString& rName ) const
229 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
230 if (maTabs[nTab])
232 maTabs[nTab]->GetCodeName( rName );
233 return true;
235 rName.clear();
236 return false;
239 bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
241 OUString aUpperName;
242 static OUString aCacheName, aCacheUpperName;
244 if (aCacheName != rName)
246 aCacheName = rName;
247 // surprisingly slow ...
248 aCacheUpperName = ScGlobal::pCharClass->uppercase(rName);
250 aUpperName = aCacheUpperName;
252 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
253 if (maTabs[i])
255 if (aUpperName.equals(maTabs[i]->GetUpperName()))
257 rTab = i;
258 return true;
261 rTab = 0;
262 return false;
265 std::vector<OUString> ScDocument::GetAllTableNames() const
267 std::vector<OUString> aNames;
268 aNames.reserve(maTabs.size());
269 TableContainer::const_iterator it = maTabs.begin(), itEnd = maTabs.end();
270 for (; it != itEnd; ++it)
272 // Positions need to be preserved for ScCompiler and address convention
273 // context, so still push an empty string for NULL tabs.
274 OUString aName;
275 if (*it)
277 const ScTable& rTab = **it;
278 rTab.GetName(aName);
280 aNames.push_back(aName);
283 return aNames;
286 ScDBData* ScDocument::GetAnonymousDBData(SCTAB nTab)
288 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
289 return maTabs[nTab]->GetAnonymousDBData();
290 return NULL;
293 SCTAB ScDocument::GetTableCount() const
295 return static_cast<SCTAB>(maTabs.size());
298 void ScDocument::SetAnonymousDBData(SCTAB nTab, ScDBData* pDBData)
300 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
301 maTabs[nTab]->SetAnonymousDBData(pDBData);
304 bool ScDocument::ValidTabName( const OUString& rName )
306 if (rName.isEmpty())
307 return false;
308 sal_Int32 nLen = rName.getLength();
310 #if 1
311 // Restrict sheet names to what Excel accepts.
312 /* TODO: We may want to remove this restriction for full ODFF compliance.
313 * Merely loading and calculating ODF documents using these characters in
314 * sheet names is not affected by this, but all sheet name editing and
315 * copying functionality is, maybe falling back to "Sheet4" or similar. */
316 for (sal_Int32 i = 0; i < nLen; ++i)
318 const sal_Unicode c = rName[i];
319 switch (c)
321 case ':':
322 case '\\':
323 case '/':
324 case '?':
325 case '*':
326 case '[':
327 case ']':
328 // these characters are not allowed to match XL's convention.
329 return false;
330 case '\'':
331 if (i == 0 || i == nLen - 1)
332 // single quote is not allowed at the first or last
333 // character position.
334 return false;
335 break;
338 #endif
340 return true;
343 bool ScDocument::ValidNewTabName( const OUString& rName ) const
345 bool bValid = ValidTabName(rName);
346 TableContainer::const_iterator it = maTabs.begin();
347 for (; it != maTabs.end() && bValid; ++it)
348 if ( *it )
350 OUString aOldName;
351 (*it)->GetName(aOldName);
352 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
354 return bValid;
357 void ScDocument::CreateValidTabName(OUString& rName) const
359 if ( !ValidTabName(rName) )
361 // Find new one
363 // Get Custom prefix
364 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
365 OUString aStrTable = rOpt.GetInitTabPrefix();
367 bool bOk = false;
369 // First test if the prefix is valid, if so only avoid doubles
370 bool bPrefix = ValidTabName( aStrTable );
371 OSL_ENSURE(bPrefix, "Invalid Table Name");
372 SCTAB nDummy;
374 for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
376 OUStringBuffer aBuf;
377 aBuf.append(aStrTable);
378 aBuf.append(static_cast<sal_Int32>(i));
379 rName = aBuf.makeStringAndClear();
380 if (bPrefix)
381 bOk = ValidNewTabName( rName );
382 else
383 bOk = !GetTable( rName, nDummy );
386 else
388 // testing the supplied Name
390 if ( !ValidNewTabName(rName) )
392 SCTAB i = 1;
393 OUStringBuffer aName;
396 i++;
397 aName = rName;
398 aName.append('_');
399 aName.append(static_cast<sal_Int32>(i));
401 while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
402 rName = aName.makeStringAndClear();
407 void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount) const
409 aNames.clear();//ensure that the vector is empty
411 // Get Custom prefix
412 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
413 OUString aStrTable = rOpt.GetInitTabPrefix();
415 OUStringBuffer rName;
416 bool bOk = false;
418 // First test if the prefix is valid, if so only avoid doubles
419 bool bPrefix = ValidTabName( aStrTable );
420 OSL_ENSURE(bPrefix, "Invalid Table Name");
421 SCTAB nDummy;
422 SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
424 for (SCTAB j = 0; j < nCount; ++j)
426 bOk = false;
427 while(!bOk)
429 rName = aStrTable;
430 rName.append(static_cast<sal_Int32>(i));
431 if (bPrefix)
432 bOk = ValidNewTabName( rName.toString() );
433 else
434 bOk = !GetTable( rName.toString(), nDummy );
435 i++;
437 aNames.push_back(rName.makeStringAndClear());
441 void ScDocument::AppendTabOnLoad(const OUString& rName)
443 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
444 if (!ValidTab(nTabCount))
445 // max table count reached. No more tables.
446 return;
448 OUString aName = rName;
449 CreateValidTabName(aName);
450 maTabs.push_back( new ScTable(this, nTabCount, aName) );
453 void ScDocument::SetTabNameOnLoad(SCTAB nTab, const OUString& rName)
455 if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
456 return;
458 if (!ValidTabName(rName))
459 return;
461 maTabs[nTab]->SetName(rName);
464 void ScDocument::InvalidateStreamOnSave()
466 TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
467 for (; it != itEnd; ++it)
469 ScTable* pTab = *it;
470 if (pTab)
471 pTab->SetStreamValid(false);
475 bool ScDocument::InsertTab(
476 SCTAB nPos, const OUString& rName, bool bExternalDocument, bool bUndoDeleteTab )
478 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
479 bool bValid = ValidTab(nTabCount);
480 if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
481 bValid = (bValid && ValidNewTabName(rName));
482 if (bValid)
484 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
486 nPos = maTabs.size();
487 maTabs.push_back( new ScTable(this, nTabCount, rName) );
488 if ( bExternalDocument )
489 maTabs[nTabCount]->SetVisible( false );
491 else
493 if (ValidTab(nPos) && (nPos < nTabCount))
495 sc::RefUpdateInsertTabContext aCxt( *this, nPos, 1);
497 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
498 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
499 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
500 if (pRangeName)
501 pRangeName->UpdateInsertTab(aCxt);
502 pDBCollection->UpdateReference(
503 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
504 if (pDPCollection)
505 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
506 if (pDetOpList)
507 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
508 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
509 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
510 if ( pUnoBroadcaster )
511 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
513 SCTAB i;
514 TableContainer::iterator it = maTabs.begin();
515 for (; it != maTabs.end(); ++it)
516 if ( *it )
517 (*it)->UpdateInsertTab(aCxt);
518 maTabs.push_back(NULL);
519 for (i = nTabCount; i > nPos; i--)
521 maTabs[i] = maTabs[i - 1];
524 maTabs[nPos] = new ScTable(this, nPos, rName);
526 // UpdateBroadcastAreas must be called between UpdateInsertTab,
527 // which ends listening, and StartAllListeners, to not modify
528 // areas that are to be inserted by starting listeners.
529 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
530 it = maTabs.begin();
531 for (; it != maTabs.end(); ++it)
532 if ( *it )
533 (*it)->UpdateCompile();
535 StartAllListeners();
537 if (pValidationList)
538 pValidationList->UpdateInsertTab(aCxt);
540 // sheet names of references are not valid until sheet is inserted
541 if ( pChartListenerCollection )
542 pChartListenerCollection->UpdateScheduledSeriesRanges();
544 bValid = true;
546 else
547 bValid = false;
551 if (bValid)
553 sc::SetFormulaDirtyContext aCxt;
554 aCxt.mbClearTabDeletedFlag = bUndoDeleteTab;
555 aCxt.mnTabDeletedStart = nPos;
556 aCxt.mnTabDeletedEnd = nPos;
557 SetAllFormulasDirty(aCxt);
560 return bValid;
563 bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
564 bool bExternalDocument, bool bNamesValid )
566 SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
567 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
568 bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
570 if (bValid)
572 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
574 for ( SCTAB i = 0; i < nNewSheets; ++i )
576 maTabs.push_back( new ScTable(this, nTabCount + i, rNames.at(i)) );
577 if ( bExternalDocument )
578 maTabs[nTabCount+i]->SetVisible( false );
581 else
583 if (ValidTab(nPos) && (nPos < nTabCount))
585 sc::RefUpdateInsertTabContext aCxt( *this, nPos, nNewSheets);
586 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
587 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
588 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
589 if (pRangeName)
590 pRangeName->UpdateInsertTab(aCxt);
591 pDBCollection->UpdateReference(
592 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
593 if (pDPCollection)
594 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
595 if (pDetOpList)
596 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,nNewSheets );
597 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
598 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0, nNewSheets );
599 if ( pUnoBroadcaster )
600 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,nNewSheets ) );
602 TableContainer::iterator it = maTabs.begin();
603 for (; it != maTabs.end(); ++it)
604 if ( *it )
605 (*it)->UpdateInsertTab(aCxt);
606 it = maTabs.begin();
607 maTabs.insert(it+nPos,nNewSheets, NULL);
608 for (SCTAB i = 0; i < nNewSheets; ++i)
610 maTabs[nPos + i] = new ScTable(this, nPos + i, rNames.at(i));
613 // UpdateBroadcastAreas must be called between UpdateInsertTab,
614 // which ends listening, and StartAllListeners, to not modify
615 // areas that are to be inserted by starting listeners.
616 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,nNewSheets);
617 it = maTabs.begin();
618 for (; it != maTabs.end(); ++it)
620 if ( *it )
621 (*it)->UpdateCompile();
624 StartAllListeners();
626 if (pValidationList)
627 pValidationList->UpdateInsertTab(aCxt);
629 // sheet names of references are not valid until sheet is inserted
630 if ( pChartListenerCollection )
631 pChartListenerCollection->UpdateScheduledSeriesRanges();
633 bValid = true;
635 else
636 bValid = false;
640 if (bValid)
642 sc::SetFormulaDirtyContext aCxt;
643 SetAllFormulasDirty(aCxt);
646 return bValid;
649 bool ScDocument::DeleteTab( SCTAB nTab )
651 bool bValid = false;
652 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
654 if (maTabs[nTab])
656 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
657 if (nTabCount > 1)
659 sc::AutoCalcSwitch aACSwitch(*this, false);
660 sc::RefUpdateDeleteTabContext aCxt( *this, nTab, 1);
662 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
663 DelBroadcastAreasInRange( aRange );
665 // #i8180# remove database ranges etc. that are on the deleted tab
666 // (restored in undo with ScRefUndoData)
668 xColNameRanges->DeleteOnTab( nTab );
669 xRowNameRanges->DeleteOnTab( nTab );
670 pDBCollection->DeleteOnTab( nTab );
671 if (pDPCollection)
672 pDPCollection->DeleteOnTab( nTab );
673 if (pDetOpList)
674 pDetOpList->DeleteOnTab( nTab );
675 DeleteAreaLinksOnTab( nTab );
677 // normal reference update
679 aRange.aEnd.SetTab( static_cast<SCTAB>(maTabs.size())-1 );
680 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
681 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
682 if (pRangeName)
683 pRangeName->UpdateDeleteTab(aCxt);
684 pDBCollection->UpdateReference(
685 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
686 if (pDPCollection)
687 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
688 if (pDetOpList)
689 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
690 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
691 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
692 if (pValidationList)
693 pValidationList->UpdateDeleteTab(aCxt);
694 if ( pUnoBroadcaster )
695 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
697 for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
698 if (maTabs[i])
699 maTabs[i]->UpdateDeleteTab(aCxt);
701 TableContainer::iterator it = maTabs.begin() + nTab;
702 delete *it;
703 maTabs.erase(it);
704 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
705 // which ends listening, and StartAllListeners, to not modify
706 // areas that are to be inserted by starting listeners.
707 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
708 it = maTabs.begin();
709 for (; it != maTabs.end(); ++it)
710 if ( *it )
711 (*it)->UpdateCompile();
712 // Excel-Filter deletes some Tables while loading, Listeners will
713 // only be triggered after the loading is done.
714 if ( !bInsertingFromOtherDoc )
716 StartAllListeners();
718 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
719 SetAllFormulasDirty(aFormulaDirtyCxt);
721 // sheet names of references are not valid until sheet is deleted
722 pChartListenerCollection->UpdateScheduledSeriesRanges();
724 bValid = true;
728 return bValid;
731 bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets )
733 bool bValid = false;
734 if (ValidTab(nTab) && (nTab + nSheets) < static_cast<SCTAB>(maTabs.size()))
736 if (maTabs[nTab])
738 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
739 if (nTabCount > nSheets)
741 sc::AutoCalcSwitch aACSwitch(*this, false);
742 sc::RefUpdateDeleteTabContext aCxt( *this, nTab, nSheets);
744 for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
746 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab + aTab );
747 DelBroadcastAreasInRange( aRange );
749 // #i8180# remove database ranges etc. that are on the deleted tab
750 // (restored in undo with ScRefUndoData)
752 xColNameRanges->DeleteOnTab( nTab + aTab );
753 xRowNameRanges->DeleteOnTab( nTab + aTab );
754 pDBCollection->DeleteOnTab( nTab + aTab );
755 if (pDPCollection)
756 pDPCollection->DeleteOnTab( nTab + aTab );
757 if (pDetOpList)
758 pDetOpList->DeleteOnTab( nTab + aTab );
759 DeleteAreaLinksOnTab( nTab + aTab );
762 if (pRangeName)
763 pRangeName->UpdateDeleteTab(aCxt);
765 // normal reference update
767 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTabCount - 1 );
768 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
769 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
770 pDBCollection->UpdateReference(
771 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
772 if (pDPCollection)
773 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
774 if (pDetOpList)
775 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
776 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
777 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
778 if (pValidationList)
779 pValidationList->UpdateDeleteTab(aCxt);
780 if ( pUnoBroadcaster )
781 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
783 for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
784 if (maTabs[i])
785 maTabs[i]->UpdateDeleteTab(aCxt);
787 TableContainer::iterator it = maTabs.begin() + nTab;
788 TableContainer::iterator itEnd = it + nSheets;
789 std::for_each(it, itEnd, boost::checked_deleter<ScTable>());
790 maTabs.erase(it, itEnd);
791 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
792 // which ends listening, and StartAllListeners, to not modify
793 // areas that are to be inserted by starting listeners.
794 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
795 it = maTabs.begin();
796 for (; it != maTabs.end(); ++it)
797 if ( *it )
798 (*it)->UpdateCompile();
799 // Excel-Filter deletes some Tables while loading, Listeners will
800 // only be triggered after the loading is done.
801 if ( !bInsertingFromOtherDoc )
803 StartAllListeners();
805 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
806 SetAllFormulasDirty(aFormulaDirtyCxt);
808 // sheet names of references are not valid until sheet is deleted
809 pChartListenerCollection->UpdateScheduledSeriesRanges();
811 bValid = true;
815 return bValid;
818 bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool /* bUpdateRef */,
819 bool bExternalDocument )
821 bool bValid = false;
822 SCTAB i;
823 if (ValidTab(nTab))
825 if (maTabs[nTab])
827 if ( bExternalDocument )
828 bValid = true; // composed name
829 else
830 bValid = ValidTabName(rName);
831 for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
832 if (maTabs[i] && (i != nTab))
834 OUString aOldName;
835 maTabs[i]->GetName(aOldName);
836 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
838 if (bValid)
840 // #i75258# update charts before renaming, so they can get their live data objects.
841 // Once the charts are live, the sheet can be renamed without problems.
842 if ( pChartListenerCollection )
843 pChartListenerCollection->UpdateChartsContainingTab( nTab );
844 maTabs[nTab]->SetName(rName);
846 // If formulas refer to the renamed sheet, the TokenArray remains valid,
847 // but the XML stream must be re-generated.
848 TableContainer::iterator it = maTabs.begin();
849 for (; it != maTabs.end(); ++it)
850 if ( *it && (*it)->IsStreamValid())
851 (*it)->SetStreamValid( false );
855 return bValid;
858 void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
860 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
861 if (maTabs[nTab])
862 maTabs[nTab]->SetVisible(bVisible);
865 bool ScDocument::IsVisible( SCTAB nTab ) const
867 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
868 if (maTabs[nTab])
869 return maTabs[nTab]->IsVisible();
871 return false;
874 bool ScDocument::IsStreamValid( SCTAB nTab ) const
876 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
877 return maTabs[nTab]->IsStreamValid();
879 return false;
882 void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
884 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
885 maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
888 void ScDocument::LockStreamValid( bool bLock )
890 mbStreamValidLocked = bLock;
893 bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
895 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
896 return maTabs[nTab]->IsPendingRowHeights();
898 return false;
901 void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
903 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
904 maTabs[nTab]->SetPendingRowHeights( bSet );
907 void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
909 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
911 if ( bImportingXML )
913 // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
914 // is applied in SetImportingXML(false). This is so the shapes can be loaded in
915 // normal LTR mode.
917 maTabs[nTab]->SetLoadingRTL( bRTL );
918 return;
921 maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
922 maTabs[nTab]->SetDrawPageSize();
924 // mirror existing objects:
926 if (pDrawLayer)
928 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
929 OSL_ENSURE(pPage,"Page ?");
930 if (pPage)
932 SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
933 SdrObject* pObject = aIter.Next();
934 while (pObject)
936 // objects with ScDrawObjData are re-positioned in SetPageSize,
937 // don't mirror again
938 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
939 if ( !pData )
940 pDrawLayer->MirrorRTL( pObject );
942 pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
944 pObject = aIter.Next();
951 bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
953 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
954 return maTabs[nTab]->IsLayoutRTL();
956 return false;
959 bool ScDocument::IsNegativePage( SCTAB nTab ) const
961 // Negative page area is always used for RTL layout.
962 // The separate method is used to find all RTL handling of drawing objects.
963 return IsLayoutRTL( nTab );
966 /* ----------------------------------------------------------------------------
967 used search area:
969 GetCellArea - Only Data
970 GetTableArea - Data / Attributes
971 GetPrintArea - intended for character objects,
972 sweeps attributes all the way to bottom / right
973 ---------------------------------------------------------------------------- */
975 bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
977 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
978 if (maTabs[nTab])
979 return maTabs[nTab]->GetCellArea( rEndCol, rEndRow );
981 rEndCol = 0;
982 rEndRow = 0;
983 return false;
986 bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
988 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
989 if (maTabs[nTab])
990 return maTabs[nTab]->GetTableArea( rEndCol, rEndRow );
992 rEndCol = 0;
993 rEndRow = 0;
994 return false;
997 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
999 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1000 return false;
1002 SCCOL nCol1, nCol2;
1003 SCROW nRow1, nRow2;
1004 maTabs[nTab]->GetFirstDataPos(nCol1, nRow1);
1005 maTabs[nTab]->GetLastDataPos(nCol2, nRow2);
1007 if (nCol1 > nCol2 || nRow1 > nRow2)
1008 // invalid range.
1009 return false;
1011 // Make sure the area only shrinks, and doesn't grow.
1012 if (rStartCol < nCol1)
1013 rStartCol = nCol1;
1014 if (nCol2 < rEndCol)
1015 rEndCol = nCol2;
1016 if (rStartRow < nRow1)
1017 rStartRow = nRow1;
1018 if (nRow2 < rEndRow)
1019 rEndRow = nRow2;
1021 if (rStartCol > rEndCol || rStartRow > rEndRow)
1022 // invalid range.
1023 return false;
1025 return true; // success!
1028 bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
1029 SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly,
1030 bool bStickyTopRow, bool bStickyLeftCol ) const
1032 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1034 o_bShrunk = false;
1035 return false;
1037 return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow,
1038 bColumnsOnly, bStickyTopRow, bStickyLeftCol);
1041 SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
1043 const ScTable* pTab = FetchTable(nTab);
1044 if (!pTab)
1045 return -1;
1047 return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
1050 ScAddress ScDocument::GetLastDataPos( SCTAB nTab ) const
1052 const ScTable* pTab = FetchTable(nTab);
1053 if (!pTab)
1054 return ScAddress(ScAddress::INITIALIZE_INVALID);
1056 SCCOL nCol;
1057 SCROW nRow;
1058 pTab->GetLastDataPos(nCol, nRow);
1059 return ScAddress(nCol, nRow, nTab);
1062 // connected area
1064 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1065 SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
1067 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1068 maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
1071 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1072 SCCOL& rEndCol, SCROW& rEndRow )
1074 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1075 if (maTabs[nTab])
1076 maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
1079 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
1081 ScRangeListRef aNew = new ScRangeList;
1082 if (rRangeList.Is())
1084 for ( size_t i = 0, nCount = rRangeList->size(); i < nCount; i++ )
1086 ScRange aRange( *(*rRangeList)[i] );
1087 if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
1088 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
1090 SCCOL nStartCol = aRange.aStart.Col();
1091 SCROW nStartRow = aRange.aStart.Row();
1092 SCCOL nEndCol = aRange.aEnd.Col();
1093 SCROW nEndRow = aRange.aEnd.Row();
1094 SCTAB nTab = aRange.aStart.Tab();
1095 if ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1096 maTabs[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
1097 aRange.aStart.SetCol( nStartCol );
1098 aRange.aStart.SetRow( nStartRow );
1099 aRange.aEnd.SetCol( nEndCol );
1100 aRange.aEnd.SetRow( nEndRow );
1102 aNew->Append(aRange);
1105 else
1107 OSL_FAIL("LimitChartIfAll: Ref==0");
1109 rRangeList = aNew;
1112 static void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1114 // without ScMarkData, leave start/end unchanged
1115 if ( pTabMark )
1117 for (SCTAB nTab=0; nTab< aMaxTab; ++nTab)
1118 if (pTabMark->GetTableSelect(nTab))
1120 // find first range of consecutive selected sheets
1121 rTabRangeStart = pTabMark->GetFirstSelected();
1122 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1123 ++nTab;
1124 rTabRangeEnd = nTab;
1125 return;
1130 static bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1132 if ( pTabMark )
1134 // find next range of consecutive selected sheets after rTabRangeEnd
1135 for (SCTAB nTab=rTabRangeEnd+1; nTab< aMaxTab; ++nTab)
1136 if (pTabMark->GetTableSelect(nTab))
1138 rTabRangeStart = nTab;
1139 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1140 ++nTab;
1141 rTabRangeEnd = nTab;
1142 return true;
1145 return false;
1148 bool ScDocument::CanInsertRow( const ScRange& rRange ) const
1150 SCCOL nStartCol = rRange.aStart.Col();
1151 SCROW nStartRow = rRange.aStart.Row();
1152 SCTAB nStartTab = rRange.aStart.Tab();
1153 SCCOL nEndCol = rRange.aEnd.Col();
1154 SCROW nEndRow = rRange.aEnd.Row();
1155 SCTAB nEndTab = rRange.aEnd.Tab();
1156 PutInOrder( nStartCol, nEndCol );
1157 PutInOrder( nStartRow, nEndRow );
1158 PutInOrder( nStartTab, nEndTab );
1159 SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
1161 bool bTest = true;
1162 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1163 if (maTabs[i])
1164 bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
1166 return bTest;
1169 namespace {
1171 struct SetDirtyIfPostponedHandler : std::unary_function<ScTable*, void>
1173 void operator() (ScTable* p)
1175 if (p)
1176 p->SetDirtyIfPostponed();
1180 struct BroadcastRecalcOnRefMoveHandler : std::unary_function<ScTable*, void>
1182 void operator() (ScTable* p)
1184 if (p)
1185 p->BroadcastRecalcOnRefMove();
1191 bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
1192 SCCOL nEndCol, SCTAB nEndTab,
1193 SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
1194 const ScMarkData* pTabMark )
1196 SCTAB i;
1198 PutInOrder( nStartCol, nEndCol );
1199 PutInOrder( nStartTab, nEndTab );
1200 if ( pTabMark )
1202 nStartTab = 0;
1203 nEndTab = static_cast<SCTAB>(maTabs.size()) -1;
1206 bool bTest = true;
1207 bool bRet = false;
1208 bool bOldAutoCalc = GetAutoCalc();
1209 SetAutoCalc( false ); // avoid mulitple calculations
1210 for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1211 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1212 bTest &= maTabs[i]->TestInsertRow(nStartCol, nEndCol, nStartRow, nSize);
1213 if (bTest)
1215 // UpdateBroadcastAreas have to be called before UpdateReference, so that entries
1216 // aren't shifted that would be rebuild at UpdateReference
1218 // handle chunks of consecutive selected sheets together
1219 SCTAB nTabRangeStart = nStartTab;
1220 SCTAB nTabRangeEnd = nEndTab;
1221 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1222 ScRange aShiftedRange(nStartCol, nStartRow, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
1223 sc::EndListeningContext aEndListenCxt(*this);
1225 std::vector<ScAddress> aGroupPos;
1228 aShiftedRange.aStart.SetTab(nTabRangeStart);
1229 aShiftedRange.aEnd.SetTab(nTabRangeEnd);
1231 // Collect all formula groups that will get split by the shifting,
1232 // and end all their listening. Record the position of the top
1233 // cell of the topmost group, and the position of the bottom cell
1234 // of the bottommost group.
1235 EndListeningIntersectedGroups(aEndListenCxt, aShiftedRange, &aGroupPos);
1237 UpdateBroadcastAreas(URM_INSDEL, aShiftedRange, 0, static_cast<SCsROW>(nSize), 0);
1239 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1241 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1243 sc::RefUpdateContext aCxt(*this);
1244 aCxt.meMode = URM_INSDEL;
1245 aCxt.maRange = aShiftedRange;
1246 aCxt.mnRowDelta = nSize;
1249 aCxt.maRange.aStart.SetTab(nTabRangeStart);
1250 aCxt.maRange.aEnd.SetTab(nTabRangeEnd);
1251 UpdateReference(aCxt, pRefUndoDoc, false); // without drawing objects
1253 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1255 // UpdateReference should have set "needs listening" flags to those
1256 // whose references have been modified. We also need to set this flag
1257 // to those that were in the groups that got split by shifting.
1258 SetNeedsListeningGroups(aGroupPos);
1260 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1261 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1262 maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
1264 // UpdateRef for drawing layer must be after inserting,
1265 // when the new row heights are known.
1266 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1267 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1268 maTabs[i]->UpdateDrawRef( URM_INSDEL,
1269 nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
1270 0, static_cast<SCsROW>(nSize), 0 );
1272 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1273 { // A new Listening is needed when references to deleted ranges are restored,
1274 // previous Listeners were removed in FormulaCell UpdateReference.
1275 StartAllListeners();
1277 else
1278 { // Listeners have been removed in UpdateReference
1279 StartNeededListeners();
1281 // At least all cells using range names pointing relative to the
1282 // moved range must be recalculated, and all cells marked postponed
1283 // dirty.
1284 TableContainer::iterator it = maTabs.begin();
1285 for (; it != maTabs.end(); ++it)
1286 if (*it)
1287 (*it)->SetDirtyIfPostponed();
1289 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1291 bRet = true;
1293 SetAutoCalc( bOldAutoCalc );
1294 if ( bRet )
1295 pChartListenerCollection->UpdateDirtyCharts();
1296 return bRet;
1299 bool ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
1301 return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1302 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1303 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
1304 pRefUndoDoc );
1307 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
1308 SCCOL nEndCol, SCTAB nEndTab,
1309 SCROW nStartRow, SCSIZE nSize,
1310 ScDocument* pRefUndoDoc, bool* pUndoOutline,
1311 const ScMarkData* pTabMark )
1313 SCTAB i;
1315 PutInOrder( nStartCol, nEndCol );
1316 PutInOrder( nStartTab, nEndTab );
1317 if ( pTabMark )
1319 nStartTab = 0;
1320 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1323 sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1325 // handle chunks of consecutive selected sheets together
1326 SCTAB nTabRangeStart = nStartTab;
1327 SCTAB nTabRangeEnd = nEndTab;
1328 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1331 if ( ValidRow(nStartRow+nSize) )
1333 DelBroadcastAreasInRange( ScRange(
1334 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1335 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
1336 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1337 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
1338 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
1340 else
1341 DelBroadcastAreasInRange( ScRange(
1342 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1343 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
1345 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1347 sc::RefUpdateContext aCxt(*this);
1348 if ( ValidRow(nStartRow+nSize) )
1350 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1351 aCxt.meMode = URM_INSDEL;
1352 aCxt.maRange = ScRange(nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
1353 aCxt.mnRowDelta = -(static_cast<SCROW>(nSize));
1356 UpdateReference(aCxt, pRefUndoDoc, true, false);
1358 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1361 if (pUndoOutline)
1362 *pUndoOutline = false;
1364 // Keep track of the positions of all formula groups that have been joined
1365 // during row deletion.
1366 std::vector<ScAddress> aGroupPos;
1368 for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1369 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1370 maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline, &aGroupPos);
1372 // Newly joined groups have some of their members still listening. We
1373 // need to make sure none of them are listening.
1374 EndListeningGroups(aGroupPos);
1376 // Mark all joined groups for group listening.
1377 SetNeedsListeningGroups(aGroupPos);
1379 if ( ValidRow(nStartRow+nSize) )
1381 // Listeners have been removed in UpdateReference
1382 StartNeededListeners();
1384 // At least all cells using range names pointing relative to the moved
1385 // range must be recalculated, and all cells marked postponed dirty.
1386 TableContainer::iterator it = maTabs.begin();
1387 for (; it != maTabs.end(); ++it)
1388 if (*it)
1389 (*it)->SetDirtyIfPostponed();
1391 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1394 pChartListenerCollection->UpdateDirtyCharts();
1397 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, bool* pUndoOutline )
1399 DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1400 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1401 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
1402 pRefUndoDoc, pUndoOutline );
1405 bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1407 SCCOL nStartCol = rRange.aStart.Col();
1408 SCROW nStartRow = rRange.aStart.Row();
1409 SCTAB nStartTab = rRange.aStart.Tab();
1410 SCCOL nEndCol = rRange.aEnd.Col();
1411 SCROW nEndRow = rRange.aEnd.Row();
1412 SCTAB nEndTab = rRange.aEnd.Tab();
1413 PutInOrder( nStartCol, nEndCol );
1414 PutInOrder( nStartRow, nEndRow );
1415 PutInOrder( nStartTab, nEndTab );
1416 SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1418 bool bTest = true;
1419 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1420 if (maTabs[i])
1421 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1423 return bTest;
1426 bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1427 SCROW nEndRow, SCTAB nEndTab,
1428 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1429 const ScMarkData* pTabMark )
1431 SCTAB i;
1433 PutInOrder( nStartRow, nEndRow );
1434 PutInOrder( nStartTab, nEndTab );
1435 if ( pTabMark )
1437 nStartTab = 0;
1438 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1441 bool bTest = true;
1442 bool bRet = false;
1443 bool bOldAutoCalc = GetAutoCalc();
1444 SetAutoCalc( false ); // avoid multiple calculations
1445 for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1446 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1447 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1448 if (bTest)
1450 // handle chunks of consecutive selected sheets together
1451 SCTAB nTabRangeStart = nStartTab;
1452 SCTAB nTabRangeEnd = nEndTab;
1453 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1456 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1457 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1458 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1460 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1462 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1464 sc::RefUpdateContext aCxt(*this);
1465 aCxt.meMode = URM_INSDEL;
1466 aCxt.maRange = ScRange(nStartCol, nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
1467 aCxt.mnColDelta = nSize;
1470 UpdateReference(aCxt, pRefUndoDoc, true, false);
1472 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1474 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1475 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1476 maTabs[i]->InsertCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize);
1478 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1479 { // A new Listening is needed when references to deleted ranges are restored,
1480 // previous Listeners were removed in FormulaCell UpdateReference.
1481 StartAllListeners();
1483 else
1485 // Listeners have been removed in UpdateReference
1486 StartNeededListeners();
1487 // At least all cells using range names pointing relative to the
1488 // moved range must be recalculated, and all cells marked postponed
1489 // dirty.
1490 std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
1491 // Cells containing functions such as CELL, COLUMN or ROW may have
1492 // changed their values on relocation. Broadcast them.
1493 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1495 bRet = true;
1497 SetAutoCalc( bOldAutoCalc );
1498 if ( bRet )
1499 pChartListenerCollection->UpdateDirtyCharts();
1500 return bRet;
1503 bool ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1505 return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1506 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1507 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1508 pRefUndoDoc );
1511 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1512 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1513 bool* pUndoOutline, const ScMarkData* pTabMark )
1515 SCTAB i;
1517 PutInOrder( nStartRow, nEndRow );
1518 PutInOrder( nStartTab, nEndTab );
1519 if ( pTabMark )
1521 nStartTab = 0;
1522 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1525 sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1527 // handle chunks of consecutive selected sheets together
1528 SCTAB nTabRangeStart = nStartTab;
1529 SCTAB nTabRangeEnd = nEndTab;
1530 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1533 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1535 DelBroadcastAreasInRange( ScRange(
1536 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1537 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1538 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1539 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1540 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1542 else
1543 DelBroadcastAreasInRange( ScRange(
1544 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1545 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1547 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1549 sc::RefUpdateContext aCxt(*this);
1550 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1552 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1553 aCxt.meMode = URM_INSDEL;
1554 aCxt.maRange = ScRange(sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
1555 aCxt.mnColDelta = -(static_cast<SCCOL>(nSize));
1558 UpdateReference(aCxt, pRefUndoDoc, true, false);
1560 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1563 if (pUndoOutline)
1564 *pUndoOutline = false;
1566 for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
1568 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1569 maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
1572 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1574 // Listeners have been removed in UpdateReference
1575 StartNeededListeners();
1577 // At least all cells using range names pointing relative to the moved
1578 // range must be recalculated, and all cells marked postponed dirty.
1579 TableContainer::iterator it = maTabs.begin();
1580 for (; it != maTabs.end(); ++it)
1581 if (*it)
1582 (*it)->SetDirtyIfPostponed();
1584 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1587 pChartListenerCollection->UpdateDirtyCharts();
1590 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, bool* pUndoOutline )
1592 DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1593 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1594 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1595 pRefUndoDoc, pUndoOutline );
1598 // for Area-Links: Insert/delete cells, when the range is changed.
1599 // (without Paint)
1601 static void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1602 ScRange& rColRange, bool& rInsCol, bool& rDelCol,
1603 ScRange& rRowRange, bool& rInsRow, bool& rDelRow )
1605 OSL_ENSURE( rOld.aStart == rNew.aStart, "FitBlock: Beginning is different" );
1607 rInsCol = rDelCol = rInsRow = rDelRow = false;
1609 SCCOL nStartX = rOld.aStart.Col();
1610 SCROW nStartY = rOld.aStart.Row();
1611 SCCOL nOldEndX = rOld.aEnd.Col();
1612 SCROW nOldEndY = rOld.aEnd.Row();
1613 SCCOL nNewEndX = rNew.aEnd.Col();
1614 SCROW nNewEndY = rNew.aEnd.Row();
1615 SCTAB nTab = rOld.aStart.Tab();
1617 // if more rows, columns are inserted/deleted at the old height.
1618 bool bGrowY = ( nNewEndY > nOldEndY );
1619 SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1620 SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1622 // Columns
1624 if ( nNewEndX > nOldEndX ) // Insert columns
1626 rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1627 rInsCol = true;
1629 else if ( nNewEndX < nOldEndX ) // Delete columns
1631 rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1632 rDelCol = true;
1635 // Rows
1637 if ( nNewEndY > nOldEndY ) // Insert rows
1639 rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1640 rInsRow = true;
1642 else if ( nNewEndY < nOldEndY ) // Delete rows
1644 rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1645 rDelRow = true;
1649 bool ScDocument::HasPartOfMerged( const ScRange& rRange )
1651 bool bPart = false;
1652 SCTAB nTab = rRange.aStart.Tab();
1654 SCCOL nStartX = rRange.aStart.Col();
1655 SCROW nStartY = rRange.aStart.Row();
1656 SCCOL nEndX = rRange.aEnd.Col();
1657 SCROW nEndY = rRange.aEnd.Row();
1659 if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1660 HASATTR_MERGED | HASATTR_OVERLAPPED ))
1662 ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1663 ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1665 bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1666 nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1668 return bPart;
1671 size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const
1673 SCTAB nTab = rPos.Tab();
1674 if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab])
1675 return 0;
1677 return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row());
1680 ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos ) const
1682 SCTAB nTab = rPos.Tab();
1683 if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab])
1684 return FormulaVectorUnknown;
1686 return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
1689 formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
1691 SCTAB nTab = rPos.Tab();
1692 if (!TableExists(nTab))
1693 return formula::FormulaTokenRef();
1695 return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
1698 formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
1700 SCTAB nTab = rRange.aStart.Tab();
1701 if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
1702 return formula::FormulaTokenRef();
1704 return maTabs[nTab]->ResolveStaticReference(
1705 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
1708 formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos, SCROW nLength )
1710 SCTAB nTab = rPos.Tab();
1711 if (!TableExists(nTab))
1712 return formula::VectorRefArray();
1714 return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1717 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1719 if ( rOld == rNew )
1720 return true;
1722 bool bOk = true;
1723 bool bInsCol,bDelCol,bInsRow,bDelRow;
1724 ScRange aColRange,aRowRange;
1725 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1727 if ( bInsCol && !CanInsertCol( aColRange ) ) // Cells at the edge ?
1728 bOk = false;
1729 if ( bInsRow && !CanInsertRow( aRowRange ) ) // Cells at the edge ?
1730 bOk = false;
1732 if ( bInsCol || bDelCol )
1734 aColRange.aEnd.SetCol(MAXCOL);
1735 if ( HasPartOfMerged(aColRange) )
1736 bOk = false;
1738 if ( bInsRow || bDelRow )
1740 aRowRange.aEnd.SetRow(MAXROW);
1741 if ( HasPartOfMerged(aRowRange) )
1742 bOk = false;
1745 return bOk;
1748 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, bool bClear )
1750 if (bClear)
1751 DeleteAreaTab( rOld, IDF_ALL );
1753 bool bInsCol,bDelCol,bInsRow,bDelRow;
1754 ScRange aColRange,aRowRange;
1755 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1757 if ( bInsCol )
1758 InsertCol( aColRange ); // First insert columns
1759 if ( bInsRow )
1760 InsertRow( aRowRange );
1762 if ( bDelRow )
1763 DeleteRow( aRowRange ); // First delete rows
1764 if ( bDelCol )
1765 DeleteCol( aColRange );
1767 // Expand references to inserted rows
1769 if ( bInsCol || bInsRow )
1771 ScRange aGrowSource = rOld;
1772 aGrowSource.aEnd.SetCol(std::min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1773 aGrowSource.aEnd.SetRow(std::min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1774 SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1775 SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1776 UpdateGrow( aGrowSource, nGrowX, nGrowY );
1780 void ScDocument::DeleteArea(
1781 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
1782 InsertDeleteFlags nDelFlag, bool bBroadcast, sc::ColumnSpanSet* pBroadcastSpans )
1784 sc::AutoCalcSwitch aACSwitch(*this, false);
1786 PutInOrder( nCol1, nCol2 );
1787 PutInOrder( nRow1, nRow2 );
1789 std::vector<ScAddress> aGroupPos;
1790 // Destroy and reconstruct listeners only if content is affected.
1791 bool bDelContent = ((nDelFlag & ~IDF_CONTENTS) != nDelFlag);
1792 if (bDelContent)
1794 // Record the positions of top and/or bottom formula groups that intersect
1795 // the area borders.
1796 sc::EndListeningContext aCxt(*this);
1797 ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1798 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1800 if (rMark.GetTableSelect(i))
1802 aRange.aStart.SetTab(i);
1803 aRange.aEnd.SetTab(i);
1805 EndListeningIntersectedGroups(aCxt, aRange, &aGroupPos);
1808 aCxt.purgeEmptyBroadcasters();
1811 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1812 if (maTabs[i])
1813 if ( rMark.GetTableSelect(i) || bIsUndo )
1814 maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
1816 if (bDelContent)
1818 // Re-start listeners on those top bottom groups that have been split.
1819 SetNeedsListeningGroups(aGroupPos);
1820 StartNeededListeners();
1824 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1825 SCCOL nCol2, SCROW nRow2,
1826 SCTAB nTab, InsertDeleteFlags nDelFlag)
1828 PutInOrder( nCol1, nCol2 );
1829 PutInOrder( nRow1, nRow2 );
1830 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1832 bool bOldAutoCalc = GetAutoCalc();
1833 SetAutoCalc( false ); // avoid multiple calculations
1834 maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1835 SetAutoCalc( bOldAutoCalc );
1839 void ScDocument::DeleteAreaTab( const ScRange& rRange, InsertDeleteFlags nDelFlag )
1841 for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1842 DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1843 rRange.aEnd.Col(), rRange.aEnd.Row(),
1844 nTab, nDelFlag );
1847 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1848 bool bColInfo, bool bRowInfo )
1850 if (bIsUndo)
1852 Clear();
1854 SharePooledResources(pSrcDoc);
1856 OUString aString;
1857 for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
1858 if ( rTabSelection.GetTableSelect( nTab ) )
1860 ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1861 if (nTab < static_cast<SCTAB>(maTabs.size()))
1862 maTabs[nTab] = pTable;
1863 else
1864 maTabs.push_back(pTable);
1866 else
1868 if (nTab < static_cast<SCTAB>(maTabs.size()))
1869 maTabs[nTab]=NULL;
1870 else
1871 maTabs.push_back(NULL);
1874 else
1876 OSL_FAIL("InitUndo");
1880 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1881 bool bColInfo, bool bRowInfo )
1883 if (!bIsUndo)
1885 OSL_FAIL("InitUndo");
1886 return;
1889 Clear();
1891 // Undo document shares its pooled resources with the source document.
1892 SharePooledResources(pSrcDoc);
1894 if (pSrcDoc->pShell->GetMedium())
1895 maFileURL = pSrcDoc->pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
1897 OUString aString;
1898 if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
1899 maTabs.resize(nTab2 + 1, NULL);
1900 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1902 ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1903 maTabs[nTab] = pTable;
1907 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowInfo )
1909 if (!bIsUndo)
1911 OSL_FAIL("AddUndoTab");
1912 return;
1915 OUString aString;
1916 if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
1918 maTabs.resize(nTab2+1,NULL);
1921 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1922 if (!maTabs[nTab])
1924 maTabs[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1928 void ScDocument::SetCutMode( bool bVal )
1930 if (bIsClip)
1931 GetClipParam().mbCutMode = bVal;
1932 else
1934 OSL_FAIL("SetCutMode without bIsClip");
1938 bool ScDocument::IsCutMode()
1940 if (bIsClip)
1941 return GetClipParam().mbCutMode;
1942 else
1944 OSL_FAIL("IsCutMode without bIsClip");
1945 return false;
1949 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1950 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1951 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
1952 const ScMarkData* pMarks, bool bColRowFlags )
1954 PutInOrder( nCol1, nCol2 );
1955 PutInOrder( nRow1, nRow2 );
1956 PutInOrder( nTab1, nTab2 );
1957 if( pDestDoc->aDocName.isEmpty() )
1958 pDestDoc->aDocName = aDocName;
1959 if (ValidTab(nTab1) && ValidTab(nTab2))
1961 sc::CopyToDocContext aCxt(*pDestDoc);
1962 bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1963 pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
1964 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
1965 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
1967 if (maTabs[i] && pDestDoc->maTabs[i])
1968 maTabs[i]->CopyToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
1969 bOnlyMarked, pDestDoc->maTabs[i], pMarks,
1970 false, bColRowFlags );
1972 pDestDoc->SetAutoCalc( bOldAutoCalc );
1976 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1977 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1978 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
1979 const ScMarkData* pMarks)
1981 PutInOrder( nCol1, nCol2 );
1982 PutInOrder( nRow1, nRow2 );
1983 PutInOrder( nTab1, nTab2 );
1984 if (ValidTab(nTab1) && ValidTab(nTab2))
1986 sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations
1988 if (nTab1 > 0)
1989 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
1991 sc::CopyToDocContext aCxt(*pDestDoc);
1992 OSL_ASSERT( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(pDestDoc->maTabs.size()));
1993 for (SCTAB i = nTab1; i <= nTab2; i++)
1995 if (maTabs[i] && pDestDoc->maTabs[i])
1996 maTabs[i]->UndoToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
1997 bOnlyMarked, pDestDoc->maTabs[i], pMarks);
2000 if (nTab2 < MAXTAB)
2001 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, false, pDestDoc, pMarks );
2005 void ScDocument::CopyToDocument(const ScRange& rRange,
2006 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
2007 const ScMarkData* pMarks, bool bColRowFlags)
2009 ScRange aNewRange = rRange;
2010 aNewRange.Justify();
2012 if( pDestDoc->aDocName.isEmpty() )
2013 pDestDoc->aDocName = aDocName;
2015 sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations
2017 sc::CopyToDocContext aCxt(*pDestDoc);
2018 aCxt.setStartListening(false);
2020 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
2021 for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
2023 ScTable* pTab = FetchTable(i);
2024 ScTable* pDestTab = pDestDoc->FetchTable(i);
2025 if (!pTab || !pDestTab)
2026 continue;
2028 pTab->CopyToTable(
2029 aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2030 nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags);
2033 pDestDoc->StartAllListeners(aNewRange);
2036 void ScDocument::UndoToDocument(const ScRange& rRange,
2037 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
2038 const ScMarkData* pMarks)
2040 sc::AutoCalcSwitch aAutoCalcSwitch(*this, false);
2042 ScRange aNewRange = rRange;
2043 aNewRange.Justify();
2044 SCTAB nTab1 = aNewRange.aStart.Tab();
2045 SCTAB nTab2 = aNewRange.aEnd.Tab();
2047 sc::CopyToDocContext aCxt(*pDestDoc);
2048 if (nTab1 > 0)
2049 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
2051 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
2052 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
2054 if (maTabs[i] && pDestDoc->maTabs[i])
2055 maTabs[i]->UndoToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
2056 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2057 nFlags, bOnlyMarked, pDestDoc->maTabs[i], pMarks);
2060 if (nTab2 < static_cast<SCTAB>(maTabs.size()))
2061 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,maTabs.size(), IDF_FORMULA, false, pDestDoc, pMarks );
2064 // bUseRangeForVBA added for VBA api support to allow content of a specified
2065 // range to be copied ( e.g. don't use marked data but the just the range
2066 // specified by rClipParam
2067 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
2068 ScDocument* pClipDoc, const ScMarkData* pMarks,
2069 bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions, bool bUseRangeForVBA )
2071 OSL_ENSURE( !bUseRangeForVBA && ( bAllTabs || pMarks ), "CopyToClip: ScMarkData fails" );
2073 if (bIsClip)
2074 return;
2076 if (!pClipDoc)
2078 OSL_TRACE("CopyToClip: no ClipDoc");
2079 pClipDoc = ScModule::GetClipDoc();
2082 if (pShell->GetMedium())
2084 pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
2085 // for unsaved files use the title name and adjust during save of file
2086 if (pClipDoc->maFileURL.isEmpty())
2087 pClipDoc->maFileURL = pShell->GetName();
2089 else
2091 pClipDoc->maFileURL = pShell->GetName();
2094 //init maTabNames
2095 for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
2097 if( *itr )
2099 OUString aTabName;
2100 (*itr)->GetName(aTabName);
2101 pClipDoc->maTabNames.push_back(aTabName);
2103 else
2104 pClipDoc->maTabNames.push_back(OUString());
2107 pClipDoc->aDocName = aDocName;
2108 pClipDoc->SetClipParam(rClipParam);
2109 ScRange aClipRange = rClipParam.getWholeRange();
2110 SCTAB nTab = aClipRange.aStart.Tab();
2111 SCTAB i = 0;
2112 SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
2114 if ( bUseRangeForVBA )
2116 pClipDoc->ResetClip( this, nTab );
2117 i = nTab;
2118 nEndTab = nTab + 1;
2120 else
2121 pClipDoc->ResetClip(this, pMarks);
2123 sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags, bCloneNoteCaptions);
2124 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
2126 for ( ; i < nEndTab; ++i)
2128 if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
2129 continue;
2131 if ( !bUseRangeForVBA && ( pMarks && !pMarks->GetTableSelect(i) ) )
2132 continue;
2134 maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i]);
2136 if (pDrawLayer && bIncludeObjects)
2138 // also copy drawing objects
2139 Rectangle aObjRect = GetMMRect(
2140 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
2141 pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
2145 // Make sure to mark overlapped cells.
2146 pClipDoc->ExtendMerge(aClipRange, true);
2149 void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument* pDestDoc)
2151 if (!pDestDoc)
2152 return;
2154 ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()] : NULL;
2155 ScTable* pDestTab = nDestTab < static_cast<SCTAB>(pDestDoc->maTabs.size()) ? pDestDoc->maTabs[nDestTab] : NULL;
2157 if (!pSrcTab || !pDestTab)
2158 return;
2160 pDestDoc->GetFormatTable()->MergeFormatter(*GetFormatTable());
2161 SvNumberFormatterMergeMap aMap = pDestDoc->GetFormatTable()->ConvertMergeTableToMap();
2163 pSrcTab->CopyStaticToDocument(
2164 rSrcRange.aStart.Col(), rSrcRange.aStart.Row(), rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(),
2165 aMap, pDestTab);
2168 void ScDocument::CopyCellToDocument( const ScAddress& rSrcPos, const ScAddress& rDestPos, ScDocument& rDestDoc )
2170 if (!TableExists(rSrcPos.Tab()) || !rDestDoc.TableExists(rDestPos.Tab()))
2171 return;
2173 ScTable& rSrcTab = *maTabs[rSrcPos.Tab()];
2174 ScTable& rDestTab = *rDestDoc.maTabs[rDestPos.Tab()];
2176 rSrcTab.CopyCellToDocument(rSrcPos.Col(), rSrcPos.Row(), rDestPos.Col(), rDestPos.Row(), rDestTab);
2179 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
2180 SCCOL nCol2, SCROW nRow2,
2181 SCTAB nTab, ScDocument* pClipDoc)
2183 if (!bIsClip)
2185 if (!pClipDoc)
2187 OSL_TRACE("CopyTabToClip: no ClipDoc");
2188 pClipDoc = ScModule::GetClipDoc();
2191 if (pShell->GetMedium())
2193 pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
2194 // for unsaved files use the title name and adjust during save of file
2195 if (pClipDoc->maFileURL.isEmpty())
2196 pClipDoc->maFileURL = pShell->GetName();
2198 else
2200 pClipDoc->maFileURL = pShell->GetName();
2203 //init maTabNames
2204 for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
2206 if( *itr )
2208 OUString aTabName;
2209 (*itr)->GetName(aTabName);
2210 pClipDoc->maTabNames.push_back(aTabName);
2212 else
2213 pClipDoc->maTabNames.push_back(OUString());
2216 PutInOrder( nCol1, nCol2 );
2217 PutInOrder( nRow1, nRow2 );
2219 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2220 pClipDoc->aDocName = aDocName;
2221 rClipParam.maRanges.RemoveAll();
2222 rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
2223 pClipDoc->ResetClip( this, nTab );
2225 sc::CopyToClipContext aCxt(*pClipDoc, false, true);
2226 if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
2227 if (maTabs[nTab] && pClipDoc->maTabs[nTab])
2228 maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab]);
2230 pClipDoc->GetClipParam().mbCutMode = false;
2234 void ScDocument::TransposeClip( ScDocument* pTransClip, InsertDeleteFlags nFlags, bool bAsLink )
2236 OSL_ENSURE( bIsClip && pTransClip && pTransClip->bIsClip,
2237 "TransposeClip with wrong Document" );
2239 // initialize
2240 // -> pTransClip has to be delted before the original document!
2242 pTransClip->ResetClip(this, (ScMarkData*)NULL); // all
2244 // Take over range
2246 if (pRangeName)
2248 pTransClip->GetRangeName()->clear();
2249 ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
2250 for (; itr != itrEnd; ++itr)
2252 sal_uInt16 nIndex = itr->second->GetIndex();
2253 ScRangeData* pData = new ScRangeData(*itr->second);
2254 if (pTransClip->pRangeName->insert(pData))
2255 pData->SetIndex(nIndex);
2259 // The data
2261 ScRange aClipRange = GetClipParam().getWholeRange();
2262 if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
2264 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
2265 if (maTabs[i])
2267 OSL_ENSURE( pTransClip->maTabs[i], "TransposeClip: Table not there" );
2268 maTabs[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2269 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
2270 pTransClip->maTabs[i], nFlags, bAsLink );
2272 if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
2274 // Drawing objects are copied to the new area without transposing.
2275 // CopyFromClip is used to adjust the objects to the transposed block's
2276 // cell range area.
2277 // (pDrawLayer in the original clipboard document is set only if there
2278 // are drawing objects to copy)
2280 pTransClip->InitDrawLayer();
2281 Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2282 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
2283 Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
2284 static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
2285 static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
2286 pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
2290 pTransClip->SetClipParam(GetClipParam());
2291 pTransClip->GetClipParam().transpose();
2293 else
2295 OSL_TRACE("TransposeClip: Too big");
2298 // This happens only when inserting...
2300 GetClipParam().mbCutMode = false;
2303 namespace {
2305 void copyUsedNamesToClip(ScRangeName* pClipRangeName, ScRangeName* pRangeName, const std::set<sal_uInt16>& rUsedNames)
2307 pClipRangeName->clear();
2308 ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
2309 for (; itr != itrEnd; ++itr) //TODO: also DB and Pivot regions!!!
2311 sal_uInt16 nIndex = itr->second->GetIndex();
2312 bool bInUse = (rUsedNames.count(nIndex) > 0);
2313 if (!bInUse)
2314 continue;
2316 ScRangeData* pData = new ScRangeData(*itr->second);
2317 if (pClipRangeName->insert(pData))
2318 pData->SetIndex(nIndex);
2324 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
2326 if (!pRangeName || pRangeName->empty())
2327 return;
2329 std::set<sal_uInt16> aUsedNames; // indexes of named ranges that are used in the copied cells
2330 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pClipDoc->maTabs.size()));
2331 for (SCTAB i = 0; i < nMinSizeBothTabs; ++i)
2332 if (maTabs[i] && pClipDoc->maTabs[i])
2333 if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
2334 maTabs[i]->FindRangeNamesInUse(
2335 rClipRange.aStart.Col(), rClipRange.aStart.Row(),
2336 rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
2338 copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName, aUsedNames);
2341 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
2342 mpDoc(pDoc)
2344 mpDoc->MergeNumberFormatter(pSrcDoc);
2347 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
2349 mpDoc->pFormatExchangeList = NULL;
2352 void ScDocument::ClearFormulaContext()
2354 mpFormulaGroupCxt.reset();
2357 SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos )
2359 ScTable* pTab = FetchTable(rPos.Tab());
2360 if (!pTab)
2361 return NULL;
2363 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2366 const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
2368 const ScTable* pTab = FetchTable(rPos.Tab());
2369 if (!pTab)
2370 return NULL;
2372 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2375 void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength )
2377 ScTable* pTab = FetchTable(rTopPos.Tab());
2378 if (!pTab || nLength <= 0)
2379 return;
2381 pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
2384 bool ScDocument::HasBroadcaster( SCTAB nTab, SCCOL nCol ) const
2386 const ScTable* pTab = FetchTable(nTab);
2387 if (!pTab)
2388 return false;
2390 return pTab->HasBroadcaster(nCol);
2393 #if DEBUG_COLUMN_STORAGE
2394 void ScDocument::DumpFormulaGroups( SCTAB nTab, SCCOL nCol ) const
2396 const ScTable* pTab = FetchTable(nTab);
2397 if (!pTab)
2398 return;
2400 pTab->DumpFormulaGroups(nCol);
2402 #endif
2404 #if DEBUG_AREA_BROADCASTER
2405 void ScDocument::DumpAreaBroadcasters() const
2407 if (pBASM)
2408 pBASM->Dump();
2410 #endif
2412 bool ScDocument::TableExists( SCTAB nTab ) const
2414 return ValidTab(nTab) && static_cast<size_t>(nTab) < maTabs.size() && maTabs[nTab];
2417 ScTable* ScDocument::FetchTable( SCTAB nTab )
2419 if (!TableExists(nTab))
2420 return NULL;
2422 return maTabs[nTab];
2425 const ScTable* ScDocument::FetchTable( SCTAB nTab ) const
2427 if (!TableExists(nTab))
2428 return NULL;
2430 return maTabs[nTab];
2433 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
2435 SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
2436 SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
2437 if (pOtherFormatter && pOtherFormatter != pThisFormatter)
2439 SvNumberFormatterIndexTable* pExchangeList =
2440 pThisFormatter->MergeFormatter(*(pOtherFormatter));
2441 if (!pExchangeList->empty())
2442 pFormatExchangeList = pExchangeList;
2446 ScClipParam& ScDocument::GetClipParam()
2448 if (!mpClipParam.get())
2449 mpClipParam.reset(new ScClipParam);
2451 return *mpClipParam;
2454 void ScDocument::SetClipParam(const ScClipParam& rParam)
2456 mpClipParam.reset(new ScClipParam(rParam));
2459 bool ScDocument::IsClipboardSource() const
2461 ScDocument* pClipDoc = ScModule::GetClipDoc();
2462 return pClipDoc && pClipDoc->xPoolHelper.is() &&
2463 xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
2466 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
2467 SCCOL nCol2, SCROW nRow2,
2468 const ScMarkData& rMark, InsertDeleteFlags nInsFlag )
2470 if (nInsFlag & IDF_CONTENTS)
2472 boost::shared_ptr<sc::ColumnBlockPositionSet> pSet(
2473 new sc::ColumnBlockPositionSet(*this));
2475 sc::StartListeningContext aStartCxt(*this, pSet);
2476 sc::EndListeningContext aEndCxt(*this, pSet, NULL);
2478 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2479 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
2480 for (; itr != itrEnd && *itr < nMax; ++itr)
2481 if (maTabs[*itr])
2482 maTabs[*itr]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
2486 void ScDocument::SetDirtyFromClip(
2487 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
2488 InsertDeleteFlags nInsFlag, sc::ColumnSpanSet& rBroadcastSpans )
2490 if (nInsFlag & IDF_CONTENTS)
2492 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2493 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
2494 for (; itr != itrEnd && *itr < nMax; ++itr)
2495 if (maTabs[*itr])
2496 maTabs[*itr]->SetDirtyFromClip(nCol1, nRow1, nCol2, nRow2, rBroadcastSpans);
2500 bool ScDocument::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCTAB nTab, SCCOL nCol )
2502 if (!TableExists(nTab))
2503 return false;
2505 return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
2508 void ScDocument::CopyBlockFromClip(
2509 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2510 const ScMarkData& rMark, SCsCOL nDx, SCsROW nDy )
2512 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2513 SCTAB nTabEnd = rCxt.getTabEnd();
2514 SCTAB nClipTab = 0;
2515 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2517 if (maTabs[i] && rMark.GetTableSelect(i) )
2519 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2521 maTabs[i]->CopyFromClip(
2522 rCxt, nCol1, nRow1, nCol2, nRow2, nDx, nDy, rClipTabs[nClipTab]);
2524 if (rCxt.getClipDoc()->pDrawLayer && (rCxt.getInsertFlag() & IDF_OBJECTS))
2526 // also copy drawing objects
2528 // drawing layer must be created before calling CopyFromClip
2529 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
2530 OSL_ENSURE( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
2531 if ( pDrawLayer )
2533 // For GetMMRect, the row heights in the target document must already be valid
2534 // (copied in an extra step before pasting, or updated after pasting cells, but
2535 // before pasting objects).
2537 Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
2538 nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
2539 Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
2540 pDrawLayer->CopyFromClip(rCxt.getClipDoc()->pDrawLayer, nClipTab, aSourceRect,
2541 ScAddress( nCol1, nRow1, i ), aDestRect );
2545 nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2548 if (rCxt.getInsertFlag() & IDF_CONTENTS)
2550 nClipTab = 0;
2551 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2553 if (maTabs[i] && rMark.GetTableSelect(i) )
2555 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2556 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
2558 // ranges of consecutive selected tables (in clipboard and dest. doc)
2559 // must be handled in one UpdateReference call
2560 SCTAB nFollow = 0;
2561 while ( i + nFollow < nTabEnd
2562 && rMark.GetTableSelect( i + nFollow + 1 )
2563 && nClipTab + nFollow < MAXTAB
2564 && rClipTabs[(nClipTab + nFollow + 1) % static_cast<SCTAB>(rClipTabs.size())] )
2565 ++nFollow;
2567 sc::RefUpdateContext aRefCxt(*this);
2568 aRefCxt.maRange = ScRange(nCol1, nRow1, i, nCol2, nRow2, i+nFollow);
2569 aRefCxt.mnColDelta = nDx;
2570 aRefCxt.mnRowDelta = nDy;
2571 aRefCxt.mnTabDelta = nDz;
2572 if (rCxt.getClipDoc()->GetClipParam().mbCutMode)
2574 // Update references only if cut originates from the same
2575 // document we are pasting into.
2576 if (rCxt.getClipDoc()->GetPool() == GetPool())
2578 bool bOldInserting = IsInsertingFromOtherDoc();
2579 SetInsertingFromOtherDoc( true);
2580 aRefCxt.meMode = URM_MOVE;
2581 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2582 SetInsertingFromOtherDoc( bOldInserting);
2585 else
2587 aRefCxt.meMode = URM_COPY;
2588 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2591 nClipTab = (nClipTab+nFollow+1) % (static_cast<SCTAB>(rClipTabs.size()));
2592 i = sal::static_int_cast<SCTAB>( i + nFollow );
2598 void ScDocument::CopyNonFilteredFromClip(
2599 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2600 const ScMarkData& rMark, SCsCOL nDx, SCROW & rClipStartRow )
2602 // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2603 // nCol1/nRow1 etc. is in target doc
2605 // filtered state is taken from first used table in clipboard (as in GetClipArea)
2606 SCTAB nFlagTab = 0;
2607 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2608 while ( nFlagTab < static_cast<SCTAB>(rClipTabs.size()) && !rClipTabs[nFlagTab] )
2609 ++nFlagTab;
2611 SCROW nSourceRow = rClipStartRow;
2612 SCROW nSourceEnd = 0;
2613 if (!rCxt.getClipDoc()->GetClipParam().maRanges.empty())
2614 nSourceEnd = rCxt.getClipDoc()->GetClipParam().maRanges.front()->aEnd.Row();
2615 SCROW nDestRow = nRow1;
2617 while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2619 // skip filtered rows
2620 nSourceRow = rCxt.getClipDoc()->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2622 if ( nSourceRow <= nSourceEnd )
2624 // look for more non-filtered rows following
2625 SCROW nLastRow = nSourceRow;
2626 rCxt.getClipDoc()->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2627 SCROW nFollow = nLastRow - nSourceRow;
2629 if (nFollow > nSourceEnd - nSourceRow)
2630 nFollow = nSourceEnd - nSourceRow;
2631 if (nFollow > nRow2 - nDestRow)
2632 nFollow = nRow2 - nDestRow;
2634 SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2635 CopyBlockFromClip(
2636 rCxt, nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy);
2638 nSourceRow += nFollow + 1;
2639 nDestRow += nFollow + 1;
2642 rClipStartRow = nSourceRow;
2645 namespace {
2647 class BroadcastAction : public sc::ColumnSpanSet::ColumnAction
2649 ScDocument& mrDoc;
2650 ScColumn* mpCol;
2652 public:
2653 BroadcastAction( ScDocument& rDoc ) : mrDoc(rDoc), mpCol(NULL) {}
2655 virtual void startColumn( ScColumn* pCol ) SAL_OVERRIDE
2657 mpCol = pCol;
2660 virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) SAL_OVERRIDE
2662 if (!bVal)
2663 return;
2665 assert(mpCol);
2666 ScRange aRange(mpCol->GetCol(), nRow1, mpCol->GetTab());
2667 aRange.aEnd.SetRow(nRow2);
2668 mrDoc.BroadcastCells(aRange, SC_HINT_DATACHANGED);
2674 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2675 InsertDeleteFlags nInsFlag,
2676 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
2677 bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
2678 const ScRangeList * pDestRanges )
2680 if (bIsClip)
2681 return;
2683 if (!pClipDoc)
2685 OSL_FAIL("CopyFromClip: no ClipDoc");
2686 pClipDoc = ScModule::GetClipDoc();
2689 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2690 return;
2692 sc::AutoCalcSwitch aACSwitch(*this, false); // temporarily turn off auto calc.
2694 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2696 SCCOL nAllCol1 = rDestRange.aStart.Col();
2697 SCROW nAllRow1 = rDestRange.aStart.Row();
2698 SCCOL nAllCol2 = rDestRange.aEnd.Col();
2699 SCROW nAllRow2 = rDestRange.aEnd.Row();
2701 SCCOL nXw = 0;
2702 SCROW nYw = 0;
2703 ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2704 for (SCTAB nTab = 0; nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
2705 if (pClipDoc->maTabs[nTab]) // all sheets of the clipboard content
2707 SCCOL nThisEndX = aClipRange.aEnd.Col();
2708 SCROW nThisEndY = aClipRange.aEnd.Row();
2709 pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2710 aClipRange.aStart.Row(),
2711 nThisEndX, nThisEndY, nTab );
2712 // only extra value from ExtendMerge
2713 nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2714 nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2715 if ( nThisEndX > nXw )
2716 nXw = nThisEndX;
2717 if ( nThisEndY > nYw )
2718 nYw = nThisEndY;
2721 SCCOL nDestAddX;
2722 SCROW nDestAddY;
2723 pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2724 nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2725 nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2727 /* Decide which contents to delete before copying. Delete all
2728 contents if nInsFlag contains any real content flag.
2729 #i102056# Notes are pasted from clipboard in a second pass,
2730 together with the special flag IDF_ADDNOTES that states to not
2731 overwrite/delete existing cells but to insert the notes into
2732 these cells. In this case, just delete old notes from the
2733 destination area. */
2734 InsertDeleteFlags nDelFlag = IDF_NONE;
2735 if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2736 nDelFlag |= IDF_NOTE;
2737 else if ( nInsFlag & IDF_CONTENTS )
2738 nDelFlag |= IDF_CONTENTS;
2740 if (nInsFlag & IDF_ATTRIB)
2741 nDelFlag |= IDF_ATTRIB;
2743 sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2744 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2745 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2746 aCxt.setDeleteFlag(nDelFlag);
2748 ScRangeList aLocalRangeList;
2749 if (!pDestRanges)
2751 aLocalRangeList.Append( rDestRange);
2752 pDestRanges = &aLocalRangeList;
2755 bInsertingFromOtherDoc = true; // kein Broadcast/Listener aufbauen bei Insert
2757 sc::ColumnSpanSet aBroadcastSpans(false);
2759 SCCOL nClipStartCol = aClipRange.aStart.Col();
2760 SCROW nClipStartRow = aClipRange.aStart.Row();
2761 SCROW nClipEndRow = aClipRange.aEnd.Row();
2762 for ( size_t nRange = 0; nRange < pDestRanges->size(); ++nRange )
2764 const ScRange* pRange = (*pDestRanges)[nRange];
2765 SCCOL nCol1 = pRange->aStart.Col();
2766 SCROW nRow1 = pRange->aStart.Row();
2767 SCCOL nCol2 = pRange->aEnd.Col();
2768 SCROW nRow2 = pRange->aEnd.Row();
2770 if (bSkipAttrForEmpty)
2772 // Delete cells in the destination only if their corresponding clip cells are not empty.
2773 aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
2774 DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);
2776 else
2777 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag, false, &aBroadcastSpans);
2779 if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2))
2780 continue;
2782 SCCOL nC1 = nCol1;
2783 SCROW nR1 = nRow1;
2784 SCCOL nC2 = nC1 + nXw;
2785 if (nC2 > nCol2)
2786 nC2 = nCol2;
2787 SCROW nR2 = nR1 + nYw;
2788 if (nR2 > nRow2)
2789 nR2 = nRow2;
2791 const SCCOLROW nThreshold = 8192;
2792 bool bPreallocatePattern = ((nInsFlag & IDF_ATTRIB) && (nRow2 - nRow1 > nThreshold));
2793 std::vector< SCTAB > vTables;
2795 if (bPreallocatePattern)
2797 for (SCTAB i = aCxt.getTabStart(); i <= aCxt.getTabEnd(); ++i)
2798 if (maTabs[i] && rMark.GetTableSelect( i ) )
2799 vTables.push_back( i );
2804 // Pasting is done column-wise, when pasting to a filtered
2805 // area this results in partitioning and we have to
2806 // remember and reset the start row for each column until
2807 // it can be advanced for the next chunk of unfiltered
2808 // rows.
2809 SCROW nSaveClipStartRow = nClipStartRow;
2812 nClipStartRow = nSaveClipStartRow;
2813 SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2814 SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2815 if ( bIncludeFiltered )
2817 CopyBlockFromClip(
2818 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nDy);
2819 nClipStartRow += nR2 - nR1 + 1;
2821 else
2823 CopyNonFilteredFromClip(
2824 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nClipStartRow);
2826 nC1 = nC2 + 1;
2827 nC2 = std::min((SCCOL)(nC1 + nXw), nCol2);
2828 } while (nC1 <= nCol2);
2829 if (nClipStartRow > nClipEndRow)
2830 nClipStartRow = aClipRange.aStart.Row();
2831 nC1 = nCol1;
2832 nC2 = nC1 + nXw;
2833 if (nC2 > nCol2)
2834 nC2 = nCol2;
2836 // Preallocate pattern memory once if further chunks are to be pasted.
2837 if (bPreallocatePattern && (nR2+1) <= nRow2)
2839 SCROW nR3 = nR2 + 1;
2840 for (size_t j = 0; j < vTables.size(); ++j)
2842 SCTAB nTab = vTables[j];
2843 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2845 // Pattern count of the first chunk pasted.
2846 SCSIZE nChunk = GetPatternCount( nTab, nCol, nR1, nR2);
2847 // If it is only one pattern per chunk and chunks are
2848 // pasted consecutively then it will get its range
2849 // enlarged for each chunk and no further allocation
2850 // happens. For non-consecutive chunks we're out of
2851 // luck in this case.
2852 if (nChunk > 1)
2854 SCSIZE nNeeded = nChunk * (nRow2 - nR3 + 1) / (nYw + 1);
2855 SCSIZE nRemain = GetPatternCount( nTab, nCol, nR3, nRow2);
2856 if (nNeeded > nRemain)
2858 SCSIZE nCurr = GetPatternCount( nTab, nCol);
2859 ReservePatternCount( nTab, nCol, nCurr + nNeeded);
2864 bPreallocatePattern = false;
2867 nR1 = nR2 + 1;
2868 nR2 = std::min((SCROW)(nR1 + nYw), nRow2);
2869 } while (nR1 <= nRow2);
2872 bInsertingFromOtherDoc = false;
2874 // Create Listener after everything has been inserted
2875 StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2878 ScBulkBroadcast aBulkBroadcast( GetBASM());
2880 // Set all formula cells dirty, and collect non-empty non-formula cell
2881 // positions so that we can broadcast on them below.
2882 SetDirtyFromClip(nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag, aBroadcastSpans);
2884 BroadcastAction aAction(*this);
2885 aBroadcastSpans.executeColumnAction(*this, aAction);
2888 if (bResetCut)
2889 pClipDoc->GetClipParam().mbCutMode = false;
2892 void ScDocument::CopyMultiRangeFromClip(
2893 const ScAddress& rDestPos, const ScMarkData& rMark, InsertDeleteFlags nInsFlag, ScDocument* pClipDoc,
2894 bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2896 if (bIsClip)
2897 return;
2899 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2900 // There is nothing in the clip doc to copy.
2901 return;
2903 // Right now, we don't allow pasting into filtered rows, so we don't even handle it here.
2905 sc::AutoCalcSwitch aACSwitch(*this, false); // turn of auto calc temporarily.
2906 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2908 ScRange aDestRange;
2909 rMark.GetMarkArea(aDestRange);
2911 bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
2913 SCCOL nCol1 = rDestPos.Col();
2914 SCROW nRow1 = rDestPos.Row();
2915 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2917 sc::ColumnSpanSet aBroadcastSpans(false);
2919 if (!bSkipAttrForEmpty)
2921 // Do the deletion first.
2922 InsertDeleteFlags nDelFlag = IDF_CONTENTS;
2923 SCCOL nColSize = rClipParam.getPasteColSize();
2924 SCROW nRowSize = rClipParam.getPasteRowSize();
2926 DeleteArea(nCol1, nRow1, nCol1+nColSize-1, nRow1+nRowSize-1, rMark, nDelFlag, false, &aBroadcastSpans);
2929 sc::CopyFromClipContext aCxt(*this, NULL, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2930 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2931 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2933 for (size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i)
2935 ScRange* p = rClipParam.maRanges[i];
2937 SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2938 SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2939 SCsROW nDy = static_cast<SCsROW>(nRow1 - p->aStart.Row());
2940 SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2941 SCROW nEndRow = nRow1 + nRowCount - 1;
2943 CopyBlockFromClip(aCxt, nCol1, nRow1, nCol2, nEndRow, rMark, nDx, nDy);
2945 switch (rClipParam.meDirection)
2947 case ScClipParam::Row:
2948 // Begin row for the next range being pasted.
2949 nRow1 += nRowCount;
2950 break;
2951 case ScClipParam::Column:
2952 nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2953 break;
2954 default:
2959 bInsertingFromOtherDoc = false;
2961 // Create Listener after everything has been inserted
2962 StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2963 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2966 ScBulkBroadcast aBulkBroadcast( GetBASM());
2968 // Set formula cells dirty and collect non-formula cells.
2969 SetDirtyFromClip(
2970 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aEnd.Col(), aDestRange.aEnd.Row(),
2971 rMark, nInsFlag, aBroadcastSpans);
2973 BroadcastAction aAction(*this);
2974 aBroadcastSpans.executeColumnAction(*this, aAction);
2977 if (bResetCut)
2978 pClipDoc->GetClipParam().mbCutMode = false;
2981 void ScDocument::SetClipArea( const ScRange& rArea, bool bCut )
2983 if (bIsClip)
2985 ScClipParam& rClipParam = GetClipParam();
2986 rClipParam.maRanges.RemoveAll();
2987 rClipParam.maRanges.Append(rArea);
2988 rClipParam.mbCutMode = bCut;
2990 else
2992 OSL_FAIL("SetClipArea: No Clip");
2996 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered)
2998 if (!bIsClip)
3000 OSL_FAIL("GetClipArea: No Clip");
3001 return;
3004 ScRangeList& rClipRanges = GetClipParam().maRanges;
3005 if (rClipRanges.empty())
3006 // No clip range. Bail out.
3007 return;
3009 ScRange* p = rClipRanges.front();
3010 SCCOL nStartCol = p->aStart.Col();
3011 SCCOL nEndCol = p->aEnd.Col();
3012 SCROW nStartRow = p->aStart.Row();
3013 SCROW nEndRow = p->aEnd.Row();
3014 for ( size_t i = 1, n = rClipRanges.size(); i < n; ++i )
3016 p = rClipRanges[ i ];
3017 if (p->aStart.Col() < nStartCol)
3018 nStartCol = p->aStart.Col();
3019 if (p->aStart.Row() < nStartRow)
3020 nStartRow = p->aStart.Row();
3021 if (p->aEnd.Col() > nEndCol)
3022 nEndCol = p->aEnd.Col();
3023 if (p->aEnd.Row() < nEndRow)
3024 nEndRow = p->aEnd.Row();
3027 nClipX = nEndCol - nStartCol;
3029 if ( bIncludeFiltered )
3030 nClipY = nEndRow - nStartRow;
3031 else
3033 // count non-filtered rows
3034 // count on first used table in clipboard
3035 SCTAB nCountTab = 0;
3036 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3037 ++nCountTab;
3039 SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
3041 if ( nResult > 0 )
3042 nClipY = nResult - 1;
3043 else
3044 nClipY = 0; // always return at least 1 row
3048 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
3050 if (bIsClip)
3052 ScRangeList& rClipRanges = GetClipParam().maRanges;
3053 if ( !rClipRanges.empty() )
3055 nClipX = rClipRanges.front()->aStart.Col();
3056 nClipY = rClipRanges.front()->aStart.Row();
3059 else
3061 OSL_FAIL("GetClipStart: No Clip");
3065 bool ScDocument::HasClipFilteredRows()
3067 // count on first used table in clipboard
3068 SCTAB nCountTab = 0;
3069 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3070 ++nCountTab;
3072 ScRangeList& rClipRanges = GetClipParam().maRanges;
3073 if ( rClipRanges.empty() )
3074 return false;
3076 for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
3078 ScRange* p = rClipRanges[ i ];
3079 bool bAnswer = maTabs[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
3080 if (bAnswer)
3081 return true;
3083 return false;
3086 void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, bool bSkipEmpty,
3087 ScDocument* pSrcDoc )
3089 SCTAB nTab1 = rRange.aStart.Tab();
3090 SCTAB nTab2 = rRange.aEnd.Tab();
3091 sc::MixDocContext aCxt(*this);
3092 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pSrcDoc->maTabs.size()));
3093 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
3095 ScTable* pTab = FetchTable(i);
3096 const ScTable* pSrcTab = pSrcDoc->FetchTable(i);
3097 if (!pTab || !pSrcTab)
3098 continue;
3100 pTab->MixData(
3101 aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
3102 nFunction, bSkipEmpty, pSrcTab);
3106 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
3107 InsertDeleteFlags nFlags, sal_uInt16 nFunction,
3108 bool bSkipEmpty, bool bAsLink )
3110 InsertDeleteFlags nDelFlags = nFlags;
3111 if (nDelFlags & IDF_CONTENTS)
3112 nDelFlags |= IDF_CONTENTS; // Either all contents or delete nothing!
3114 SCTAB nSrcTab = rSrcArea.aStart.Tab();
3116 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3118 SCCOL nStartCol = rSrcArea.aStart.Col();
3119 SCROW nStartRow = rSrcArea.aStart.Row();
3120 SCCOL nEndCol = rSrcArea.aEnd.Col();
3121 SCROW nEndRow = rSrcArea.aEnd.Row();
3122 boost::scoped_ptr<ScDocument> pMixDoc;
3123 bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
3125 bool bOldAutoCalc = GetAutoCalc();
3126 SetAutoCalc( false ); // avoid multiple calculations
3128 sc::CopyToDocContext aCxt(*this);
3129 sc::MixDocContext aMixDocCxt(*this);
3131 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3132 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
3133 for (; itr != itrEnd && *itr < nCount; ++itr)
3134 if ( *itr!=nSrcTab && maTabs[*itr])
3136 SCTAB i = *itr;
3137 if (bDoMix)
3139 if (!pMixDoc)
3141 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3142 pMixDoc->InitUndo( this, i, i );
3144 else
3145 pMixDoc->AddUndoTab( i, i );
3147 // context used for copying content to the temporary mix document.
3148 sc::CopyToDocContext aMixCxt(*pMixDoc);
3149 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3150 IDF_CONTENTS, false, pMixDoc->maTabs[i] );
3152 maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
3153 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3154 nFlags, false, maTabs[i], NULL, bAsLink );
3156 if (bDoMix)
3157 maTabs[i]->MixData(aMixDocCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3158 nFunction, bSkipEmpty, pMixDoc->maTabs[i] );
3161 SetAutoCalc( bOldAutoCalc );
3163 else
3165 OSL_FAIL("wrong table");
3169 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
3170 InsertDeleteFlags nFlags, sal_uInt16 nFunction,
3171 bool bSkipEmpty, bool bAsLink )
3173 InsertDeleteFlags nDelFlags = nFlags;
3174 if (nDelFlags & IDF_CONTENTS)
3175 nDelFlags |= IDF_CONTENTS; // Either all contents or delete nothing!
3177 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3179 boost::scoped_ptr<ScDocument> pMixDoc;
3180 bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
3182 bool bOldAutoCalc = GetAutoCalc();
3183 SetAutoCalc( false ); // avoid multiple calculations
3185 ScRange aArea;
3186 rMark.GetMultiMarkArea( aArea );
3187 SCCOL nStartCol = aArea.aStart.Col();
3188 SCROW nStartRow = aArea.aStart.Row();
3189 SCCOL nEndCol = aArea.aEnd.Col();
3190 SCROW nEndRow = aArea.aEnd.Row();
3192 sc::CopyToDocContext aCxt(*this);
3193 sc::MixDocContext aMixDocCxt(*this);
3194 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3195 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
3196 for (; itr != itrEnd && *itr < nCount; ++itr)
3197 if ( *itr!=nSrcTab && maTabs[*itr] )
3199 SCTAB i = *itr;
3200 if (bDoMix)
3202 if (!pMixDoc)
3204 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3205 pMixDoc->InitUndo( this, i, i );
3207 else
3208 pMixDoc->AddUndoTab( i, i );
3210 sc::CopyToDocContext aMixCxt(*pMixDoc);
3211 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3212 IDF_CONTENTS, true, pMixDoc->maTabs[i], &rMark );
3215 maTabs[i]->DeleteSelection( nDelFlags, rMark );
3216 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3217 nFlags, true, maTabs[i], &rMark, bAsLink );
3219 if (bDoMix)
3220 maTabs[i]->MixMarked(aMixDocCxt, rMark, nFunction, bSkipEmpty, pMixDoc->maTabs[i]);
3223 SetAutoCalc( bOldAutoCalc );
3225 else
3227 OSL_FAIL("wrong table");
3231 bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
3232 ScSetStringParam* pParam )
3234 ScTable* pTab = FetchTable(nTab);
3235 if (!pTab)
3236 return false;
3238 bool bNumFmtSet = false;
3240 const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(nCol, nRow);
3241 if (pCurCellFormula && pCurCellFormula->IsShared())
3243 // In case setting this string affects an existing formula group, record
3244 // its above and below position for later listening.
3246 std::vector<ScAddress> aGroupPos;
3247 sc::EndListeningContext aCxt(*this);
3248 ScAddress aPos(nCol, nRow, nTab);
3249 EndListeningIntersectedGroup(aCxt, aPos, &aGroupPos);
3250 aCxt.purgeEmptyBroadcasters();
3252 bNumFmtSet = pTab->SetString(nCol, nRow, nTab, rString, pParam);
3254 SetNeedsListeningGroups(aGroupPos);
3255 StartNeededListeners();
3257 else
3259 bNumFmtSet = pTab->SetString(nCol, nRow, nTab, rString, pParam);
3262 return bNumFmtSet;
3265 bool ScDocument::SetString(
3266 const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam )
3268 return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam);
3271 bool ScDocument::SetEditText( const ScAddress& rPos, EditTextObject* pEditText )
3273 if (!TableExists(rPos.Tab()))
3275 delete pEditText;
3276 return false;
3279 return maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), pEditText);
3282 void ScDocument::SetEditText( const ScAddress& rPos, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
3284 if (!TableExists(rPos.Tab()))
3285 return;
3287 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
3290 void ScDocument::SetEditText( const ScAddress& rPos, const OUString& rStr )
3292 if (!TableExists(rPos.Tab()))
3293 return;
3295 ScFieldEditEngine& rEngine = GetEditEngine();
3296 rEngine.SetText(rStr);
3297 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3300 SCROW ScDocument::GetFirstEditTextRow( const ScRange& rRange ) const
3302 const ScTable* pTab = FetchTable(rRange.aStart.Tab());
3303 if (!pTab)
3304 return -1;
3306 return pTab->GetFirstEditTextRow(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3309 void ScDocument::SetTextCell( const ScAddress& rPos, const OUString& rStr )
3311 if (!TableExists(rPos.Tab()))
3312 return;
3314 if (ScStringUtil::isMultiline(rStr))
3316 ScFieldEditEngine& rEngine = GetEditEngine();
3317 rEngine.SetText(rStr);
3318 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3320 else
3322 ScSetStringParam aParam;
3323 aParam.setTextInput();
3324 maTabs[rPos.Tab()]->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
3328 void ScDocument::SetEmptyCell( const ScAddress& rPos )
3330 if (!TableExists(rPos.Tab()))
3331 return;
3333 maTabs[rPos.Tab()]->SetEmptyCell(rPos.Col(), rPos.Row());
3336 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
3338 SetValue(ScAddress(nCol, nRow, nTab), rVal);
3341 void ScDocument::SetValue( const ScAddress& rPos, double fVal )
3343 ScTable* pTab = FetchTable(rPos.Tab());
3344 if (!pTab)
3345 return;
3347 const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(rPos.Col(), rPos.Row());
3348 if (pCurCellFormula && pCurCellFormula->IsShared())
3350 // In case setting this string affects an existing formula group, record
3351 // its above and below position for later listening.
3353 std::vector<ScAddress> aGroupPos;
3354 sc::EndListeningContext aCxt(*this);
3355 EndListeningIntersectedGroup(aCxt, rPos, &aGroupPos);
3356 aCxt.purgeEmptyBroadcasters();
3358 pTab->SetValue(rPos.Col(), rPos.Row(), fVal);
3360 SetNeedsListeningGroups(aGroupPos);
3361 StartNeededListeners();
3363 else
3365 pTab->SetValue(rPos.Col(), rPos.Row(), fVal);
3369 OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3371 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3373 OUString aStr;
3374 maTabs[nTab]->GetString(nCol, nRow, aStr);
3375 return aStr;
3377 else
3378 return EMPTY_OUSTRING;
3381 OUString ScDocument::GetString( const ScAddress& rPos ) const
3383 if (!TableExists(rPos.Tab()))
3384 return EMPTY_OUSTRING;
3386 OUString aStr;
3387 maTabs[rPos.Tab()]->GetString(rPos.Col(), rPos.Row(), aStr);
3388 return aStr;
3391 double* ScDocument::GetValueCell( const ScAddress& rPos )
3393 if (!TableExists(rPos.Tab()))
3394 return NULL;
3396 return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
3399 svl::SharedString ScDocument::GetSharedString( const ScAddress& rPos ) const
3401 if (!TableExists(rPos.Tab()))
3402 return svl::SharedString();
3404 return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
3407 sc::FormulaGroupContext& ScDocument::GetFormulaGroupContext()
3409 if (!mpFormulaGroupCxt)
3410 mpFormulaGroupCxt.reset(new sc::FormulaGroupContext);
3412 return *mpFormulaGroupCxt;
3415 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
3417 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3418 maTabs[nTab]->GetInputString( nCol, nRow, rString );
3419 else
3420 rString.clear();
3423 sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& rString )
3425 // Used in formulas (add-in parameters etc), so it must use the same semantics as
3426 // ScInterpreter::GetCellString: always format values as numbers.
3427 // The return value is the error code.
3429 ScRefCellValue aCell;
3430 aCell.assign(*this, rPos);
3431 if (aCell.isEmpty())
3433 rString = EMPTY_OUSTRING;
3434 return 0;
3437 sal_uInt16 nErr = 0;
3438 OUString aStr;
3439 SvNumberFormatter* pFormatter = GetFormatTable();
3440 switch (aCell.meType)
3442 case CELLTYPE_STRING:
3443 case CELLTYPE_EDIT:
3444 aStr = aCell.getString(this);
3445 break;
3446 case CELLTYPE_FORMULA:
3448 ScFormulaCell* pFCell = aCell.mpFormula;
3449 nErr = pFCell->GetErrCode();
3450 if (pFCell->IsValue())
3452 double fVal = pFCell->GetValue();
3453 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3454 css::util::NumberFormat::NUMBER,
3455 ScGlobal::eLnge);
3456 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3458 else
3459 aStr = pFCell->GetString().getString();
3461 break;
3462 case CELLTYPE_VALUE:
3464 double fVal = aCell.mfValue;
3465 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3466 css::util::NumberFormat::NUMBER,
3467 ScGlobal::eLnge);
3468 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3470 break;
3471 default:
3475 rString = aStr;
3476 return nErr;
3479 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ) const
3481 if (TableExists(nTab))
3482 rValue = maTabs[nTab]->GetValue( nCol, nRow );
3483 else
3484 rValue = 0.0;
3487 const EditTextObject* ScDocument::GetEditText( const ScAddress& rPos ) const
3489 SCTAB nTab = rPos.Tab();
3490 if (!TableExists(nTab))
3491 return NULL;
3493 return maTabs[nTab]->GetEditText(rPos.Col(), rPos.Row());
3496 void ScDocument::RemoveEditTextCharAttribs( const ScAddress& rPos, const ScPatternAttr& rAttr )
3498 if (!TableExists(rPos.Tab()))
3499 return;
3501 return maTabs[rPos.Tab()]->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
3504 double ScDocument::GetValue( const ScAddress& rPos ) const
3506 SCTAB nTab = rPos.Tab();
3507 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3508 return maTabs[nTab]->GetValue(rPos.Col(), rPos.Row());
3509 return 0.0;
3512 double ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3514 ScAddress aAdr(nCol, nRow, nTab); return GetValue(aAdr);
3517 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
3518 sal_uInt32& rFormat ) const
3520 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
3521 if (maTabs[nTab])
3523 rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
3524 return ;
3526 rFormat = 0;
3529 sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
3531 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
3532 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
3533 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3535 if (!ValidTab(nTab1) || !ValidTab(nTab2) || !maTabs[nTab1] || !maTabs[nTab2])
3536 return 0;
3538 sal_uInt32 nFormat = 0;
3539 bool bFirstItem = true;
3540 for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
3541 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
3543 sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
3544 if (bFirstItem)
3546 nFormat = nThisFormat;
3547 bFirstItem = false;
3549 else if (nThisFormat != nFormat)
3550 return 0;
3553 return nFormat;
3556 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
3558 SCTAB nTab = rPos.Tab();
3559 if (!TableExists(nTab))
3560 return 0;
3562 return maTabs[nTab]->GetNumberFormat( rPos );
3565 void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
3567 SCTAB nTab = rPos.Tab();
3568 if (!TableExists(nTab))
3569 return;
3571 maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
3574 void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
3575 const ScAddress& rPos ) const
3577 SCTAB nTab = rPos.Tab();
3578 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3580 nIndex = maTabs[nTab]->GetNumberFormat( rPos );
3581 nType = GetFormatTable()->GetType( nIndex );
3583 else
3585 nType = css::util::NumberFormat::UNDEFINED;
3586 nIndex = 0;
3590 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const
3592 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3593 maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
3594 else
3595 rFormula.clear();
3598 const ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos ) const
3600 if (!TableExists(rPos.Tab()))
3601 return NULL;
3603 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3606 ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos )
3608 if (!TableExists(rPos.Tab()))
3609 return NULL;
3611 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3614 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
3616 SCTAB nTab = rPos.Tab();
3617 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3618 return maTabs[nTab]->GetCellType( rPos );
3619 return CELLTYPE_NONE;
3622 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
3623 CellType& rCellType ) const
3625 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3626 rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
3627 else
3628 rCellType = CELLTYPE_NONE;
3631 bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3633 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3634 return maTabs[nTab]->HasStringData( nCol, nRow );
3635 else
3636 return false;
3639 bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3641 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3642 return maTabs[nTab]->HasValueData( nCol, nRow );
3643 else
3644 return false;
3647 bool ScDocument::HasValueData( const ScAddress& rPos ) const
3649 return HasValueData(rPos.Col(), rPos.Row(), rPos.Tab());
3652 bool ScDocument::HasStringCells( const ScRange& rRange ) const
3654 // true, if String- or Edit cells in range
3656 SCCOL nStartCol = rRange.aStart.Col();
3657 SCROW nStartRow = rRange.aStart.Row();
3658 SCTAB nStartTab = rRange.aStart.Tab();
3659 SCCOL nEndCol = rRange.aEnd.Col();
3660 SCROW nEndRow = rRange.aEnd.Row();
3661 SCTAB nEndTab = rRange.aEnd.Tab();
3663 for ( SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
3664 if ( maTabs[nTab] && maTabs[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
3665 return true;
3667 return false;
3670 bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3672 sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
3673 if( nValidation )
3675 const ScValidationData* pData = GetValidationEntry( nValidation );
3676 if( pData && pData->HasSelectionList() )
3677 return true;
3679 return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
3682 void ScDocument::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
3684 bool bOldAutoCalc = GetAutoCalc();
3685 bAutoCalc = false; // no mulitple calculations
3686 { // scope for bulk broadcast
3687 ScBulkBroadcast aBulkBroadcast( GetBASM());
3688 TableContainer::iterator it = maTabs.begin();
3689 for (;it != maTabs.end(); ++it)
3690 if (*it)
3691 (*it)->SetAllFormulasDirty(rCxt);
3694 // Allthough Charts are also set to dirty in Tracking without AutoCalc
3695 // if all formulas are dirty, the charts can no longer be caught
3696 // (#45205#) - that is why all Charts have to be explicitly handled again
3697 if (pChartListenerCollection)
3698 pChartListenerCollection->SetDirty();
3700 SetAutoCalc( bOldAutoCalc );
3703 void ScDocument::SetDirty( const ScRange& rRange, bool bIncludeEmptyCells )
3705 bool bOldAutoCalc = GetAutoCalc();
3706 bAutoCalc = false; // no mulitple calculations
3707 { // scope for bulk broadcast
3708 ScBulkBroadcast aBulkBroadcast( GetBASM());
3709 SCTAB nTab2 = rRange.aEnd.Tab();
3710 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3711 if (maTabs[i]) maTabs[i]->SetDirty( rRange,
3712 (bIncludeEmptyCells ? ScColumn::BROADCAST_BROADCASTERS : ScColumn::BROADCAST_DATA_POSITIONS));
3714 /* TODO: this now also notifies conditional formatting and does an UNO
3715 * broadcast, which wasn't done here before. Is that an actually
3716 * desired side effect, or should we come up with a method that
3717 * doesn't? */
3718 if (bIncludeEmptyCells)
3719 BroadcastCells( rRange, SC_HINT_DATACHANGED, false);
3721 SetAutoCalc( bOldAutoCalc );
3724 void ScDocument::SetTableOpDirty( const ScRange& rRange )
3726 bool bOldAutoCalc = GetAutoCalc();
3727 bAutoCalc = false; // no multiple recalculation
3728 SCTAB nTab2 = rRange.aEnd.Tab();
3729 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3730 if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
3731 SetAutoCalc( bOldAutoCalc );
3734 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3736 if (!GetAutoCalc())
3737 return;
3739 mpFormulaGroupCxt.reset();
3741 for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
3743 const ScRange& rRange = *rRanges[nPos];
3744 for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
3746 ScTable* pTab = FetchTable(nTab);
3747 if (!pTab)
3748 return;
3750 pTab->InterpretDirtyCells(
3751 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3755 mpFormulaGroupCxt.reset();
3758 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3760 if ( !aTableOpList.empty() )
3762 ScInterpreterTableOpParams* p = &aTableOpList.back();
3763 if ( p->bCollectNotifications )
3765 if ( p->bRefresh )
3766 { // refresh pointers only
3767 p->aNotifiedFormulaCells.push_back( pCell );
3769 else
3770 { // init both, address and pointer
3771 p->aNotifiedFormulaCells.push_back( pCell );
3772 p->aNotifiedFormulaPos.push_back( pCell->aPos );
3778 void ScDocument::CalcAll()
3780 ClearFormulaContext();
3781 ClearLookupCaches(); // Ensure we don't deliver zombie data.
3782 sc::AutoCalcSwitch aSwitch(*this, true);
3783 TableContainer::iterator it = maTabs.begin();
3784 for (; it != maTabs.end(); ++it)
3785 if (*it)
3786 (*it)->SetDirtyVar();
3787 for (it = maTabs.begin(); it != maTabs.end(); ++it)
3788 if (*it)
3789 (*it)->CalcAll();
3790 ClearFormulaTree();
3792 // In hard recalc state caches were not added as listeners, invalidate them
3793 // so the next non-CalcAll() normal lookup will not be presented with
3794 // outdated data.
3795 /* TODO: come up with more detailed hard recalc states so we can
3796 * differentiate between hard recalc after load and others. */
3797 if (GetHardRecalcState())
3798 ClearLookupCaches();
3801 void ScDocument::CompileAll()
3803 sc::CompileFormulaContext aCxt(this);
3804 TableContainer::iterator it = maTabs.begin();
3805 for (; it != maTabs.end(); ++it)
3806 if (*it)
3807 (*it)->CompileAll(aCxt);
3809 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
3810 SetAllFormulasDirty(aFormulaDirtyCxt);
3813 namespace {
3815 class CompileXMLHandler : std::unary_function<ScTable*, void>
3817 sc::CompileFormulaContext* mpCxt;
3818 ScProgress* mpProgress;
3819 public:
3820 CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress ) :
3821 mpCxt(&rCxt), mpProgress(&rProgress) {} // Take pointers to make it copyable.
3823 void operator() ( ScTable* pTab )
3825 if (pTab)
3826 pTab->CompileXML(*mpCxt, *mpProgress);
3832 void ScDocument::CompileXML()
3834 bool bOldAutoCalc = GetAutoCalc();
3835 SetAutoCalc( false );
3836 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3837 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3839 sc::CompileFormulaContext aCxt(this);
3841 // set AutoNameCache to speed up automatic name lookup
3842 OSL_ENSURE( !pAutoNameCache, "AutoNameCache already set" );
3843 pAutoNameCache = new ScAutoNameCache( this );
3845 if (pRangeName)
3846 pRangeName->CompileUnresolvedXML(aCxt);
3848 std::for_each(maTabs.begin(), maTabs.end(), CompileXMLHandler(aCxt, aProgress));
3849 StartAllListeners();
3851 DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
3853 if ( pValidationList )
3854 pValidationList->CompileXML();
3856 // Track all formula cells that were appended to the FormulaTrack during
3857 // import or CompileXML().
3858 TrackFormulas();
3860 SetAutoCalc( bOldAutoCalc );
3863 bool ScDocument::CompileErrorCells(sal_uInt16 nErrCode)
3865 bool bCompiled = false;
3866 sc::CompileFormulaContext aCxt(this);
3867 TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
3868 for (; it != itEnd; ++it)
3870 ScTable* pTab = *it;
3871 if (!pTab)
3872 continue;
3874 if (pTab->CompileErrorCells(aCxt, nErrCode))
3875 bCompiled = true;
3878 return bCompiled;
3881 void ScDocument::CalcAfterLoad( bool bStartListening )
3883 if (bIsClip) // Excel data is loaded from the Clipboard to a Clip-Doc
3884 return; // the clculation is then only perfromed when inserting into the real document
3886 bCalcingAfterLoad = true;
3887 sc::CompileFormulaContext aCxt(this);
3889 TableContainer::iterator it = maTabs.begin();
3890 for (; it != maTabs.end(); ++it)
3891 if (*it)
3892 (*it)->CalcAfterLoad(aCxt, bStartListening);
3893 for (it = maTabs.begin(); it != maTabs.end(); ++it)
3894 if (*it)
3895 (*it)->SetDirtyAfterLoad();
3897 bCalcingAfterLoad = false;
3899 SetDetectiveDirty(false); // No real changes yet
3901 // #i112436# If formula cells are already dirty, they don't broadcast further changes.
3902 // So the source ranges of charts must be interpreted even if they are not visible,
3903 // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
3904 if (pChartListenerCollection)
3906 const ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners();
3907 ScChartListenerCollection::ListenersType::const_iterator it = rListeners.begin(), itEnd = rListeners.end();
3908 for (; it != itEnd; ++it)
3910 const ScChartListener* p = it->second;
3911 InterpretDirtyCells(*p->GetRangeList());
3916 sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
3918 SCTAB nTab = rPos.Tab();
3919 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3920 return maTabs[nTab]->GetErrCode( rPos );
3921 return 0;
3924 void ScDocument::ResetChanged( const ScRange& rRange )
3926 SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
3927 SCTAB nTab1 = rRange.aStart.Tab();
3928 SCTAB nTab2 = rRange.aEnd.Tab();
3929 for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
3930 if (maTabs[nTab])
3931 maTabs[nTab]->ResetChanged(rRange);
3934 // Column widths / Row heights --------------------------------------
3936 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3938 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3939 maTabs[nTab]->SetColWidth( nCol, nNewWidth );
3942 void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3944 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3945 maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
3948 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
3950 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3951 maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
3954 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3956 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3957 maTabs[nTab]->SetRowHeightRange
3958 ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3961 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3963 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3964 maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
3967 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
3969 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3970 maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3973 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
3975 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3976 return maTabs[nTab]->GetColWidth( nCol, bHiddenAsZero );
3977 OSL_FAIL("wrong table number");
3978 return 0;
3981 sal_uLong ScDocument::GetColWidth( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHiddenAsZero ) const
3983 const ScTable* pTab = FetchTable(nTab);
3984 if (!pTab)
3985 return 0;
3987 return pTab->GetColWidth(nStartCol, nEndCol, bHiddenAsZero);
3990 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3992 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3993 return maTabs[nTab]->GetOriginalWidth( nCol );
3994 OSL_FAIL("wrong table number");
3995 return 0;
3998 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
4000 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4001 return maTabs[nTab]->GetCommonWidth( nEndCol );
4002 OSL_FAIL("Wrong table number");
4003 return 0;
4006 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
4008 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4009 return maTabs[nTab]->GetOriginalHeight( nRow );
4010 OSL_FAIL("Wrong table number");
4011 return 0;
4014 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4016 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4017 return maTabs[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
4018 OSL_FAIL("Wrong sheet number");
4019 return 0;
4022 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
4024 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4025 return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
4026 OSL_FAIL("Wrong sheet number");
4027 return 0;
4030 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
4032 if (nStartRow == nEndRow)
4033 return GetRowHeight( nStartRow, nTab, bHiddenAsZero ); // faster for a single row
4035 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4036 if (nStartRow > nEndRow)
4037 return 0;
4039 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4040 return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
4042 OSL_FAIL("wrong sheet number");
4043 return 0;
4046 SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
4048 return maTabs[nTab]->GetRowForHeight(nHeight);
4051 sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
4052 SCTAB nTab, double fScale ) const
4054 // faster for a single row
4055 if (nStartRow == nEndRow)
4056 return (sal_uLong) (GetRowHeight( nStartRow, nTab) * fScale);
4058 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4059 if (nStartRow > nEndRow)
4060 return 0;
4062 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4063 return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
4065 OSL_FAIL("wrong sheet number");
4066 return 0;
4069 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
4071 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4072 return maTabs[nTab]->GetHiddenRowCount( nRow );
4073 OSL_FAIL("wrong table number");
4074 return 0;
4077 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
4079 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4080 return maTabs[nTab]->GetColOffset( nCol, bHiddenAsZero );
4081 OSL_FAIL("wrong table number");
4082 return 0;
4085 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4087 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4088 return maTabs[nTab]->GetRowOffset( nRow, bHiddenAsZero );
4089 OSL_FAIL("wrong table number");
4090 return 0;
4093 sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
4094 double nPPTX, double nPPTY,
4095 const Fraction& rZoomX, const Fraction& rZoomY,
4096 bool bFormula, const ScMarkData* pMarkData,
4097 const ScColWidthParam* pParam )
4099 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4100 return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
4101 rZoomX, rZoomY, bFormula, pMarkData, pParam );
4102 OSL_FAIL("wrong table number");
4103 return 0;
4106 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
4107 OutputDevice* pDev,
4108 double nPPTX, double nPPTY,
4109 const Fraction& rZoomX, const Fraction& rZoomY,
4110 bool bWidth, bool bTotalSize )
4112 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4113 return maTabs[nTab]->GetNeededSize
4114 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
4115 OSL_FAIL("wrong table number");
4116 return 0;
4119 bool ScDocument::SetOptimalHeight( sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
4121 ScTable* pTab = FetchTable(nTab);
4122 if (!pTab)
4123 return false;
4125 return pTab->SetOptimalHeight(rCxt, nStartRow, nEndRow);
4128 void ScDocument::UpdateAllRowHeights( sc::RowHeightContext& rCxt, const ScMarkData* pTabMark )
4130 // one progress across all (selected) sheets
4132 sal_uLong nCellCount = 0;
4133 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4134 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4135 nCellCount += maTabs[nTab]->GetWeightedCount();
4137 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
4139 sal_uLong nProgressStart = 0;
4140 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4141 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4143 maTabs[nTab]->SetOptimalHeightOnly(rCxt, 0, MAXROW, &aProgress, nProgressStart);
4144 maTabs[nTab]->SetDrawPageSize(true, true);
4145 nProgressStart += maTabs[nTab]->GetWeightedCount();
4149 // Column/Row - Flags ----------------------------------------------
4151 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
4153 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4154 maTabs[nTab]->ShowCol( nCol, bShow );
4157 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
4159 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4160 maTabs[nTab]->ShowRow( nRow, bShow );
4163 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
4165 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4166 maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
4169 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
4171 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4172 maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
4175 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
4177 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4178 maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
4181 sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
4183 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4184 return maTabs[nTab]->GetColFlags( nCol );
4185 OSL_FAIL("wrong table number");
4186 return 0;
4189 sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
4191 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4192 return maTabs[nTab]->GetRowFlags( nRow );
4193 OSL_FAIL("wrong table number");
4194 return 0;
4197 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4199 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4200 return;
4201 maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
4204 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4206 if (!ValidTab(nTab) || !maTabs[nTab])
4207 return;
4209 maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
4212 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
4214 ScBreakType nType = BREAK_NONE;
4215 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4216 return nType;
4218 if (maTabs[nTab]->HasRowPageBreak(nRow))
4219 nType |= BREAK_PAGE;
4221 if (maTabs[nTab]->HasRowManualBreak(nRow))
4222 nType |= BREAK_MANUAL;
4224 return nType;
4227 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
4229 ScBreakType nType = BREAK_NONE;
4230 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4231 return nType;
4233 if (maTabs[nTab]->HasColPageBreak(nCol))
4234 nType |= BREAK_PAGE;
4236 if (maTabs[nTab]->HasColManualBreak(nCol))
4237 nType |= BREAK_MANUAL;
4239 return nType;
4242 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4244 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4245 return;
4247 maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
4250 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4252 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4253 return;
4255 maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
4258 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4260 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4261 return;
4263 maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
4266 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4268 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4269 return;
4271 maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
4274 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
4276 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4277 return Sequence<TablePageBreakData>();
4279 return maTabs[nTab]->GetRowBreakData();
4282 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4284 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4285 return false;
4287 return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
4290 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4292 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4293 return false;
4295 return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
4298 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4300 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4302 if (pFirstCol)
4303 *pFirstCol = nCol;
4304 if (pLastCol)
4305 *pLastCol = nCol;
4306 return false;
4309 return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
4312 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
4314 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4315 return;
4317 maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
4320 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
4322 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4323 return;
4325 maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
4328 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4330 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4331 return ::std::numeric_limits<SCROW>::max();
4333 return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
4336 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4338 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4339 return ::std::numeric_limits<SCROW>::max();
4341 return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
4344 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4346 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4347 return 0;
4349 return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
4352 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4354 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4355 return false;
4357 return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
4360 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4362 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4363 return false;
4365 return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
4368 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4370 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4371 return false;
4373 return maTabs[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
4376 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
4378 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4379 return;
4381 maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
4384 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4386 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4387 return ::std::numeric_limits<SCROW>::max();
4389 return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
4392 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4394 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4395 return ::std::numeric_limits<SCROW>::max();
4397 return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
4400 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4402 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4403 return 0;
4405 return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
4408 bool ScDocument::IsManualRowHeight(SCROW nRow, SCTAB nTab) const
4410 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4411 return false;
4413 return maTabs[nTab]->IsManualRowHeight(nRow);
4416 void ScDocument::SyncColRowFlags()
4418 TableContainer::iterator it = maTabs.begin();
4419 for (; it != maTabs.end(); ++it)
4421 if (*it)
4422 (*it)->SyncColRowFlags();
4426 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
4428 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4429 return maTabs[nTab]->GetLastFlaggedRow();
4430 return 0;
4433 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
4435 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4436 return maTabs[nTab]->GetLastChangedCol();
4437 return 0;
4440 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
4442 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4443 return maTabs[nTab]->GetLastChangedRow();
4444 return 0;
4447 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
4449 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4451 sal_uInt8 nStartFlags = maTabs[nTab]->GetColFlags(nStart);
4452 sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
4453 for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
4455 if (((nStartFlags & CR_MANUALBREAK) != (maTabs[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
4456 (nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
4457 ((nStartFlags & CR_HIDDEN) != (maTabs[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
4458 return nCol;
4460 return MAXCOL+1;
4462 return 0;
4465 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
4467 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4468 return 0;
4470 const ScBitMaskCompressedArray<SCROW, sal_uInt8>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
4471 if (!pRowFlagsArray)
4472 return 0;
4474 if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
4475 return 0;
4477 size_t nIndex; // ignored
4478 SCROW nFlagsEndRow;
4479 SCROW nHiddenEndRow;
4480 SCROW nHeightEndRow;
4481 sal_uInt8 nFlags;
4482 bool bHidden;
4483 sal_uInt16 nHeight;
4484 sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
4485 bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
4486 sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
4487 SCROW nRow;
4488 while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
4490 if (nFlagsEndRow < nRow)
4491 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
4492 if (nHiddenEndRow < nRow)
4493 bHidden = maTabs[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
4494 if (nHeightEndRow < nRow)
4495 nHeight = maTabs[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
4497 if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
4498 ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
4499 (bStartHidden != bHidden) ||
4500 (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
4501 (!bCareManualSize && ((nStartHeight != nHeight))))
4502 return nRow;
4505 return MAXROW+1;
4508 bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
4510 bool bRet(false);
4511 nDefault = 0;
4512 ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
4513 SCCOL nColumn;
4514 SCROW nStartRow;
4515 SCROW nEndRow;
4516 const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4517 if (nEndRow < nLastRow)
4519 ScDefaultAttrSet aSet;
4520 ScDefaultAttrSet::iterator aItr = aSet.end();
4521 while (pAttr)
4523 ScDefaultAttr aAttr(pAttr);
4524 aItr = aSet.find(aAttr);
4525 if (aItr == aSet.end())
4527 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4528 aAttr.nFirst = nStartRow;
4529 aSet.insert(aAttr);
4531 else
4533 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4534 aAttr.nFirst = aItr->nFirst;
4535 aSet.erase(aItr);
4536 aSet.insert(aAttr);
4538 pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4540 ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
4541 aItr = aDefaultItr;
4542 ++aItr;
4543 while (aItr != aSet.end())
4545 // for entries with equal count, use the one with the lowest start row,
4546 // don't use the random order of pointer comparisons
4547 if ( aItr->nCount > aDefaultItr->nCount ||
4548 ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
4549 aDefaultItr = aItr;
4550 ++aItr;
4552 nDefault = aDefaultItr->nFirst;
4553 bRet = true;
4555 else
4556 bRet = true;
4557 return bRet;
4560 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4562 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4563 maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
4566 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4568 if ( ValidTab(nTab) && maTabs[nTab] )
4569 maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
4572 // Attribute ----------------------------------------------------------
4574 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
4576 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4578 const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
4579 if (pTemp)
4580 return pTemp;
4581 else
4583 OSL_FAIL( "Attribut Null" );
4586 return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
4589 const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich ) const
4591 return GetAttr(rPos.Col(), rPos.Row(), rPos.Tab(), nWhich);
4594 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4596 if (TableExists(nTab))
4597 return maTabs[nTab]->GetPattern( nCol, nRow );
4598 return NULL;
4601 const ScPatternAttr* ScDocument::GetPattern( const ScAddress& rPos ) const
4603 if (TableExists(rPos.Tab()))
4604 return maTabs[rPos.Tab()]->GetPattern(rPos.Col(), rPos.Row());
4606 return NULL;
4609 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
4611 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4612 return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
4613 return NULL;
4616 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
4618 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4619 maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
4622 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
4624 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4625 maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
4628 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
4629 SCCOL nEndCol, SCROW nEndRow,
4630 const ScMarkData& rMark,
4631 const ScPatternAttr& rAttr,
4632 ScEditDataArray* pDataArray )
4634 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4635 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4636 for (; itr != itrEnd && *itr < nMax; ++itr)
4637 if (maTabs[*itr])
4638 maTabs[*itr]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray );
4641 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
4642 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
4644 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4645 if (maTabs[nTab])
4646 maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
4649 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
4650 const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
4652 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4653 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4654 for (; itr != itrEnd && *itr < nMax; ++itr)
4655 if (maTabs[*itr])
4656 maTabs[*itr]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
4659 void ScDocument::AddCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4661 if(!(static_cast<size_t>(nTab) < maTabs.size()))
4662 return;
4664 if(!maTabs[nTab])
4665 return;
4667 maTabs[nTab]->AddCondFormatData(rRange, nIndex);
4670 void ScDocument::RemoveCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4672 if(!(static_cast<size_t>(nTab) < maTabs.size()))
4673 return;
4675 if(!maTabs[nTab])
4676 return;
4678 maTabs[nTab]->RemoveCondFormatData(rRange, nIndex);
4681 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
4683 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4684 if (maTabs[nTab])
4685 maTabs[nTab]->ApplyStyle( nCol, nRow, rStyle );
4688 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
4689 SCCOL nEndCol, SCROW nEndRow,
4690 const ScMarkData& rMark,
4691 const ScStyleSheet& rStyle)
4693 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4694 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4695 for (; itr != itrEnd && *itr < nMax; ++itr)
4696 if (maTabs[*itr])
4697 maTabs[*itr]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4700 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
4701 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
4703 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4704 if (maTabs[nTab])
4705 maTabs[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4708 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
4710 // ApplySelectionStyle needs multi mark
4711 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4713 ScRange aRange;
4714 rMark.GetMarkArea( aRange );
4715 ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
4716 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
4718 else
4720 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4721 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4722 for (; itr != itrEnd && *itr < nMax; ++itr)
4723 if ( maTabs[*itr] )
4724 maTabs[*itr]->ApplySelectionStyle( rStyle, rMark );
4728 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4729 const SvxBorderLine* pLine, bool bColorOnly )
4731 if ( bColorOnly && !pLine )
4732 return;
4734 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4735 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4736 for (; itr != itrEnd && *itr < nMax; ++itr)
4737 if (maTabs[*itr])
4738 maTabs[*itr]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4741 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4743 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4744 return maTabs[nTab]->GetStyle(nCol, nRow);
4745 else
4746 return NULL;
4749 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4751 bool bEqual = true;
4752 bool bFound;
4754 const ScStyleSheet* pStyle = NULL;
4755 const ScStyleSheet* pNewStyle;
4757 if ( rMark.IsMultiMarked() )
4759 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4760 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4761 for (; itr != itrEnd && *itr < nMax; ++itr)
4762 if (maTabs[*itr])
4764 pNewStyle = maTabs[*itr]->GetSelectionStyle( rMark, bFound );
4765 if (bFound)
4767 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4768 bEqual = false; // different
4769 pStyle = pNewStyle;
4773 if ( rMark.IsMarked() )
4775 ScRange aRange;
4776 rMark.GetMarkArea( aRange );
4777 for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual && i < static_cast<SCTAB>(maTabs.size()); i++)
4778 if (maTabs[i] && rMark.GetTableSelect(i))
4780 pNewStyle = maTabs[i]->GetAreaStyle( bFound,
4781 aRange.aStart.Col(), aRange.aStart.Row(),
4782 aRange.aEnd.Col(), aRange.aEnd.Row() );
4783 if (bFound)
4785 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4786 bEqual = false; // different
4787 pStyle = pNewStyle;
4792 return bEqual ? pStyle : NULL;
4795 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, bool bRemoved,
4796 OutputDevice* pDev,
4797 double nPPTX, double nPPTY,
4798 const Fraction& rZoomX, const Fraction& rZoomY )
4800 TableContainer::iterator it = maTabs.begin();
4801 for (; it != maTabs.end(); ++it)
4802 if (*it)
4803 (*it)->StyleSheetChanged
4804 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4806 if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4808 // update attributes for all note objects
4809 ScDetectiveFunc::UpdateAllComments( *this );
4813 bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
4815 if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4817 if ( bGatherAllStyles )
4819 SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4820 SFX_STYLE_FAMILY_PARA );
4821 for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4822 pStyle = aIter.Next() )
4824 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4825 if ( pScStyle )
4826 pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4830 bool bIsUsed = false;
4832 TableContainer::const_iterator it = maTabs.begin();
4833 for (; it != maTabs.end(); ++it)
4834 if (*it)
4836 if ( (*it)->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4838 if ( !bGatherAllStyles )
4839 return true;
4840 bIsUsed = true;
4844 if ( bGatherAllStyles )
4845 bStyleSheetUsageInvalid = false;
4847 return bIsUsed;
4850 return rStyle.GetUsage() == ScStyleSheet::USED;
4853 bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4854 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4856 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4857 if (maTabs[nTab])
4858 return maTabs[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4860 OSL_FAIL("ApplyFlags: wrong table");
4861 return false;
4864 bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4865 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4867 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4868 if (maTabs[nTab])
4869 return maTabs[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4871 OSL_FAIL("RemoveFlags: wrong table");
4872 return false;
4875 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4876 bool bPutToPool )
4878 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4879 if (maTabs[nTab])
4880 maTabs[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4883 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4884 bool bPutToPool )
4886 SCTAB nTab = rPos.Tab();
4887 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
4888 maTabs[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4891 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, bool bDeep )
4893 ScMergePatternState aState;
4895 if ( rMark.IsMultiMarked() ) // multi selection
4897 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4898 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4899 for (; itr != itrEnd && *itr < nMax; ++itr)
4900 if (maTabs[*itr])
4901 maTabs[*itr]->MergeSelectionPattern( aState, rMark, bDeep );
4903 if ( rMark.IsMarked() ) // single selection
4905 ScRange aRange;
4906 rMark.GetMarkArea(aRange);
4907 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4908 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4909 for (; itr != itrEnd && *itr < nMax; ++itr)
4910 if (maTabs[*itr])
4911 maTabs[*itr]->MergePatternArea( aState,
4912 aRange.aStart.Col(), aRange.aStart.Row(),
4913 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4916 OSL_ENSURE( aState.pItemSet, "SelectionPattern Null" );
4917 if (aState.pItemSet)
4918 return new ScPatternAttr( aState.pItemSet );
4919 else
4920 return new ScPatternAttr( GetPool() ); // empty
4923 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, bool bDeep )
4925 delete pSelectionAttr;
4926 pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4927 return pSelectionAttr;
4930 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4931 SvxBoxItem& rLineOuter,
4932 SvxBoxInfoItem& rLineInner )
4934 rLineOuter.SetLine(NULL, SvxBoxItemLine::TOP);
4935 rLineOuter.SetLine(NULL, SvxBoxItemLine::BOTTOM);
4936 rLineOuter.SetLine(NULL, SvxBoxItemLine::LEFT);
4937 rLineOuter.SetLine(NULL, SvxBoxItemLine::RIGHT);
4938 rLineOuter.SetDistance(0);
4940 rLineInner.SetLine(NULL, SvxBoxInfoItemLine::HORI);
4941 rLineInner.SetLine(NULL, SvxBoxInfoItemLine::VERT);
4942 rLineInner.SetTable(true);
4943 rLineInner.SetDist(true);
4944 rLineInner.SetMinDist(false);
4946 ScLineFlags aFlags;
4948 if (rMark.IsMarked())
4950 ScRange aRange;
4951 rMark.GetMarkArea(aRange);
4952 rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4953 rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4954 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4955 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4956 for (; itr != itrEnd && *itr < nMax; ++itr)
4957 if (maTabs[*itr])
4958 maTabs[*itr]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4959 aRange.aStart.Col(), aRange.aStart.Row(),
4960 aRange.aEnd.Col(), aRange.aEnd.Row() );
4963 // Evaluate don't care Status
4965 rLineInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4966 rLineInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
4967 rLineInner.SetValid( SvxBoxInfoItemValidFlags::TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
4968 rLineInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4969 rLineInner.SetValid( SvxBoxInfoItemValidFlags::HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
4970 rLineInner.SetValid( SvxBoxInfoItemValidFlags::VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
4973 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4974 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask ) const
4976 if ( nMask & HASATTR_ROTATE )
4978 // Is attribute used in document?
4979 // (as in fillinfo)
4981 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4983 bool bAnyItem = false;
4984 sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4985 for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4987 const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4988 if ( pItem )
4990 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4991 // (see ScPatternAttr::GetCellOrientation)
4992 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4993 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4995 bAnyItem = true;
4996 break;
5000 if (!bAnyItem)
5001 nMask &= ~HASATTR_ROTATE;
5004 if ( nMask & HASATTR_RTL )
5006 // first check if right-to left is in the pool at all
5007 // (the same item is used in cell and page format)
5009 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5011 bool bHasRtl = false;
5012 sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
5013 for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
5015 const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
5016 if ( pItem && static_cast<const SvxFrameDirectionItem*>(pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
5018 bHasRtl = true;
5019 break;
5022 if (!bHasRtl)
5023 nMask &= ~HASATTR_RTL;
5026 if (!nMask)
5027 return false;
5029 bool bFound = false;
5030 for (SCTAB i=nTab1; i<=nTab2 && !bFound && i < static_cast<SCTAB>(maTabs.size()); i++)
5031 if (maTabs[i])
5033 if ( nMask & HASATTR_RTL )
5035 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
5036 bFound = true;
5038 if ( nMask & HASATTR_RIGHTORCENTER )
5040 // On a RTL sheet, don't start to look for the default left value
5041 // (which is then logically right), instead always assume true.
5042 // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
5044 if ( IsLayoutRTL(i) )
5045 bFound = true;
5048 if ( !bFound )
5049 bFound = maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
5052 return bFound;
5055 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask ) const
5057 return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
5058 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
5059 nMask );
5062 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
5063 SCCOL nX1, SCCOL nX2 ) const
5065 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5066 maTabs[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
5067 else
5069 OSL_FAIL("FindMaxRotCol: wrong table");
5073 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
5074 const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
5075 const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
5077 //TODO: consider page limits for printing !!!!!
5079 const SvxBoxItem* pThisAttr = static_cast<const SvxBoxItem*>( GetEffItem( nCol, nRow, nTab, ATTR_BORDER ) );
5080 OSL_ENSURE(pThisAttr,"where is the attribute?");
5082 const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
5083 const SvxBorderLine* pTopLine = pThisAttr->GetTop();
5084 const SvxBorderLine* pRightLine = pThisAttr->GetRight();
5085 const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
5087 if ( nCol > 0 )
5089 const SvxBorderLine* pOther = static_cast<const SvxBoxItem*>(
5090 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
5091 if ( ScHasPriority( pOther, pLeftLine ) )
5092 pLeftLine = pOther;
5094 if ( nRow > 0 )
5096 const SvxBorderLine* pOther = static_cast<const SvxBoxItem*>(
5097 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
5098 if ( ScHasPriority( pOther, pTopLine ) )
5099 pTopLine = pOther;
5101 if ( nCol < MAXCOL )
5103 const SvxBorderLine* pOther = static_cast<const SvxBoxItem*>(
5104 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
5105 if ( ScHasPriority( pOther, pRightLine ) )
5106 pRightLine = pOther;
5108 if ( nRow < MAXROW )
5110 const SvxBorderLine* pOther = static_cast<const SvxBoxItem*>(
5111 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
5112 if ( ScHasPriority( pOther, pBottomLine ) )
5113 pBottomLine = pOther;
5116 if (ppLeft)
5117 *ppLeft = pLeftLine;
5118 if (ppTop)
5119 *ppTop = pTopLine;
5120 if (ppRight)
5121 *ppRight = pRightLine;
5122 if (ppBottom)
5123 *ppBottom = pBottomLine;
5126 bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5127 SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
5129 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5130 if (maTabs[nTab])
5131 return maTabs[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
5133 OSL_FAIL("wrong table number");
5134 return false;
5137 void ScDocument::LockTable(SCTAB nTab)
5139 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5140 maTabs[nTab]->LockTable();
5141 else
5143 OSL_FAIL("wrong table number");
5147 void ScDocument::UnlockTable(SCTAB nTab)
5149 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5150 maTabs[nTab]->UnlockTable();
5151 else
5153 OSL_FAIL("wrong table number");
5157 bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5158 SCCOL nEndCol, SCROW nEndRow,
5159 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
5161 // import into read-only document is possible
5162 if (!bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly())
5164 if ( pOnlyNotBecauseOfMatrix )
5165 *pOnlyNotBecauseOfMatrix = false;
5166 return false;
5169 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5170 if (maTabs[nTab])
5171 return maTabs[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
5172 nEndRow, pOnlyNotBecauseOfMatrix );
5174 OSL_FAIL("wrong table number");
5175 if ( pOnlyNotBecauseOfMatrix )
5176 *pOnlyNotBecauseOfMatrix = false;
5177 return false;
5180 bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
5181 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
5183 // import into read-only document is possible
5184 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
5186 if ( pOnlyNotBecauseOfMatrix )
5187 *pOnlyNotBecauseOfMatrix = false;
5188 return false;
5191 ScRange aRange;
5192 rMark.GetMarkArea(aRange);
5194 bool bOk = true;
5195 bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
5196 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5197 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5198 for (; itr != itrEnd && *itr < nMax && (bOk || bMatrix); ++itr)
5200 if ( maTabs[*itr] )
5202 if (rMark.IsMarked())
5204 if ( !maTabs[*itr]->IsBlockEditable( aRange.aStart.Col(),
5205 aRange.aStart.Row(), aRange.aEnd.Col(),
5206 aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
5208 bOk = false;
5209 if ( pOnlyNotBecauseOfMatrix )
5210 bMatrix = *pOnlyNotBecauseOfMatrix;
5213 if (rMark.IsMultiMarked())
5215 if ( !maTabs[*itr]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
5217 bOk = false;
5218 if ( pOnlyNotBecauseOfMatrix )
5219 bMatrix = *pOnlyNotBecauseOfMatrix;
5225 if ( pOnlyNotBecauseOfMatrix )
5226 *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
5228 return bOk;
5231 bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
5232 SCCOL nEndCol, SCROW nEndRow,
5233 const ScMarkData& rMark ) const
5235 bool bOk = true;
5236 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5237 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5238 for (; itr != itrEnd && *itr < nMax && bOk; ++itr)
5239 if (maTabs[*itr])
5240 if (maTabs[*itr]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
5241 bOk = false;
5243 return !bOk;
5246 bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
5248 // if rCell is part of a matrix formula, return its complete range
5250 ScFormulaCell* pFCell = GetFormulaCell(rCellPos);
5251 if (!pFCell)
5252 // not a formula cell. Bail out.
5253 return false;
5255 ScAddress aOrigin = rCellPos;
5256 if (!pFCell->GetMatrixOrigin(aOrigin))
5257 // Failed to get the address of the matrix origin.
5258 return false;
5260 if (aOrigin != rCellPos)
5262 pFCell = GetFormulaCell(aOrigin);
5263 if (!pFCell)
5264 // The matrix origin cell is not a formula cell !? Something is up...
5265 return false;
5268 SCCOL nSizeX;
5269 SCROW nSizeY;
5270 pFCell->GetMatColsRows(nSizeX, nSizeY);
5271 if (nSizeX <= 0 || nSizeY <= 0)
5273 // GetMatrixEdge computes also dimensions of the matrix
5274 // if not already done (may occur if document is loaded
5275 // from old file format).
5276 // Needs an "invalid" initialized address.
5277 aOrigin.SetInvalid();
5278 pFCell->GetMatrixEdge(aOrigin);
5279 pFCell->GetMatColsRows(nSizeX, nSizeY);
5282 if (nSizeX <= 0 || nSizeY <= 0)
5283 // Matrix size is still invalid. Give up.
5284 return false;
5286 ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
5287 aOrigin.Row() + nSizeY - 1,
5288 aOrigin.Tab() );
5290 rMatrix.aStart = aOrigin;
5291 rMatrix.aEnd = aEnd;
5293 return true;
5296 bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
5297 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab ) const
5299 bool bFound = false;
5300 if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
5302 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5304 SCCOL nCol;
5305 SCCOL nOldCol = rStartCol;
5306 SCROW nOldRow = rStartRow;
5307 for (nCol=nOldCol; nCol<=nEndCol; nCol++)
5308 while (static_cast<const ScMergeFlagAttr*>(GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
5309 IsVerOverlapped())
5310 --rStartRow;
5312 //TODO: pass on ?
5314 ScAttrArray* pAttrArray = maTabs[nTab]->aCol[nOldCol].pAttrArray;
5315 SCSIZE nIndex;
5316 pAttrArray->Search( nOldRow, nIndex );
5317 SCROW nAttrPos = nOldRow;
5318 while (nAttrPos<=nEndRow)
5320 OSL_ENSURE( nIndex < pAttrArray->nCount, "Wrong index in AttrArray" );
5322 if (static_cast<const ScMergeFlagAttr&>(pAttrArray->pData[nIndex].pPattern->
5323 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
5325 SCROW nLoopEndRow = std::min( nEndRow, pAttrArray->pData[nIndex].nRow );
5326 for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
5328 SCCOL nTempCol = nOldCol;
5330 --nTempCol;
5331 while (static_cast<const ScMergeFlagAttr*>(GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
5332 ->IsHorOverlapped());
5333 if (nTempCol < rStartCol)
5334 rStartCol = nTempCol;
5337 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
5338 ++nIndex;
5342 else
5344 OSL_FAIL("ExtendOverlapped: invalid range");
5347 return bFound;
5350 bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
5351 SCCOL& rEndCol, SCROW& rEndRow,
5352 const ScMarkData& rMark, bool bRefresh )
5354 // use all selected sheets from rMark
5356 bool bFound = false;
5357 SCCOL nOldEndCol = rEndCol;
5358 SCROW nOldEndRow = rEndRow;
5360 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5361 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5362 for (; itr != itrEnd && *itr < nMax; ++itr)
5363 if ( maTabs[*itr] )
5365 SCCOL nThisEndCol = nOldEndCol;
5366 SCROW nThisEndRow = nOldEndRow;
5367 if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, *itr, bRefresh ) )
5368 bFound = true;
5369 if ( nThisEndCol > rEndCol )
5370 rEndCol = nThisEndCol;
5371 if ( nThisEndRow > rEndRow )
5372 rEndRow = nThisEndRow;
5375 return bFound;
5378 bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
5379 SCCOL& rEndCol, SCROW& rEndRow,
5380 SCTAB nTab, bool bRefresh )
5382 bool bFound = false;
5383 if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
5385 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5386 bFound = maTabs[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
5388 if (bRefresh)
5389 RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
5391 else
5393 OSL_FAIL("ExtendMerge: invalid range");
5396 return bFound;
5399 bool ScDocument::ExtendMerge( ScRange& rRange, bool bRefresh )
5401 bool bFound = false;
5402 SCTAB nStartTab = rRange.aStart.Tab();
5403 SCTAB nEndTab = rRange.aEnd.Tab();
5404 SCCOL nEndCol = rRange.aEnd.Col();
5405 SCROW nEndRow = rRange.aEnd.Row();
5407 PutInOrder( nStartTab, nEndTab );
5408 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5410 SCCOL nExtendCol = rRange.aEnd.Col();
5411 SCROW nExtendRow = rRange.aEnd.Row();
5412 if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
5413 nExtendCol, nExtendRow,
5414 nTab, bRefresh ) )
5416 bFound = true;
5417 if (nExtendCol > nEndCol) nEndCol = nExtendCol;
5418 if (nExtendRow > nEndRow) nEndRow = nExtendRow;
5422 rRange.aEnd.SetCol(nEndCol);
5423 rRange.aEnd.SetRow(nEndRow);
5425 return bFound;
5428 bool ScDocument::ExtendTotalMerge( ScRange& rRange ) const
5430 // Extend range to merged cells without including any new non-overlapped cells
5431 bool bRet = false;
5432 ScRange aExt = rRange;
5433 // ExtendMerge() is non-const, but called withouth refresh.
5434 if (const_cast<ScDocument*>(this)->ExtendMerge( aExt, false))
5436 if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
5438 ScRange aTest = aExt;
5439 aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
5440 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
5441 aExt.aEnd.SetRow(rRange.aEnd.Row());
5443 if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
5445 ScRange aTest = aExt;
5446 aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
5447 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
5448 aExt.aEnd.SetCol(rRange.aEnd.Col());
5451 bRet = ( aExt.aEnd != rRange.aEnd );
5452 rRange = aExt;
5454 return bRet;
5457 bool ScDocument::ExtendOverlapped( ScRange& rRange ) const
5459 bool bFound = false;
5460 SCTAB nStartTab = rRange.aStart.Tab();
5461 SCTAB nEndTab = rRange.aEnd.Tab();
5462 SCCOL nStartCol = rRange.aStart.Col();
5463 SCROW nStartRow = rRange.aStart.Row();
5465 PutInOrder( nStartTab, nEndTab );
5466 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5468 SCCOL nExtendCol = rRange.aStart.Col();
5469 SCROW nExtendRow = rRange.aStart.Row();
5470 ExtendOverlapped( nExtendCol, nExtendRow,
5471 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
5472 if (nExtendCol < nStartCol)
5474 nStartCol = nExtendCol;
5475 bFound = true;
5477 if (nExtendRow < nStartRow)
5479 nStartRow = nExtendRow;
5480 bFound = true;
5484 rRange.aStart.SetCol(nStartCol);
5485 rRange.aStart.SetRow(nStartRow);
5487 return bFound;
5490 bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
5491 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
5493 SCTAB nDBTab;
5494 SCCOL nDBStartCol;
5495 SCROW nDBStartRow;
5496 SCCOL nDBEndCol;
5497 SCROW nDBEndRow;
5499 // Delete Autofilter
5501 bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
5503 // Set Autofilter
5505 const ScDBData* pData = NULL;
5506 ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
5507 ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(), itrEnd = rDBs.end();
5508 for (; itr != itrEnd; ++itr)
5510 if (itr->HasAutoFilter())
5512 itr->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
5513 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5514 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5516 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5517 nDBTab, SC_MF_AUTO ))
5518 bChange = true;
5522 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5523 pData = maTabs[nTab]->GetAnonymousDBData();
5524 else
5525 pData=NULL;
5526 if (pData)
5528 if (pData->HasAutoFilter())
5530 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
5531 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5532 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5534 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5535 nDBTab, SC_MF_AUTO ))
5536 bChange = true;
5540 return bChange;
5543 void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
5545 while (IsHorOverlapped(rCol, rRow, nTab))
5546 --rCol;
5547 while (IsVerOverlapped(rCol, rRow, nTab))
5548 --rRow;
5551 bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5553 const ScMergeFlagAttr* pAttr = static_cast<const ScMergeFlagAttr*>(
5554 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ));
5555 if (pAttr)
5556 return pAttr->IsHorOverlapped();
5557 else
5559 OSL_FAIL("Overlapped: Attr==0");
5560 return false;
5564 bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5566 const ScMergeFlagAttr* pAttr = static_cast<const ScMergeFlagAttr*>(
5567 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ));
5568 if (pAttr)
5569 return pAttr->IsVerOverlapped();
5570 else
5572 OSL_FAIL("Overlapped: Attr==0");
5573 return false;
5577 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
5578 const SvxBoxItem* pLineOuter,
5579 const SvxBoxInfoItem* pLineInner )
5581 ScRangeList aRangeList;
5582 rMark.FillRangeListWithMarks( &aRangeList, false );
5583 size_t nRangeCount = aRangeList.size();
5584 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5585 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5586 for (; itr != itrEnd && *itr < nMax; ++itr)
5588 if (maTabs[*itr])
5590 for ( size_t j=0; j < nRangeCount; j++ )
5592 ScRange aRange = *aRangeList[ j ];
5593 maTabs[*itr]->ApplyBlockFrame( pLineOuter, pLineInner,
5594 aRange.aStart.Col(), aRange.aStart.Row(),
5595 aRange.aEnd.Col(), aRange.aEnd.Row() );
5601 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
5602 const SvxBoxItem* pLineOuter,
5603 const SvxBoxInfoItem* pLineInner )
5605 SCTAB nStartTab = rRange.aStart.Tab();
5606 SCTAB nEndTab = rRange.aStart.Tab();
5607 for (SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
5608 if (maTabs[nTab])
5609 maTabs[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
5610 rRange.aStart.Col(), rRange.aStart.Row(),
5611 rRange.aEnd.Col(), rRange.aEnd.Row() );
5614 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark, ScEditDataArray* pDataArray )
5616 const SfxItemSet* pSet = &rAttr.GetItemSet();
5617 bool bSet = false;
5618 sal_uInt16 i;
5619 for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
5620 if (pSet->GetItemState(i) == SfxItemState::SET)
5621 bSet = true;
5623 if (bSet)
5625 // ApplySelectionCache needs multi mark
5626 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
5628 ScRange aRange;
5629 rMark.GetMarkArea( aRange );
5630 ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
5631 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray );
5633 else
5635 SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
5636 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5637 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5638 for (; itr != itrEnd && *itr < nMax; ++itr)
5639 if (maTabs[*itr])
5640 maTabs[*itr]->ApplySelectionCache( &aCache, rMark, pDataArray );
5645 void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
5647 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5648 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5649 for (; itr != itrEnd && *itr < nMax; ++itr)
5650 if (maTabs[*itr])
5651 maTabs[*itr]->ChangeSelectionIndent( bIncrement, rMark );
5654 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
5656 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5657 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5658 for (; itr != itrEnd && *itr < nMax; ++itr)
5659 if (maTabs[*itr])
5660 maTabs[*itr]->ClearSelectionItems( pWhich, rMark );
5663 void ScDocument::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
5665 sc::AutoCalcSwitch aACSwitch(*this, false);
5667 std::vector<ScAddress> aGroupPos;
5668 // Destroy and reconstruct listeners only if content is affected.
5669 bool bDelContent = ((nDelFlag & ~IDF_CONTENTS) != nDelFlag);
5670 if (bDelContent)
5672 // Record the positions of top and/or bottom formula groups that
5673 // intersect the area borders.
5674 sc::EndListeningContext aCxt(*this);
5675 ScRangeList aRangeList;
5676 rMark.FillRangeListWithMarks( &aRangeList, false);
5677 for (size_t i = 0; i < aRangeList.size(); ++i)
5679 const ScRange* pRange = aRangeList[i];
5680 if (pRange)
5681 EndListeningIntersectedGroups( aCxt, *pRange, &aGroupPos);
5683 aCxt.purgeEmptyBroadcasters();
5686 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5687 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5688 for (; itr != itrEnd && *itr < nMax; ++itr)
5689 if (maTabs[*itr])
5690 maTabs[*itr]->DeleteSelection(nDelFlag, rMark, bBroadcast);
5692 if (bDelContent)
5694 // Re-start listeners on those top bottom groups that have been split.
5695 SetNeedsListeningGroups(aGroupPos);
5696 StartNeededListeners();
5700 void ScDocument::DeleteSelectionTab(
5701 SCTAB nTab, InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
5703 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5705 sc::AutoCalcSwitch aACSwitch(*this, false);
5707 std::vector<ScAddress> aGroupPos;
5708 // Destroy and reconstruct listeners only if content is affected.
5709 bool bDelContent = ((nDelFlag & ~IDF_CONTENTS) != nDelFlag);
5710 if (bDelContent)
5712 // Record the positions of top and/or bottom formula groups that
5713 // intersect the area borders.
5714 sc::EndListeningContext aCxt(*this);
5715 ScRangeList aRangeList;
5716 rMark.FillRangeListWithMarks( &aRangeList, false);
5717 for (size_t i = 0; i < aRangeList.size(); ++i)
5719 const ScRange* pRange = aRangeList[i];
5720 if (pRange && pRange->aStart.Tab() <= nTab && nTab <= pRange->aEnd.Tab())
5722 ScRange aRange( *pRange);
5723 aRange.aStart.SetTab( nTab);
5724 aRange.aEnd.SetTab( nTab);
5725 EndListeningIntersectedGroups( aCxt, aRange, &aGroupPos);
5728 aCxt.purgeEmptyBroadcasters();
5731 maTabs[nTab]->DeleteSelection(nDelFlag, rMark, bBroadcast);
5733 if (bDelContent)
5735 // Re-start listeners on those top bottom groups that have been split.
5736 SetNeedsListeningGroups(aGroupPos);
5737 StartNeededListeners();
5740 else
5742 OSL_FAIL("wrong table");
5746 ScPatternAttr* ScDocument::GetDefPattern() const
5748 return const_cast<ScPatternAttr*>(static_cast<const ScPatternAttr*>(&xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN)));
5751 ScDocumentPool* ScDocument::GetPool()
5753 return xPoolHelper->GetDocPool();
5756 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
5758 return xPoolHelper->GetStylePool();
5761 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
5762 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
5764 PutInOrder(nStartCol, nEndCol);
5765 PutInOrder(nStartRow, nEndRow);
5766 PutInOrder(nStartTab, nEndTab);
5767 if (ValidTab(nStartTab) && nStartTab < static_cast<SCTAB>(maTabs.size()))
5769 if (maTabs[nStartTab])
5770 return maTabs[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
5771 else
5772 return 0;
5774 else
5775 return 0;
5778 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, ScMoveDirection eDirection ) const
5780 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5781 maTabs[nTab]->FindAreaPos( rCol, rRow, eDirection );
5784 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
5785 bool bMarked, bool bUnprotected, const ScMarkData& rMark ) const
5787 OSL_ENSURE( !nMovX || !nMovY, "GetNextPos: only X or Y" );
5789 ScMarkData aCopyMark = rMark;
5790 aCopyMark.SetMarking(false);
5791 aCopyMark.MarkToMulti();
5793 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5794 maTabs[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
5797 // Data operations
5799 void ScDocument::UpdStlShtPtrsFrmNms()
5801 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5803 sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5804 ScPatternAttr* pPattern;
5805 for (sal_uInt32 i=0; i<nCount; i++)
5807 pPattern = const_cast<ScPatternAttr*>(static_cast<const ScPatternAttr*>(pPool->GetItem2(ATTR_PATTERN, i)));
5808 if (pPattern)
5809 pPattern->UpdateStyleSheet(this);
5811 const_cast<ScPatternAttr&>(static_cast<const ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN))).UpdateStyleSheet(this);
5814 void ScDocument::StylesToNames()
5816 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5818 sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5819 ScPatternAttr* pPattern;
5820 for (sal_uInt32 i=0; i<nCount; i++)
5822 pPattern = const_cast<ScPatternAttr*>(static_cast<const ScPatternAttr*>(pPool->GetItem2(ATTR_PATTERN, i)));
5823 if (pPattern)
5824 pPattern->StyleToName();
5826 const_cast<ScPatternAttr&>(static_cast<const ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN))).StyleToName();
5829 sal_uLong ScDocument::GetCellCount() const
5831 sal_uLong nCellCount = 0L;
5833 TableContainer::const_iterator it = maTabs.begin();
5834 for (; it != maTabs.end(); ++it)
5835 if ( *it )
5836 nCellCount += (*it)->GetCellCount();
5838 return nCellCount;
5841 sal_uLong ScDocument::GetCodeCount() const
5843 sal_uLong nCodeCount = 0;
5845 TableContainer::const_iterator it = maTabs.begin();
5846 for (; it != maTabs.end(); ++it)
5847 if ( *it )
5848 nCodeCount += (*it)->GetCodeCount();
5850 return nCodeCount;
5853 void ScDocument::PageStyleModified( SCTAB nTab, const OUString& rNewName )
5855 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5856 maTabs[nTab]->PageStyleModified( rNewName );
5859 void ScDocument::SetPageStyle( SCTAB nTab, const OUString& rName )
5861 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5862 maTabs[nTab]->SetPageStyle( rName );
5865 const OUString ScDocument::GetPageStyle( SCTAB nTab ) const
5867 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5868 return maTabs[nTab]->GetPageStyle();
5870 return OUString();
5873 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5875 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5876 maTabs[nTab]->SetPageSize( rSize );
5879 Size ScDocument::GetPageSize( SCTAB nTab ) const
5881 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5882 return maTabs[nTab]->GetPageSize();
5884 OSL_FAIL("invalid tab");
5885 return Size();
5888 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5890 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5891 maTabs[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5894 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5896 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5897 maTabs[nTab]->InvalidatePageBreaks();
5900 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5902 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5903 maTabs[nTab]->UpdatePageBreaks( pUserArea );
5906 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5908 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5909 maTabs[nTab]->RemoveManualBreaks();
5912 bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5914 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5915 return maTabs[nTab]->HasManualBreaks();
5917 OSL_FAIL("invalid tab");
5918 return false;
5921 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5923 rDocStat.nTableCount = GetTableCount();
5924 rDocStat.aDocName = aDocName;
5925 rDocStat.nCellCount = GetCellCount();
5928 bool ScDocument::HasPrintRange()
5930 bool bResult = false;
5932 TableContainer::iterator it = maTabs.begin();
5933 for (; it != maTabs.end() && !bResult; ++it)
5934 if ( *it )
5935 bResult = (*it)->IsPrintEntireSheet() || ((*it)->GetPrintRangeCount() > 0);
5937 return bResult;
5940 bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5942 return (ValidTab(nTab) ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsPrintEntireSheet();
5945 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5947 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5948 return maTabs[nTab]->GetPrintRangeCount();
5950 return 0;
5953 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5955 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5956 return maTabs[nTab]->GetPrintRange(nPos);
5958 return NULL;
5961 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5963 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5964 return maTabs[nTab]->GetRepeatColRange();
5966 return NULL;
5969 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5971 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5972 return maTabs[nTab]->GetRepeatRowRange();
5974 return NULL;
5977 void ScDocument::ClearPrintRanges( SCTAB nTab )
5979 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5980 maTabs[nTab]->ClearPrintRanges();
5983 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5985 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5986 maTabs[nTab]->AddPrintRange( rNew );
5989 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5991 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5992 maTabs[nTab]->SetPrintEntireSheet();
5995 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5997 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5998 maTabs[nTab]->SetRepeatColRange( pNew );
6001 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
6003 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6004 maTabs[nTab]->SetRepeatRowRange( pNew );
6007 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
6009 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
6010 ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
6011 for (SCTAB i=0; i<nCount; i++)
6012 if (maTabs[i])
6013 maTabs[i]->FillPrintSaver( pNew->GetTabData(i) );
6014 return pNew;
6017 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
6019 SCTAB nCount = rSaver.GetTabCount();
6020 for (SCTAB i=0; i<nCount && i < static_cast<SCTAB>(maTabs.size()); i++)
6021 if (maTabs[i])
6022 maTabs[i]->RestorePrintRanges( rSaver.GetTabData(i) );
6025 bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
6027 // The page number count restarts at a sheet, if another template is set at
6028 // the preseding one (oly compare names) and if a pagenumber is specified (not 0)
6030 if ( nTab + 1 < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab+1] )
6032 OUString aNew = maTabs[nTab+1]->GetPageStyle();
6033 if ( aNew != maTabs[nTab]->GetPageStyle() )
6035 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
6036 if ( pStyle )
6038 const SfxItemSet& rSet = pStyle->GetItemSet();
6039 sal_uInt16 nFirst = static_cast<const SfxUInt16Item&>(rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
6040 if ( nFirst != 0 )
6041 return true; // Specify page number in new template
6046 return false; // otherwise not
6049 SfxUndoManager* ScDocument::GetUndoManager()
6051 if (!mpUndoManager)
6053 // to support enhanced text edit for draw objects, use an SdrUndoManager
6054 mpUndoManager = new SdrUndoManager;
6057 return mpUndoManager;
6060 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
6062 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6063 return new ScRowBreakIterator(maTabs[nTab]->maRowPageBreaks);
6064 return NULL;
6067 void ScDocument::AddSubTotalCell(ScFormulaCell* pCell)
6069 maSubTotalCells.insert(pCell);
6072 void ScDocument::RemoveSubTotalCell(ScFormulaCell* pCell)
6074 maSubTotalCells.erase(pCell);
6077 namespace {
6079 bool lcl_hasDirtyRange(ScFormulaCell* pCell, const ScRange& rDirtyRange)
6081 ScDetectiveRefIter aRefIter(pCell);
6082 ScRange aRange;
6083 while (aRefIter.GetNextRef(aRange))
6085 if (aRange.Intersects(rDirtyRange))
6086 return true;
6088 return false;
6093 void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
6095 // to update the list by skipping cells that no longer contain subtotal function.
6096 set<ScFormulaCell*> aNewSet;
6098 bool bOldRecalc = GetAutoCalc();
6099 SetAutoCalc(false);
6100 set<ScFormulaCell*>::iterator itr = maSubTotalCells.begin(), itrEnd = maSubTotalCells.end();
6101 for (; itr != itrEnd; ++itr)
6103 ScFormulaCell* pCell = *itr;
6104 if (pCell->IsSubTotal())
6106 aNewSet.insert(pCell);
6107 if (lcl_hasDirtyRange(pCell, rDirtyRange))
6108 pCell->SetDirty();
6112 SetAutoCalc(bOldRecalc);
6113 maSubTotalCells.swap(aNewSet); // update the list.
6116 sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const
6118 SCTAB nTab = rPos.Tab();
6119 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6120 return maTabs[nTab]->GetTextWidth(rPos.Col(), rPos.Row());
6122 return 0;
6125 SvtScriptType ScDocument::GetScriptType( const ScAddress& rPos ) const
6127 SCTAB nTab = rPos.Tab();
6128 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6129 return maTabs[nTab]->GetScriptType(rPos.Col(), rPos.Row());
6131 return SvtScriptType::NONE;
6134 void ScDocument::SetScriptType( const ScAddress& rPos, SvtScriptType nType )
6136 SCTAB nTab = rPos.Tab();
6137 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6138 maTabs[nTab]->SetScriptType(rPos.Col(), rPos.Row(), nType);
6141 void ScDocument::EnableUndo( bool bVal )
6143 // The undo manager increases lock count every time undo is disabled.
6144 // Because of this, we shouldn't disable undo unless it's currently
6145 // enabled, or else re-enabling it may not actually re-enable undo unless
6146 // the lock count becomes zero.
6148 if (bVal != GetUndoManager()->IsUndoEnabled())
6150 GetUndoManager()->EnableUndo(bVal);
6151 if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
6154 mbUndoEnabled = bVal;
6157 void ScDocument::EnableUserInteraction( bool bVal )
6159 mbUserInteractionEnabled = bVal;
6162 bool ScDocument::IsInVBAMode() const
6164 if (!pShell)
6165 return false;
6169 uno::Reference<script::vba::XVBACompatibility> xVBA(
6170 pShell->GetBasicContainer(), uno::UNO_QUERY);
6172 return xVBA.is() && xVBA->getVBACompatibilityMode();
6174 catch (const lang::NotInitializedException&) {}
6176 return false;
6179 ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
6181 return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
6184 ScPostIt* ScDocument::GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
6186 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
6187 return maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
6188 else
6189 return NULL;
6193 void ScDocument::SetNote(const ScAddress& rPos, ScPostIt* pNote)
6195 return SetNote(rPos.Col(), rPos.Row(), rPos.Tab(), pNote);
6198 void ScDocument::SetNote(SCCOL nCol, SCROW nRow, SCTAB nTab, ScPostIt* pNote)
6200 return maTabs[nTab]->aCol[nCol].SetCellNote(nRow, pNote);
6203 bool ScDocument::HasNote(const ScAddress& rPos) const
6205 return HasNote(rPos.Col(), rPos.Row(), rPos.Tab());
6208 bool ScDocument::HasNote(SCCOL nCol, SCROW nRow, SCTAB nTab) const
6210 if (!ValidColRow(nCol, nRow))
6211 return false;
6213 const ScTable* pTab = FetchTable(nTab);
6214 if (!pTab)
6215 return false;
6217 const ScPostIt* pNote = pTab->aCol[nCol].GetCellNote(nRow);
6218 return pNote != NULL;
6221 bool ScDocument::HasColNotes(SCCOL nCol, SCTAB nTab) const
6223 if (!ValidCol(nCol))
6224 return false;
6226 const ScTable* pTab = FetchTable(nTab);
6227 if (!pTab)
6228 return false;
6230 return pTab->aCol[nCol].HasCellNotes();
6233 bool ScDocument::HasTabNotes(SCTAB nTab) const
6235 bool hasNotes = false;
6236 for (SCCOL nCol=0; nCol<MAXCOLCOUNT && !hasNotes; ++nCol)
6237 hasNotes = HasColNotes(nCol, nTab);
6239 return hasNotes;
6242 bool ScDocument::HasNotes() const
6244 for (SCTAB i = 0; i <= MAXTAB; ++i)
6246 if (HasTabNotes(i))
6247 return true;
6249 return false;
6252 ScPostIt* ScDocument::ReleaseNote(const ScAddress& rPos)
6254 ScTable* pTab = FetchTable(rPos.Tab());
6255 if (!pTab)
6256 return NULL;
6258 return pTab->ReleaseNote(rPos.Col(), rPos.Row());
6261 ScPostIt* ScDocument::GetOrCreateNote(const ScAddress& rPos)
6263 if (HasNote(rPos))
6264 return GetNote(rPos);
6265 else
6266 return CreateNote(rPos);
6268 ScPostIt* ScDocument::CreateNote(const ScAddress& rPos)
6270 ScPostIt* pPostIt = new ScPostIt(*this, rPos, false);
6271 SetNote(rPos, pPostIt);
6272 return pPostIt;
6275 size_t ScDocument::GetNoteCount( SCTAB nTab, SCCOL nCol ) const
6277 const ScTable* pTab = FetchTable(nTab);
6278 if (!pTab)
6279 return 0;
6281 return pTab->GetNoteCount(nCol);
6284 void ScDocument::CreateAllNoteCaptions()
6286 TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
6287 for (; it != itEnd; ++it)
6289 ScTable* p = *it;
6290 if (p)
6291 p->CreateAllNoteCaptions();
6295 void ScDocument::ForgetNoteCaptions( const ScRangeList& rRanges )
6297 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
6299 const ScRange* p = rRanges[i];
6300 const ScAddress& s = p->aStart;
6301 const ScAddress& e = p->aEnd;
6302 for (SCTAB nTab = s.Tab(); nTab <= e.Tab(); ++nTab)
6304 ScTable* pTab = FetchTable(nTab);
6305 if (!pTab)
6306 continue;
6308 pTab->ForgetNoteCaptions(s.Col(), s.Row(), e.Col(), e.Row());
6313 ScAddress ScDocument::GetNotePosition( size_t nIndex ) const
6315 for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
6317 for (SCCOL nCol=0; nCol<MAXCOLCOUNT; nCol++)
6319 size_t nColNoteCount = GetNoteCount(nTab, nCol);
6320 if (!nColNoteCount)
6321 continue;
6323 if (nIndex >= nColNoteCount)
6325 nIndex -= nColNoteCount;
6326 continue;
6329 SCROW nRow = GetNotePosition(nTab, nCol, nIndex);
6330 if (nRow >= 0)
6331 return ScAddress(nCol, nRow, nTab);
6333 OSL_FAIL("note not found");
6334 return ScAddress(ScAddress::INITIALIZE_INVALID);
6338 OSL_FAIL("note not found");
6339 return ScAddress(ScAddress::INITIALIZE_INVALID);
6342 ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
6344 for (SCCOL nCol=0; nCol<MAXCOLCOUNT; nCol++)
6346 size_t nColNoteCount = GetNoteCount(nTab, nCol);
6347 if (!nColNoteCount)
6348 continue;
6350 if (nIndex >= nColNoteCount)
6352 nIndex -= nColNoteCount;
6353 continue;
6356 SCROW nRow = GetNotePosition(nTab, nCol, nIndex);
6357 if (nRow >= 0)
6358 return ScAddress(nCol, nRow, nTab);
6360 OSL_FAIL("note not found");
6361 return ScAddress(ScAddress::INITIALIZE_INVALID);
6364 OSL_FAIL("note not found");
6365 return ScAddress(ScAddress::INITIALIZE_INVALID);
6368 SCROW ScDocument::GetNotePosition( SCTAB nTab, SCCOL nCol, size_t nIndex ) const
6370 const ScTable* pTab = FetchTable(nTab);
6371 if (!pTab)
6372 return -1;
6374 return pTab->GetNotePosition(nCol, nIndex);
6377 void ScDocument::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
6379 for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
6381 const ScTable* pTab = maTabs[nTab];
6382 if (!pTab)
6383 continue;
6385 pTab->GetAllNoteEntries(rNotes);
6389 void ScDocument::GetNotesInRange( const ScRangeList& rRange, std::vector<sc::NoteEntry>& rNotes ) const
6391 for( size_t i = 0; i < rRange.size(); ++i)
6393 const ScRange* pRange = rRange[i];
6394 for( SCTAB nTab = pRange->aStart.Tab(); nTab <= pRange->aEnd.Tab(); ++nTab )
6396 maTabs[nTab]->GetNotesInRange( *pRange, rNotes );
6401 bool ScDocument::ContainsNotesInRange( const ScRangeList& rRange ) const
6403 for( size_t i = 0; i < rRange.size(); ++i)
6405 const ScRange* pRange = rRange[i];
6406 for( SCTAB nTab = pRange->aStart.Tab(); nTab < pRange->aEnd.Tab(); ++nTab )
6408 bool bContainsNote = maTabs[nTab]->ContainsNotesInRange( *pRange );
6409 if(bContainsNote)
6410 return true;
6414 return false;
6417 void ScDocument::SetAutoNameCache( ScAutoNameCache* pCache )
6419 delete pAutoNameCache;
6420 pAutoNameCache = pCache;
6423 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */