Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / document.cxx
blobc9f14cf44eabd1cf0393c01e8b4b633cd1c5dcfd
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 "stlalgorithm.hxx"
88 #include "defaultsoptions.hxx"
89 #include "editutil.hxx"
90 #include "stringutil.hxx"
91 #include "formulaiter.hxx"
92 #include "formulacell.hxx"
93 #include "clipcontext.hxx"
94 #include "listenercontext.hxx"
95 #include "scopetools.hxx"
96 #include "refupdatecontext.hxx"
97 #include "formulagroup.hxx"
99 #include "formula/vectortoken.hxx"
101 #include <map>
102 #include <limits>
103 #include <boost/scoped_ptr.hpp>
105 #include "mtvelements.hxx"
107 using ::editeng::SvxBorderLine;
108 using namespace ::com::sun::star;
110 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
111 using ::com::sun::star::uno::Sequence;
112 using ::com::sun::star::sheet::TablePageBreakData;
113 using ::std::set;
115 namespace {
117 std::pair<SCTAB,SCTAB> getMarkedTableRange(const std::vector<ScTable*>& rTables, const ScMarkData& rMark)
119 SCTAB nTabStart = MAXTAB;
120 SCTAB nTabEnd = 0;
121 SCTAB nMax = static_cast<SCTAB>(rTables.size());
122 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
123 for (; itr != itrEnd && *itr < nMax; ++itr)
125 if (!rTables[*itr])
126 continue;
128 if (*itr < nTabStart)
129 nTabStart = *itr;
130 nTabEnd = *itr;
133 return std::pair<SCTAB,SCTAB>(nTabStart,nTabEnd);
138 struct ScDefaultAttr
140 const ScPatternAttr* pAttr;
141 SCROW nFirst;
142 SCSIZE nCount;
143 ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
146 struct ScLessDefaultAttr
148 bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
150 return rValue1.pAttr < rValue2.pAttr;
154 typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
156 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
158 if ( ValidTab(nTab) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab]) )
160 // Get Custom prefix
161 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
162 OUString aString = rOpt.GetInitTabPrefix();
164 aString += OUString::number(nTab+1);
165 if ( _bNeedsNameCheck )
166 CreateValidTabName( aString ); // no doubles
167 if (nTab < static_cast<SCTAB>(maTabs.size()))
169 maTabs[nTab] = new ScTable(this, nTab, aString);
171 else
173 while(nTab > static_cast<SCTAB>(maTabs.size()))
174 maTabs.push_back(NULL);
175 maTabs.push_back( new ScTable(this, nTab, aString) );
177 maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
182 bool ScDocument::HasTable( SCTAB nTab ) const
184 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
185 if (maTabs[nTab])
186 return true;
188 return false;
191 bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
193 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
194 if (maTabs[nTab])
196 maTabs[nTab]->GetName( rName );
197 return true;
199 rName = OUString();
200 return false;
203 OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
205 if (nTab < static_cast<SCTAB>(maTabNames.size()))
206 return maTabNames[nTab];
207 else
208 return OUString();
211 bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
213 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
215 if (maTabs[nTab])
217 maTabs[nTab]->SetCodeName( rName );
218 return true;
221 OSL_TRACE( "**** can't set code name %s", OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
222 return false;
225 bool ScDocument::GetCodeName( SCTAB nTab, OUString& rName ) const
227 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
228 if (maTabs[nTab])
230 maTabs[nTab]->GetCodeName( rName );
231 return true;
233 rName = OUString();
234 return false;
237 bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
239 OUString aUpperName = ScGlobal::pCharClass->uppercase(rName);
241 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
242 if (maTabs[i])
244 if (aUpperName.equals(maTabs[i]->GetUpperName()))
246 rTab = i;
247 return true;
250 rTab = 0;
251 return false;
254 std::vector<OUString> ScDocument::GetAllTableNames() const
256 std::vector<OUString> aNames;
257 aNames.reserve(maTabs.size());
258 TableContainer::const_iterator it = maTabs.begin(), itEnd = maTabs.end();
259 for (; it != itEnd; ++it)
261 OUString aName;
262 const ScTable& rTab = **it;
263 rTab.GetName(aName);
264 aNames.push_back(aName);
267 return aNames;
270 ScDBData* ScDocument::GetAnonymousDBData(SCTAB nTab)
272 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
273 return maTabs[nTab]->GetAnonymousDBData();
274 return NULL;
277 SCTAB ScDocument::GetTableCount() const
279 return static_cast<SCTAB>(maTabs.size());
282 void ScDocument::SetAnonymousDBData(SCTAB nTab, ScDBData* pDBData)
284 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
285 maTabs[nTab]->SetAnonymousDBData(pDBData);
289 bool ScDocument::ValidTabName( const OUString& rName )
291 if (rName.isEmpty())
292 return false;
293 sal_Int32 nLen = rName.getLength();
295 #if 1
296 // Restrict sheet names to what Excel accepts.
297 /* TODO: We may want to remove this restriction for full ODFF compliance.
298 * Merely loading and calculating ODF documents using these characters in
299 * sheet names is not affected by this, but all sheet name editing and
300 * copying functionality is, maybe falling back to "Sheet4" or similar. */
301 for (sal_Int32 i = 0; i < nLen; ++i)
303 const sal_Unicode c = rName[i];
304 switch (c)
306 case ':':
307 case '\\':
308 case '/':
309 case '?':
310 case '*':
311 case '[':
312 case ']':
313 // these characters are not allowed to match XL's convention.
314 return false;
315 case '\'':
316 if (i == 0 || i == nLen - 1)
317 // single quote is not allowed at the first or last
318 // character position.
319 return false;
320 break;
323 #endif
325 return true;
329 bool ScDocument::ValidNewTabName( const OUString& rName ) const
331 bool bValid = ValidTabName(rName);
332 TableContainer::const_iterator it = maTabs.begin();
333 for (; it != maTabs.end() && bValid; ++it)
334 if ( *it )
336 OUString aOldName;
337 (*it)->GetName(aOldName);
338 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
340 return bValid;
344 void ScDocument::CreateValidTabName(OUString& rName) const
346 if ( !ValidTabName(rName) )
348 // Find new one
350 // Get Custom prefix
351 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
352 OUString aStrTable = rOpt.GetInitTabPrefix();
354 bool bOk = false;
356 // First test if the prefix is valid, if so only avoid doubles
357 bool bPrefix = ValidTabName( aStrTable );
358 OSL_ENSURE(bPrefix, "Invalid Table Name");
359 SCTAB nDummy;
361 for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
363 OUStringBuffer aBuf;
364 aBuf.append(aStrTable);
365 aBuf.append(static_cast<sal_Int32>(i));
366 rName = aBuf.makeStringAndClear();
367 if (bPrefix)
368 bOk = ValidNewTabName( rName );
369 else
370 bOk = !GetTable( rName, nDummy );
373 else
375 // testing the supplied Name
377 if ( !ValidNewTabName(rName) )
379 SCTAB i = 1;
380 OUStringBuffer aName;
383 i++;
384 aName = rName;
385 aName.append('_');
386 aName.append(static_cast<sal_Int32>(i));
388 while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
389 rName = aName.makeStringAndClear();
394 void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount) const
396 aNames.clear();//ensure that the vector is empty
398 // Get Custom prefix
399 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
400 OUString aStrTable = rOpt.GetInitTabPrefix();
402 OUStringBuffer rName;
403 bool bOk = false;
405 // First test if the prefix is valid, if so only avoid doubles
406 bool bPrefix = ValidTabName( aStrTable );
407 OSL_ENSURE(bPrefix, "Invalid Table Name");
408 SCTAB nDummy;
409 SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
411 for (SCTAB j = 0; j < nCount; ++j)
413 bOk = false;
414 while(!bOk)
416 rName = aStrTable;
417 rName.append(static_cast<sal_Int32>(i));
418 if (bPrefix)
419 bOk = ValidNewTabName( rName.toString() );
420 else
421 bOk = !GetTable( rName.toString(), nDummy );
422 i++;
424 aNames.push_back(rName.makeStringAndClear());
428 void ScDocument::AppendTabOnLoad(const OUString& rName)
430 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
431 if (!ValidTab(nTabCount))
432 // max table count reached. No more tables.
433 return;
435 OUString aName = rName;
436 CreateValidTabName(aName);
437 maTabs.push_back( new ScTable(this, nTabCount, aName) );
440 void ScDocument::SetTabNameOnLoad(SCTAB nTab, const OUString& rName)
442 if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
443 return;
445 if (!ValidTabName(rName))
446 return;
448 maTabs[nTab]->SetName(rName);
451 void ScDocument::InvalidateStreamOnSave()
453 TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
454 for (; it != itEnd; ++it)
456 ScTable* pTab = *it;
457 if (pTab)
458 pTab->SetStreamValid(false);
462 bool ScDocument::InsertTab( SCTAB nPos, const OUString& rName,
463 bool bExternalDocument )
465 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
466 bool bValid = ValidTab(nTabCount);
467 if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
468 bValid = (bValid && ValidNewTabName(rName));
469 if (bValid)
471 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
473 maTabs.push_back( new ScTable(this, nTabCount, rName) );
474 if ( bExternalDocument )
475 maTabs[nTabCount]->SetVisible( false );
477 else
479 if (ValidTab(nPos) && (nPos < nTabCount))
481 sc::RefUpdateInsertTabContext aCxt(nPos, 1);
483 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
484 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
485 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
486 if (pRangeName)
487 pRangeName->UpdateInsertTab(aCxt);
488 pDBCollection->UpdateReference(
489 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
490 if (pDPCollection)
491 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
492 if (pDetOpList)
493 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
494 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
495 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
496 if ( pUnoBroadcaster )
497 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
499 SCTAB i;
500 TableContainer::iterator it = maTabs.begin();
501 for (; it != maTabs.end(); ++it)
502 if ( *it )
503 (*it)->UpdateInsertTab(aCxt);
504 maTabs.push_back(NULL);
505 for (i = nTabCount; i > nPos; i--)
507 maTabs[i] = maTabs[i - 1];
510 maTabs[nPos] = new ScTable(this, nPos, rName);
512 // UpdateBroadcastAreas must be called between UpdateInsertTab,
513 // which ends listening, and StartAllListeners, to not modify
514 // areas that are to be inserted by starting listeners.
515 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
516 it = maTabs.begin();
517 for (; it != maTabs.end(); ++it)
518 if ( *it )
519 (*it)->UpdateCompile();
520 it = maTabs.begin();
521 for (; it != maTabs.end(); ++it)
522 if ( *it )
523 (*it)->StartAllListeners();
525 if (pValidationList)
526 pValidationList->UpdateInsertTab(aCxt);
528 // sheet names of references are not valid until sheet is inserted
529 if ( pChartListenerCollection )
530 pChartListenerCollection->UpdateScheduledSeriesRanges();
532 bValid = true;
534 else
535 bValid = false;
539 if (bValid)
540 SetDirty();
542 return bValid;
546 bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
547 bool bExternalDocument, bool bNamesValid )
549 SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
550 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
551 bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
552 // if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
553 // bValid = (bValid && ValidNewTabName(rNames));
554 if (bValid)
556 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
558 for ( SCTAB i = 0; i < nNewSheets; ++i )
560 maTabs.push_back( new ScTable(this, nTabCount + i, rNames.at(i)) );
561 if ( bExternalDocument )
562 maTabs[nTabCount+i]->SetVisible( false );
565 else
567 if (ValidTab(nPos) && (nPos < nTabCount))
569 sc::RefUpdateInsertTabContext aCxt(nPos, nNewSheets);
570 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
571 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
572 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
573 if (pRangeName)
574 pRangeName->UpdateInsertTab(aCxt);
575 pDBCollection->UpdateReference(
576 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
577 if (pDPCollection)
578 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
579 if (pDetOpList)
580 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,nNewSheets );
581 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
582 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0, nNewSheets );
583 if ( pUnoBroadcaster )
584 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,nNewSheets ) );
586 TableContainer::iterator it = maTabs.begin();
587 for (; it != maTabs.end(); ++it)
588 if ( *it )
589 (*it)->UpdateInsertTab(aCxt);
590 it = maTabs.begin();
591 maTabs.insert(it+nPos,nNewSheets, NULL);
592 for (SCTAB i = 0; i < nNewSheets; ++i)
594 maTabs[nPos + i] = new ScTable(this, nPos + i, rNames.at(i));
597 // UpdateBroadcastAreas must be called between UpdateInsertTab,
598 // which ends listening, and StartAllListeners, to not modify
599 // areas that are to be inserted by starting listeners.
600 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,nNewSheets);
601 it = maTabs.begin();
602 for (; it != maTabs.end(); ++it)
604 if ( *it )
605 (*it)->UpdateCompile();
607 it = maTabs.begin();
608 for (; it != maTabs.end(); ++it)
609 if ( *it )
610 (*it)->StartAllListeners();
612 if (pValidationList)
613 pValidationList->UpdateInsertTab(aCxt);
615 // sheet names of references are not valid until sheet is inserted
616 if ( pChartListenerCollection )
617 pChartListenerCollection->UpdateScheduledSeriesRanges();
619 bValid = true;
621 else
622 bValid = false;
626 if (bValid)
627 SetDirty();
629 return bValid;
633 bool ScDocument::DeleteTab( SCTAB nTab )
635 bool bValid = false;
636 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
638 if (maTabs[nTab])
640 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
641 if (nTabCount > 1)
643 sc::AutoCalcSwitch aACSwitch(*this, false);
644 sc::RefUpdateDeleteTabContext aCxt(nTab, 1);
646 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
647 DelBroadcastAreasInRange( aRange );
649 // #i8180# remove database ranges etc. that are on the deleted tab
650 // (restored in undo with ScRefUndoData)
652 xColNameRanges->DeleteOnTab( nTab );
653 xRowNameRanges->DeleteOnTab( nTab );
654 pDBCollection->DeleteOnTab( nTab );
655 if (pDPCollection)
656 pDPCollection->DeleteOnTab( nTab );
657 if (pDetOpList)
658 pDetOpList->DeleteOnTab( nTab );
659 DeleteAreaLinksOnTab( nTab );
661 // normal reference update
663 aRange.aEnd.SetTab( static_cast<SCTAB>(maTabs.size())-1 );
664 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
665 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
666 if (pRangeName)
667 pRangeName->UpdateDeleteTab(aCxt);
668 pDBCollection->UpdateReference(
669 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
670 if (pDPCollection)
671 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
672 if (pDetOpList)
673 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
674 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
675 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
676 if (pValidationList)
677 pValidationList->UpdateDeleteTab(aCxt);
678 if ( pUnoBroadcaster )
679 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
681 for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
682 if (maTabs[i])
683 maTabs[i]->UpdateDeleteTab(aCxt);
685 TableContainer::iterator it = maTabs.begin() + nTab;
686 delete *it;
687 maTabs.erase(it);
688 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
689 // which ends listening, and StartAllListeners, to not modify
690 // areas that are to be inserted by starting listeners.
691 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
692 it = maTabs.begin();
693 for (; it != maTabs.end(); ++it)
694 if ( *it )
695 (*it)->UpdateCompile();
696 // Excel-Filter deletes some Tables while loading, Listeners will
697 // only be triggered after the loading is done.
698 if ( !bInsertingFromOtherDoc )
700 it = maTabs.begin();
701 for (; it != maTabs.end(); ++it)
702 if ( *it )
703 (*it)->StartAllListeners();
704 SetDirty();
706 // sheet names of references are not valid until sheet is deleted
707 pChartListenerCollection->UpdateScheduledSeriesRanges();
709 bValid = true;
713 return bValid;
717 bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets )
719 bool bValid = false;
720 if (ValidTab(nTab) && (nTab + nSheets) < static_cast<SCTAB>(maTabs.size()))
722 if (maTabs[nTab])
724 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
725 if (nTabCount > nSheets)
727 sc::AutoCalcSwitch aACSwitch(*this, false);
728 sc::RefUpdateDeleteTabContext aCxt(nTab, nSheets);
730 for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
732 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab + aTab );
733 DelBroadcastAreasInRange( aRange );
735 // #i8180# remove database ranges etc. that are on the deleted tab
736 // (restored in undo with ScRefUndoData)
738 xColNameRanges->DeleteOnTab( nTab + aTab );
739 xRowNameRanges->DeleteOnTab( nTab + aTab );
740 pDBCollection->DeleteOnTab( nTab + aTab );
741 if (pDPCollection)
742 pDPCollection->DeleteOnTab( nTab + aTab );
743 if (pDetOpList)
744 pDetOpList->DeleteOnTab( nTab + aTab );
745 DeleteAreaLinksOnTab( nTab + aTab );
748 if (pRangeName)
749 pRangeName->UpdateDeleteTab(aCxt);
751 // normal reference update
753 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTabCount - 1 );
754 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
755 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
756 pDBCollection->UpdateReference(
757 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
758 if (pDPCollection)
759 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
760 if (pDetOpList)
761 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
762 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
763 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
764 if (pValidationList)
765 pValidationList->UpdateDeleteTab(aCxt);
766 if ( pUnoBroadcaster )
767 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
769 for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
770 if (maTabs[i])
771 maTabs[i]->UpdateDeleteTab(aCxt);
773 TableContainer::iterator it = maTabs.begin() + nTab;
774 TableContainer::iterator itEnd = it + nSheets;
775 std::for_each(it, itEnd, ScDeleteObjectByPtr<ScTable>());
776 maTabs.erase(it, itEnd);
777 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
778 // which ends listening, and StartAllListeners, to not modify
779 // areas that are to be inserted by starting listeners.
780 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
781 it = maTabs.begin();
782 for (; it != maTabs.end(); ++it)
783 if ( *it )
784 (*it)->UpdateCompile();
785 // Excel-Filter deletes some Tables while loading, Listeners will
786 // only be triggered after the loading is done.
787 if ( !bInsertingFromOtherDoc )
789 it = maTabs.begin();
790 for (; it != maTabs.end(); ++it)
791 if ( *it )
792 (*it)->StartAllListeners();
793 SetDirty();
795 // sheet names of references are not valid until sheet is deleted
796 pChartListenerCollection->UpdateScheduledSeriesRanges();
798 bValid = true;
802 return bValid;
806 bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool /* bUpdateRef */,
807 bool bExternalDocument )
809 bool bValid = false;
810 SCTAB i;
811 if (ValidTab(nTab))
813 if (maTabs[nTab])
815 if ( bExternalDocument )
816 bValid = true; // composed name
817 else
818 bValid = ValidTabName(rName);
819 for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
820 if (maTabs[i] && (i != nTab))
822 OUString aOldName;
823 maTabs[i]->GetName(aOldName);
824 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
826 if (bValid)
828 // #i75258# update charts before renaming, so they can get their live data objects.
829 // Once the charts are live, the sheet can be renamed without problems.
830 if ( pChartListenerCollection )
831 pChartListenerCollection->UpdateChartsContainingTab( nTab );
832 maTabs[nTab]->SetName(rName);
834 // If formulas refer to the renamed sheet, the TokenArray remains valid,
835 // but the XML stream must be re-generated.
836 TableContainer::iterator it = maTabs.begin();
837 for (; it != maTabs.end(); ++it)
838 if ( *it && (*it)->IsStreamValid())
839 (*it)->SetStreamValid( false );
843 return bValid;
847 void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
849 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
850 if (maTabs[nTab])
851 maTabs[nTab]->SetVisible(bVisible);
855 bool ScDocument::IsVisible( SCTAB nTab ) const
857 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
858 if (maTabs[nTab])
859 return maTabs[nTab]->IsVisible();
861 return false;
865 bool ScDocument::IsStreamValid( SCTAB nTab ) const
867 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
868 return maTabs[nTab]->IsStreamValid();
870 return false;
874 void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
876 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
877 maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
881 void ScDocument::LockStreamValid( bool bLock )
883 mbStreamValidLocked = bLock;
887 bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
889 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
890 return maTabs[nTab]->IsPendingRowHeights();
892 return false;
896 void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
898 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
899 maTabs[nTab]->SetPendingRowHeights( bSet );
903 void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
905 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
907 if ( bImportingXML )
909 // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
910 // is applied in SetImportingXML(false). This is so the shapes can be loaded in
911 // normal LTR mode.
913 maTabs[nTab]->SetLoadingRTL( bRTL );
914 return;
917 maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
918 maTabs[nTab]->SetDrawPageSize();
920 // mirror existing objects:
922 if (pDrawLayer)
924 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
925 OSL_ENSURE(pPage,"Page ?");
926 if (pPage)
928 SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
929 SdrObject* pObject = aIter.Next();
930 while (pObject)
932 // objects with ScDrawObjData are re-positioned in SetPageSize,
933 // don't mirror again
934 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
935 if ( !pData )
936 pDrawLayer->MirrorRTL( pObject );
938 pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
940 pObject = aIter.Next();
948 bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
950 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
951 return maTabs[nTab]->IsLayoutRTL();
953 return false;
957 bool ScDocument::IsNegativePage( SCTAB nTab ) const
959 // Negative page area is always used for RTL layout.
960 // The separate method is used to find all RTL handling of drawing objects.
961 return IsLayoutRTL( nTab );
965 /* ----------------------------------------------------------------------------
966 used search area:
968 GetCellArea - Only Data
969 GetTableArea - Data / Attributes
970 GetPrintArea - intended for character objects,
971 sweeps attributes all the way to bottom / right
972 ---------------------------------------------------------------------------- */
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;
987 bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
989 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
990 if (maTabs[nTab])
991 return maTabs[nTab]->GetTableArea( rEndCol, rEndRow );
993 rEndCol = 0;
994 rEndRow = 0;
995 return false;
998 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
1000 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1001 return false;
1003 SCCOL nCol1, nCol2;
1004 SCROW nRow1, nRow2;
1005 maTabs[nTab]->GetFirstDataPos(nCol1, nRow1);
1006 maTabs[nTab]->GetLastDataPos(nCol2, nRow2);
1008 if (nCol1 > nCol2 || nRow1 > nRow2)
1009 // invalid range.
1010 return false;
1012 // Make sure the area only shrinks, and doesn't grow.
1013 if (rStartCol < nCol1)
1014 rStartCol = nCol1;
1015 if (nCol2 < rEndCol)
1016 rEndCol = nCol2;
1017 if (rStartRow < nRow1)
1018 rStartRow = nRow1;
1019 if (nRow2 < rEndRow)
1020 rEndRow = nRow2;
1022 if (rStartCol > rEndCol || rStartRow > rEndRow)
1023 // invalid range.
1024 return false;
1026 return true; // success!
1029 bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
1030 SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) 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, bColumnsOnly);
1040 SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
1042 const ScTable* pTab = FetchTable(nTab);
1043 if (!pTab)
1044 return -1;
1046 return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
1049 // connected area
1051 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1052 SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
1054 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1055 maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
1059 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1060 SCCOL& rEndCol, SCROW& rEndRow )
1062 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1063 if (maTabs[nTab])
1064 maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
1068 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
1070 ScRangeListRef aNew = new ScRangeList;
1071 if (rRangeList.Is())
1073 for ( size_t i = 0, nCount = rRangeList->size(); i < nCount; i++ )
1075 ScRange aRange( *(*rRangeList)[i] );
1076 if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
1077 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
1079 SCCOL nStartCol = aRange.aStart.Col();
1080 SCROW nStartRow = aRange.aStart.Row();
1081 SCCOL nEndCol = aRange.aEnd.Col();
1082 SCROW nEndRow = aRange.aEnd.Row();
1083 SCTAB nTab = aRange.aStart.Tab();
1084 if ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1085 maTabs[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
1086 aRange.aStart.SetCol( nStartCol );
1087 aRange.aStart.SetRow( nStartRow );
1088 aRange.aEnd.SetCol( nEndCol );
1089 aRange.aEnd.SetRow( nEndRow );
1091 aNew->Append(aRange);
1094 else
1096 OSL_FAIL("LimitChartIfAll: Ref==0");
1098 rRangeList = aNew;
1102 static void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1104 // without ScMarkData, leave start/end unchanged
1105 if ( pTabMark )
1107 for (SCTAB nTab=0; nTab< aMaxTab; ++nTab)
1108 if (pTabMark->GetTableSelect(nTab))
1110 // find first range of consecutive selected sheets
1111 rTabRangeStart = pTabMark->GetFirstSelected();
1112 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1113 ++nTab;
1114 rTabRangeEnd = nTab;
1115 return;
1120 static bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1122 if ( pTabMark )
1124 // find next range of consecutive selected sheets after rTabRangeEnd
1125 for (SCTAB nTab=rTabRangeEnd+1; nTab< aMaxTab; ++nTab)
1126 if (pTabMark->GetTableSelect(nTab))
1128 rTabRangeStart = nTab;
1129 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1130 ++nTab;
1131 rTabRangeEnd = nTab;
1132 return true;
1135 return false;
1139 bool ScDocument::CanInsertRow( const ScRange& rRange ) const
1141 SCCOL nStartCol = rRange.aStart.Col();
1142 SCROW nStartRow = rRange.aStart.Row();
1143 SCTAB nStartTab = rRange.aStart.Tab();
1144 SCCOL nEndCol = rRange.aEnd.Col();
1145 SCROW nEndRow = rRange.aEnd.Row();
1146 SCTAB nEndTab = rRange.aEnd.Tab();
1147 PutInOrder( nStartCol, nEndCol );
1148 PutInOrder( nStartRow, nEndRow );
1149 PutInOrder( nStartTab, nEndTab );
1150 SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
1152 bool bTest = true;
1153 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1154 if (maTabs[i])
1155 bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
1157 return bTest;
1160 namespace {
1162 struct StartNeededListenersHandler : std::unary_function<ScTable*, void>
1164 void operator() (ScTable* p)
1166 if (p)
1167 p->StartNeededListeners();
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()) );
1224 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1225 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1226 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
1228 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1230 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1232 sc::RefUpdateContext aCxt(*this);
1233 aCxt.meMode = URM_INSDEL;
1234 aCxt.maRange = ScRange(nStartCol, nStartRow, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
1235 aCxt.mnRowDelta = nSize;
1238 UpdateReference(aCxt, pRefUndoDoc, false); // without drawing objects
1240 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1242 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1243 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1244 maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
1246 // UpdateRef for drawing layer must be after inserting,
1247 // when the new row heights are known.
1248 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1249 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1250 maTabs[i]->UpdateDrawRef( URM_INSDEL,
1251 nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
1252 0, static_cast<SCsROW>(nSize), 0 );
1254 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1255 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1256 // ein neues Listening faellig, bisherige Listener wurden in
1257 // FormulaCell UpdateReference abgehaengt
1258 StartAllListeners();
1260 else
1261 { // Listeners have been removed in UpdateReference
1262 TableContainer::iterator it = maTabs.begin();
1263 for (; it != maTabs.end(); ++it)
1264 if (*it)
1265 (*it)->StartNeededListeners();
1266 // At least all cells using range names pointing relative to the
1267 // moved range must be recalculated, and all cells marked postponed
1268 // dirty.
1269 it = maTabs.begin();
1270 for (; it != maTabs.end(); ++it)
1271 if (*it)
1272 (*it)->SetDirtyIfPostponed();
1274 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1276 bRet = true;
1278 SetAutoCalc( bOldAutoCalc );
1279 if ( bRet )
1280 pChartListenerCollection->UpdateDirtyCharts();
1281 return bRet;
1285 bool ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
1287 return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1288 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1289 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
1290 pRefUndoDoc );
1294 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
1295 SCCOL nEndCol, SCTAB nEndTab,
1296 SCROW nStartRow, SCSIZE nSize,
1297 ScDocument* pRefUndoDoc, bool* pUndoOutline,
1298 const ScMarkData* pTabMark )
1300 SCTAB i;
1302 PutInOrder( nStartCol, nEndCol );
1303 PutInOrder( nStartTab, nEndTab );
1304 if ( pTabMark )
1306 nStartTab = 0;
1307 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1310 bool bOldAutoCalc = GetAutoCalc();
1311 SetAutoCalc( false ); // avoid multiple calculations
1313 // handle chunks of consecutive selected sheets together
1314 SCTAB nTabRangeStart = nStartTab;
1315 SCTAB nTabRangeEnd = nEndTab;
1316 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1319 if ( ValidRow(nStartRow+nSize) )
1321 DelBroadcastAreasInRange( ScRange(
1322 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1323 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
1324 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1325 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
1326 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
1328 else
1329 DelBroadcastAreasInRange( ScRange(
1330 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1331 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
1333 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1335 sc::RefUpdateContext aCxt(*this);
1336 if ( ValidRow(nStartRow+nSize) )
1338 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1339 aCxt.meMode = URM_INSDEL;
1340 aCxt.maRange = ScRange(nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
1341 aCxt.mnRowDelta = -(static_cast<SCROW>(nSize));
1344 UpdateReference(aCxt, pRefUndoDoc, true, false);
1346 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1349 if (pUndoOutline)
1350 *pUndoOutline = false;
1352 for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1353 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1354 maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline);
1356 if ( ValidRow(nStartRow+nSize) )
1357 { // Listeners have been removed in UpdateReference
1358 TableContainer::iterator it = maTabs.begin();
1359 for (; it != maTabs.end(); ++it)
1360 if (*it)
1361 (*it)->StartNeededListeners();
1362 // At least all cells using range names pointing relative to the moved
1363 // range must be recalculated, and all cells marked postponed dirty.
1364 it = maTabs.begin();
1365 for (; it != maTabs.end(); ++it)
1366 if (*it)
1367 (*it)->SetDirtyIfPostponed();
1369 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1372 SetAutoCalc( bOldAutoCalc );
1373 pChartListenerCollection->UpdateDirtyCharts();
1377 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, bool* pUndoOutline )
1379 DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1380 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1381 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
1382 pRefUndoDoc, pUndoOutline );
1386 bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1388 SCCOL nStartCol = rRange.aStart.Col();
1389 SCROW nStartRow = rRange.aStart.Row();
1390 SCTAB nStartTab = rRange.aStart.Tab();
1391 SCCOL nEndCol = rRange.aEnd.Col();
1392 SCROW nEndRow = rRange.aEnd.Row();
1393 SCTAB nEndTab = rRange.aEnd.Tab();
1394 PutInOrder( nStartCol, nEndCol );
1395 PutInOrder( nStartRow, nEndRow );
1396 PutInOrder( nStartTab, nEndTab );
1397 SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1399 bool bTest = true;
1400 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1401 if (maTabs[i])
1402 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1404 return bTest;
1407 bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1408 SCROW nEndRow, SCTAB nEndTab,
1409 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1410 const ScMarkData* pTabMark )
1412 SCTAB i;
1414 PutInOrder( nStartRow, nEndRow );
1415 PutInOrder( nStartTab, nEndTab );
1416 if ( pTabMark )
1418 nStartTab = 0;
1419 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1422 bool bTest = true;
1423 bool bRet = false;
1424 bool bOldAutoCalc = GetAutoCalc();
1425 SetAutoCalc( false ); // avoid multiple calculations
1426 for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1427 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1428 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1429 if (bTest)
1431 // handle chunks of consecutive selected sheets together
1432 SCTAB nTabRangeStart = nStartTab;
1433 SCTAB nTabRangeEnd = nEndTab;
1434 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1437 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1438 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1439 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1441 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1443 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1445 sc::RefUpdateContext aCxt(*this);
1446 aCxt.meMode = URM_INSDEL;
1447 aCxt.maRange = ScRange(nStartCol, nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
1448 aCxt.mnColDelta = nSize;
1451 UpdateReference(aCxt, pRefUndoDoc, true, false);
1453 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1455 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1456 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1457 maTabs[i]->InsertCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize);
1459 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1460 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1461 // ein neues Listening faellig, bisherige Listener wurden in
1462 // FormulaCell UpdateReference abgehaengt
1463 StartAllListeners();
1465 else
1467 // Listeners have been removed in UpdateReference
1468 std::for_each(maTabs.begin(), maTabs.end(), StartNeededListenersHandler());
1469 // At least all cells using range names pointing relative to the
1470 // moved range must be recalculated, and all cells marked postponed
1471 // dirty.
1472 std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
1473 // Cells containing functions such as CELL, COLUMN or ROW may have
1474 // changed their values on relocation. Broadcast them.
1475 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1477 bRet = true;
1479 SetAutoCalc( bOldAutoCalc );
1480 if ( bRet )
1481 pChartListenerCollection->UpdateDirtyCharts();
1482 return bRet;
1486 bool ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1488 return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1489 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1490 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1491 pRefUndoDoc );
1495 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1496 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1497 bool* pUndoOutline, const ScMarkData* pTabMark )
1499 SCTAB i;
1501 PutInOrder( nStartRow, nEndRow );
1502 PutInOrder( nStartTab, nEndTab );
1503 if ( pTabMark )
1505 nStartTab = 0;
1506 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1509 sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1511 // handle chunks of consecutive selected sheets together
1512 SCTAB nTabRangeStart = nStartTab;
1513 SCTAB nTabRangeEnd = nEndTab;
1514 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1517 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1519 DelBroadcastAreasInRange( ScRange(
1520 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1521 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1522 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1523 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1524 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1526 else
1527 DelBroadcastAreasInRange( ScRange(
1528 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1529 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1531 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1533 sc::RefUpdateContext aCxt(*this);
1534 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1536 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1537 aCxt.meMode = URM_INSDEL;
1538 aCxt.maRange = ScRange(sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
1539 aCxt.mnColDelta = -(static_cast<SCCOL>(nSize));
1542 UpdateReference(aCxt, pRefUndoDoc, true, false);
1544 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1547 if (pUndoOutline)
1548 *pUndoOutline = false;
1550 for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
1552 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1553 maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
1556 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1557 {// Listeners have been removed in UpdateReference
1558 TableContainer::iterator it = maTabs.begin();
1559 for (; it != maTabs.end(); ++it)
1560 if (*it)
1561 (*it)->StartNeededListeners();
1562 // At least all cells using range names pointing relative to the moved
1563 // range must be recalculated, and all cells marked postponed dirty.
1564 it = maTabs.begin();
1565 for (; it != maTabs.end(); ++it)
1566 if (*it)
1567 (*it)->SetDirtyIfPostponed();
1569 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1572 pChartListenerCollection->UpdateDirtyCharts();
1576 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, bool* pUndoOutline )
1578 DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1579 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1580 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1581 pRefUndoDoc, pUndoOutline );
1585 // fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
1586 // (ohne Paint)
1589 static void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1590 ScRange& rColRange, bool& rInsCol, bool& rDelCol,
1591 ScRange& rRowRange, bool& rInsRow, bool& rDelRow )
1593 OSL_ENSURE( rOld.aStart == rNew.aStart, "FitBlock: Beginning is different" );
1595 rInsCol = rDelCol = rInsRow = rDelRow = false;
1597 SCCOL nStartX = rOld.aStart.Col();
1598 SCROW nStartY = rOld.aStart.Row();
1599 SCCOL nOldEndX = rOld.aEnd.Col();
1600 SCROW nOldEndY = rOld.aEnd.Row();
1601 SCCOL nNewEndX = rNew.aEnd.Col();
1602 SCROW nNewEndY = rNew.aEnd.Row();
1603 SCTAB nTab = rOld.aStart.Tab();
1605 // wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
1606 bool bGrowY = ( nNewEndY > nOldEndY );
1607 SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1608 SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1610 // Spalten
1612 if ( nNewEndX > nOldEndX ) // Spalten einfuegen
1614 rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1615 rInsCol = true;
1617 else if ( nNewEndX < nOldEndX ) // Spalten loeschen
1619 rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1620 rDelCol = true;
1623 // Zeilen
1625 if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
1627 rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1628 rInsRow = true;
1630 else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
1632 rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1633 rDelRow = true;
1638 bool ScDocument::HasPartOfMerged( const ScRange& rRange )
1640 bool bPart = false;
1641 SCTAB nTab = rRange.aStart.Tab();
1643 SCCOL nStartX = rRange.aStart.Col();
1644 SCROW nStartY = rRange.aStart.Row();
1645 SCCOL nEndX = rRange.aEnd.Col();
1646 SCROW nEndY = rRange.aEnd.Row();
1648 if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1649 HASATTR_MERGED | HASATTR_OVERLAPPED ))
1651 ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1652 ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1654 bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1655 nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1657 return bPart;
1660 size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const
1662 SCTAB nTab = rPos.Tab();
1663 if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab])
1664 return 0;
1666 return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row());
1669 ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos ) const
1671 SCTAB nTab = rPos.Tab();
1672 if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab])
1673 return FormulaVectorUnknown;
1675 return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
1678 formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
1680 SCTAB nTab = rPos.Tab();
1681 if (!TableExists(nTab))
1682 return formula::FormulaTokenRef();
1684 return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
1687 formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
1689 SCTAB nTab = rRange.aStart.Tab();
1690 if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
1691 return formula::FormulaTokenRef();
1693 return maTabs[nTab]->ResolveStaticReference(
1694 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
1697 formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos, SCROW nLength )
1699 SCTAB nTab = rPos.Tab();
1700 if (!TableExists(nTab))
1701 return formula::VectorRefArray();
1703 return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1706 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1708 if ( rOld == rNew )
1709 return true;
1711 bool bOk = true;
1712 bool bInsCol,bDelCol,bInsRow,bDelRow;
1713 ScRange aColRange,aRowRange;
1714 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1716 if ( bInsCol && !CanInsertCol( aColRange ) ) // Zellen am Rand ?
1717 bOk = false;
1718 if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
1719 bOk = false;
1721 if ( bInsCol || bDelCol )
1723 aColRange.aEnd.SetCol(MAXCOL);
1724 if ( HasPartOfMerged(aColRange) )
1725 bOk = false;
1727 if ( bInsRow || bDelRow )
1729 aRowRange.aEnd.SetRow(MAXROW);
1730 if ( HasPartOfMerged(aRowRange) )
1731 bOk = false;
1734 return bOk;
1738 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, bool bClear )
1740 if (bClear)
1741 DeleteAreaTab( rOld, IDF_ALL );
1743 bool bInsCol,bDelCol,bInsRow,bDelRow;
1744 ScRange aColRange,aRowRange;
1745 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1747 if ( bInsCol )
1748 InsertCol( aColRange ); // Spalten zuerst einfuegen
1749 if ( bInsRow )
1750 InsertRow( aRowRange );
1752 if ( bDelRow )
1753 DeleteRow( aRowRange ); // Zeilen zuerst loeschen
1754 if ( bDelCol )
1755 DeleteCol( aColRange );
1757 // Referenzen um eingefuegte Zeilen erweitern
1759 if ( bInsCol || bInsRow )
1761 ScRange aGrowSource = rOld;
1762 aGrowSource.aEnd.SetCol(std::min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1763 aGrowSource.aEnd.SetRow(std::min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1764 SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1765 SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1766 UpdateGrow( aGrowSource, nGrowX, nGrowY );
1771 void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
1772 SCCOL nCol2, SCROW nRow2,
1773 const ScMarkData& rMark, sal_uInt16 nDelFlag)
1775 PutInOrder( nCol1, nCol2 );
1776 PutInOrder( nRow1, nRow2 );
1777 bool bOldAutoCalc = GetAutoCalc();
1778 SetAutoCalc( false ); // avoid multiple calculations
1779 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1780 if (maTabs[i])
1781 if ( rMark.GetTableSelect(i) || bIsUndo )
1782 maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1783 SetAutoCalc( bOldAutoCalc );
1787 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1788 SCCOL nCol2, SCROW nRow2,
1789 SCTAB nTab, sal_uInt16 nDelFlag)
1791 PutInOrder( nCol1, nCol2 );
1792 PutInOrder( nRow1, nRow2 );
1793 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1795 bool bOldAutoCalc = GetAutoCalc();
1796 SetAutoCalc( false ); // avoid multiple calculations
1797 maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1798 SetAutoCalc( bOldAutoCalc );
1803 void ScDocument::DeleteAreaTab( const ScRange& rRange, sal_uInt16 nDelFlag )
1805 for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1806 DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1807 rRange.aEnd.Col(), rRange.aEnd.Row(),
1808 nTab, nDelFlag );
1812 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1813 bool bColInfo, bool bRowInfo )
1815 if (bIsUndo)
1817 Clear();
1819 xPoolHelper = pSrcDoc->xPoolHelper;
1822 OUString aString;
1823 for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
1824 if ( rTabSelection.GetTableSelect( nTab ) )
1826 ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1827 if (nTab < static_cast<SCTAB>(maTabs.size()))
1828 maTabs[nTab] = pTable;
1829 else
1830 maTabs.push_back(pTable);
1832 else
1834 if (nTab < static_cast<SCTAB>(maTabs.size()))
1835 maTabs[nTab]=NULL;
1836 else
1837 maTabs.push_back(NULL);
1840 else
1842 OSL_FAIL("InitUndo");
1847 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1848 bool bColInfo, bool bRowInfo )
1850 if (bIsUndo)
1852 Clear();
1854 xPoolHelper = pSrcDoc->xPoolHelper;
1855 if (pSrcDoc->pShell->GetMedium())
1856 maFileURL = pSrcDoc->pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
1858 OUString aString;
1859 if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
1860 maTabs.resize(nTab2 + 1, NULL);
1861 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1863 ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1864 maTabs[nTab] = pTable;
1867 else
1869 OSL_FAIL("InitUndo");
1874 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowInfo )
1876 if (bIsUndo)
1878 OUString aString;
1879 if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
1881 maTabs.resize(nTab2+1,NULL);
1883 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1884 if (!maTabs[nTab])
1886 maTabs[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1890 else
1892 OSL_FAIL("InitUndo");
1897 void ScDocument::SetCutMode( bool bVal )
1899 if (bIsClip)
1900 GetClipParam().mbCutMode = bVal;
1901 else
1903 OSL_FAIL("SetCutMode without bIsClip");
1908 bool ScDocument::IsCutMode()
1910 if (bIsClip)
1911 return GetClipParam().mbCutMode;
1912 else
1914 OSL_FAIL("IsCutMode without bIsClip");
1915 return false;
1920 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1921 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1922 sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
1923 const ScMarkData* pMarks, bool bColRowFlags )
1925 PutInOrder( nCol1, nCol2 );
1926 PutInOrder( nRow1, nRow2 );
1927 PutInOrder( nTab1, nTab2 );
1928 if( pDestDoc->aDocName.isEmpty() )
1929 pDestDoc->aDocName = aDocName;
1930 if (ValidTab(nTab1) && ValidTab(nTab2))
1932 sc::CopyToDocContext aCxt(*pDestDoc);
1933 bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1934 pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
1935 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
1936 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
1938 if (maTabs[i] && pDestDoc->maTabs[i])
1939 maTabs[i]->CopyToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
1940 bOnlyMarked, pDestDoc->maTabs[i], pMarks,
1941 false, bColRowFlags );
1943 pDestDoc->SetAutoCalc( bOldAutoCalc );
1948 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1949 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1950 sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
1951 const ScMarkData* pMarks)
1953 PutInOrder( nCol1, nCol2 );
1954 PutInOrder( nRow1, nRow2 );
1955 PutInOrder( nTab1, nTab2 );
1956 if (ValidTab(nTab1) && ValidTab(nTab2))
1958 bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1959 pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
1960 if (nTab1 > 0)
1961 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
1963 sc::CopyToDocContext aCxt(*pDestDoc);
1964 OSL_ASSERT( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(pDestDoc->maTabs.size()));
1965 for (SCTAB i = nTab1; i <= nTab2; i++)
1967 if (maTabs[i] && pDestDoc->maTabs[i])
1968 maTabs[i]->UndoToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
1969 bOnlyMarked, pDestDoc->maTabs[i], pMarks);
1972 if (nTab2 < MAXTAB)
1973 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, false, pDestDoc, pMarks );
1974 pDestDoc->SetAutoCalc( bOldAutoCalc );
1979 void ScDocument::CopyToDocument(const ScRange& rRange,
1980 sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
1981 const ScMarkData* pMarks, bool bColRowFlags)
1983 ScRange aNewRange = rRange;
1984 aNewRange.Justify();
1986 if( pDestDoc->aDocName.isEmpty() )
1987 pDestDoc->aDocName = aDocName;
1988 bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1989 pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
1990 sc::CopyToDocContext aCxt(*pDestDoc);
1991 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
1992 for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
1994 if (!TableExists(i) || !pDestDoc->TableExists(i))
1995 continue;
1997 maTabs[i]->CopyToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1998 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1999 nFlags, bOnlyMarked, pDestDoc->maTabs[i],
2000 pMarks, false, bColRowFlags);
2002 pDestDoc->SetAutoCalc( bOldAutoCalc );
2006 void ScDocument::UndoToDocument(const ScRange& rRange,
2007 sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
2008 const ScMarkData* pMarks)
2010 sc::AutoCalcSwitch aAutoCalcSwitch(*this, false);
2012 ScRange aNewRange = rRange;
2013 aNewRange.Justify();
2014 SCTAB nTab1 = aNewRange.aStart.Tab();
2015 SCTAB nTab2 = aNewRange.aEnd.Tab();
2017 sc::CopyToDocContext aCxt(*pDestDoc);
2018 if (nTab1 > 0)
2019 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
2021 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pDestDoc->maTabs.size()));
2022 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
2024 if (maTabs[i] && pDestDoc->maTabs[i])
2025 maTabs[i]->UndoToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
2026 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2027 nFlags, bOnlyMarked, pDestDoc->maTabs[i], pMarks);
2030 if (nTab2 < static_cast<SCTAB>(maTabs.size()))
2031 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,maTabs.size(), IDF_FORMULA, false, pDestDoc, pMarks );
2034 // bUseRangeForVBA added for VBA api support to allow content of a specified
2035 // range to be copied ( e.g. don't use marked data but the just the range
2036 // specified by rClipParam
2037 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
2038 ScDocument* pClipDoc, const ScMarkData* pMarks,
2039 bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions, bool bUseRangeForVBA )
2041 OSL_ENSURE( !bUseRangeForVBA && ( bAllTabs || pMarks ), "CopyToClip: ScMarkData fails" );
2043 if (bIsClip)
2044 return;
2046 if (!pClipDoc)
2048 OSL_TRACE("CopyToClip: no ClipDoc");
2049 pClipDoc = SC_MOD()->GetClipDoc();
2052 if (pShell->GetMedium())
2054 pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
2055 // for unsaved files use the title name and adjust during save of file
2056 if (pClipDoc->maFileURL.isEmpty())
2057 pClipDoc->maFileURL = pShell->GetName();
2059 else
2061 pClipDoc->maFileURL = pShell->GetName();
2064 //init maTabNames
2065 for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
2067 if( *itr )
2069 OUString aTabName;
2070 (*itr)->GetName(aTabName);
2071 pClipDoc->maTabNames.push_back(aTabName);
2073 else
2074 pClipDoc->maTabNames.push_back(OUString());
2077 pClipDoc->aDocName = aDocName;
2078 pClipDoc->SetClipParam(rClipParam);
2079 ScRange aClipRange = rClipParam.getWholeRange();
2080 SCTAB nTab = aClipRange.aStart.Tab();
2081 SCTAB i = 0;
2082 SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
2084 if ( bUseRangeForVBA )
2086 pClipDoc->ResetClip( this, nTab );
2087 i = nTab;
2088 nEndTab = nTab + 1;
2090 else
2091 pClipDoc->ResetClip(this, pMarks);
2093 sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags, bCloneNoteCaptions);
2094 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
2096 for ( ; i < nEndTab; ++i)
2098 if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
2099 continue;
2101 if ( !bUseRangeForVBA && ( pMarks && !pMarks->GetTableSelect(i) ) )
2102 continue;
2104 maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i]);
2106 if (pDrawLayer && bIncludeObjects)
2108 // also copy drawing objects
2109 Rectangle aObjRect = GetMMRect(
2110 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
2111 pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
2115 // Make sure to mark overlapped cells.
2116 pClipDoc->ExtendMerge(aClipRange, true);
2119 void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument* pDestDoc)
2121 if (!pDestDoc)
2122 return;
2124 ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()] : NULL;
2125 ScTable* pDestTab = nDestTab < static_cast<SCTAB>(pDestDoc->maTabs.size()) ? pDestDoc->maTabs[nDestTab] : NULL;
2127 if (!pSrcTab || !pDestTab)
2128 return;
2130 pSrcTab->CopyStaticToDocument(
2131 rSrcRange.aStart.Col(), rSrcRange.aStart.Row(), rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(), pDestTab);
2134 void ScDocument::CopyCellToDocument( const ScAddress& rSrcPos, const ScAddress& rDestPos, ScDocument& rDestDoc )
2136 if (!TableExists(rSrcPos.Tab()) || !rDestDoc.TableExists(rDestPos.Tab()))
2137 return;
2139 ScTable& rSrcTab = *maTabs[rSrcPos.Tab()];
2140 ScTable& rDestTab = *rDestDoc.maTabs[rDestPos.Tab()];
2142 rSrcTab.CopyCellToDocument(rSrcPos.Col(), rSrcPos.Row(), rDestPos.Col(), rDestPos.Row(), rDestTab);
2145 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
2146 SCCOL nCol2, SCROW nRow2,
2147 SCTAB nTab, ScDocument* pClipDoc)
2149 if (!bIsClip)
2151 if (pShell->GetMedium())
2153 pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
2154 // for unsaved files use the title name and adjust during save of file
2155 if (pClipDoc->maFileURL.isEmpty())
2156 pClipDoc->maFileURL = pShell->GetName();
2158 else
2160 pClipDoc->maFileURL = pShell->GetName();
2163 //init maTabNames
2164 for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
2166 if( *itr )
2168 OUString aTabName;
2169 (*itr)->GetName(aTabName);
2170 pClipDoc->maTabNames.push_back(aTabName);
2172 else
2173 pClipDoc->maTabNames.push_back(OUString());
2176 PutInOrder( nCol1, nCol2 );
2177 PutInOrder( nRow1, nRow2 );
2178 if (!pClipDoc)
2180 OSL_TRACE("CopyTabToClip: no ClipDoc");
2181 pClipDoc = SC_MOD()->GetClipDoc();
2184 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2185 pClipDoc->aDocName = aDocName;
2186 rClipParam.maRanges.RemoveAll();
2187 rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
2188 pClipDoc->ResetClip( this, nTab );
2190 sc::CopyToClipContext aCxt(*pClipDoc, false, true);
2191 if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
2192 if (maTabs[nTab] && pClipDoc->maTabs[nTab])
2193 maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab]);
2195 pClipDoc->GetClipParam().mbCutMode = false;
2200 void ScDocument::TransposeClip( ScDocument* pTransClip, sal_uInt16 nFlags, bool bAsLink )
2202 OSL_ENSURE( bIsClip && pTransClip && pTransClip->bIsClip,
2203 "TransposeClip with wrong Document" );
2205 // initialisieren
2206 // -> pTransClip muss vor dem Original-Dokument geloescht werden!
2208 pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
2210 // Bereiche uebernehmen
2212 if (pRangeName)
2214 pTransClip->GetRangeName()->clear();
2215 ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
2216 for (; itr != itrEnd; ++itr)
2218 sal_uInt16 nIndex = itr->second->GetIndex();
2219 ScRangeData* pData = new ScRangeData(*itr->second);
2220 if (pTransClip->pRangeName->insert(pData))
2221 pData->SetIndex(nIndex);
2225 // The data
2227 ScRange aClipRange = GetClipParam().getWholeRange();
2228 if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
2230 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
2231 if (maTabs[i])
2233 OSL_ENSURE( pTransClip->maTabs[i], "TransposeClip: Table not there" );
2234 maTabs[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2235 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
2236 pTransClip->maTabs[i], nFlags, bAsLink );
2238 if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
2240 // Drawing objects are copied to the new area without transposing.
2241 // CopyFromClip is used to adjust the objects to the transposed block's
2242 // cell range area.
2243 // (pDrawLayer in the original clipboard document is set only if there
2244 // are drawing objects to copy)
2246 pTransClip->InitDrawLayer();
2247 Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2248 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
2249 Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
2250 static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
2251 static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
2252 pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
2256 pTransClip->SetClipParam(GetClipParam());
2257 pTransClip->GetClipParam().transpose();
2259 else
2261 OSL_TRACE("TransposeClip: Too big");
2264 // Dies passiert erst beim Einfuegen...
2266 GetClipParam().mbCutMode = false;
2269 namespace {
2271 void copyUsedNamesToClip(ScRangeName* pClipRangeName, ScRangeName* pRangeName, const std::set<sal_uInt16>& rUsedNames)
2273 pClipRangeName->clear();
2274 ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
2275 for (; itr != itrEnd; ++itr) //! DB-Bereiche Pivot-Bereiche auch !!!
2277 sal_uInt16 nIndex = itr->second->GetIndex();
2278 bool bInUse = (rUsedNames.count(nIndex) > 0);
2279 if (!bInUse)
2280 continue;
2282 ScRangeData* pData = new ScRangeData(*itr->second);
2283 if (pClipRangeName->insert(pData))
2284 pData->SetIndex(nIndex);
2290 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
2292 if (!pRangeName || pRangeName->empty())
2293 return;
2295 std::set<sal_uInt16> aUsedNames; // indexes of named ranges that are used in the copied cells
2296 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pClipDoc->maTabs.size()));
2297 for (SCTAB i = 0; i < nMinSizeBothTabs; ++i)
2298 if (maTabs[i] && pClipDoc->maTabs[i])
2299 if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
2300 maTabs[i]->FindRangeNamesInUse(
2301 rClipRange.aStart.Col(), rClipRange.aStart.Row(),
2302 rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
2304 copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName, aUsedNames);
2307 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
2308 mpDoc(pDoc)
2310 mpDoc->MergeNumberFormatter(pSrcDoc);
2313 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
2315 mpDoc->pFormatExchangeList = NULL;
2318 void ScDocument::CellContentModified()
2320 mpFormulaGroupCxt.reset();
2323 SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos )
2325 ScTable* pTab = FetchTable(rPos.Tab());
2326 if (!pTab)
2327 return NULL;
2329 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2332 const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
2334 const ScTable* pTab = FetchTable(rPos.Tab());
2335 if (!pTab)
2336 return NULL;
2338 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2341 void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength )
2343 ScTable* pTab = FetchTable(rTopPos.Tab());
2344 if (!pTab || nLength <= 0)
2345 return;
2347 pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
2350 bool ScDocument::HasBroadcaster( SCTAB nTab, SCCOL nCol ) const
2352 const ScTable* pTab = FetchTable(nTab);
2353 if (!pTab)
2354 return false;
2356 return pTab->HasBroadcaster(nCol);
2359 #if DEBUG_COLUMN_STORAGE
2360 void ScDocument::DumpFormulaGroups( SCTAB nTab, SCCOL nCol ) const
2362 const ScTable* pTab = FetchTable(nTab);
2363 if (!pTab)
2364 return;
2366 pTab->DumpFormulaGroups(nCol);
2368 #endif
2370 bool ScDocument::TableExists( SCTAB nTab ) const
2372 return ValidTab(nTab) && static_cast<size_t>(nTab) < maTabs.size() && maTabs[nTab];
2375 ScTable* ScDocument::FetchTable( SCTAB nTab )
2377 if (!TableExists(nTab))
2378 return NULL;
2380 return maTabs[nTab];
2383 const ScTable* ScDocument::FetchTable( SCTAB nTab ) const
2385 if (!TableExists(nTab))
2386 return NULL;
2388 return maTabs[nTab];
2391 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
2393 SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
2394 SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
2395 if (pOtherFormatter && pOtherFormatter != pThisFormatter)
2397 SvNumberFormatterIndexTable* pExchangeList =
2398 pThisFormatter->MergeFormatter(*(pOtherFormatter));
2399 if (!pExchangeList->empty())
2400 pFormatExchangeList = pExchangeList;
2404 ScClipParam& ScDocument::GetClipParam()
2406 if (!mpClipParam.get())
2407 mpClipParam.reset(new ScClipParam);
2409 return *mpClipParam;
2412 void ScDocument::SetClipParam(const ScClipParam& rParam)
2414 mpClipParam.reset(new ScClipParam(rParam));
2417 bool ScDocument::IsClipboardSource() const
2419 ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
2420 return pClipDoc && pClipDoc->xPoolHelper.is() &&
2421 xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
2425 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
2426 SCCOL nCol2, SCROW nRow2,
2427 const ScMarkData& rMark, sal_uInt16 nInsFlag )
2429 if (nInsFlag & IDF_CONTENTS)
2431 sc::StartListeningContext aCxt(*this);
2432 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2433 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
2434 for (; itr != itrEnd && *itr < nMax; ++itr)
2435 if (maTabs[*itr])
2436 maTabs[*itr]->StartListeningInArea(aCxt, nCol1, nRow1, nCol2, nRow2);
2441 void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
2442 SCCOL nCol2, SCROW nRow2,
2443 const ScMarkData& rMark, sal_uInt16 nInsFlag )
2445 if (nInsFlag & IDF_CONTENTS)
2447 ScBulkBroadcast aBulkBroadcast( GetBASM());
2448 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2449 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
2450 for (; itr != itrEnd && *itr < nMax; ++itr)
2451 if (maTabs[*itr])
2452 maTabs[*itr]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
2456 bool ScDocument::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCTAB nTab, SCCOL nCol )
2458 if (!TableExists(nTab))
2459 return false;
2461 return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
2464 void ScDocument::CopyBlockFromClip(
2465 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2466 const ScMarkData& rMark, SCsCOL nDx, SCsROW nDy )
2468 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2469 SCTAB nTabEnd = rCxt.getTabEnd();
2470 SCTAB nClipTab = 0;
2471 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2473 if (maTabs[i] && rMark.GetTableSelect(i) )
2475 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2477 maTabs[i]->CopyFromClip(
2478 rCxt, nCol1, nRow1, nCol2, nRow2, nDx, nDy, rClipTabs[nClipTab]);
2480 if (rCxt.getClipDoc()->pDrawLayer && (rCxt.getInsertFlag() & IDF_OBJECTS))
2482 // also copy drawing objects
2484 // drawing layer must be created before calling CopyFromClip
2485 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
2486 OSL_ENSURE( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
2487 if ( pDrawLayer )
2489 // For GetMMRect, the row heights in the target document must already be valid
2490 // (copied in an extra step before pasting, or updated after pasting cells, but
2491 // before pasting objects).
2493 Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
2494 nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
2495 Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
2496 pDrawLayer->CopyFromClip(rCxt.getClipDoc()->pDrawLayer, nClipTab, aSourceRect,
2497 ScAddress( nCol1, nRow1, i ), aDestRect );
2501 nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2504 if (rCxt.getInsertFlag() & IDF_CONTENTS)
2506 nClipTab = 0;
2507 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2509 if (maTabs[i] && rMark.GetTableSelect(i) )
2511 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
2512 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
2514 // ranges of consecutive selected tables (in clipboard and dest. doc)
2515 // must be handled in one UpdateReference call
2516 SCTAB nFollow = 0;
2517 while ( i + nFollow < nTabEnd
2518 && rMark.GetTableSelect( i + nFollow + 1 )
2519 && nClipTab + nFollow < MAXTAB
2520 && rClipTabs[(nClipTab + nFollow + 1) % static_cast<SCTAB>(rClipTabs.size())] )
2521 ++nFollow;
2523 sc::RefUpdateContext aRefCxt(*this);
2524 aRefCxt.maRange = ScRange(nCol1, nRow1, i, nCol2, nRow2, i+nFollow);
2525 aRefCxt.mnColDelta = nDx;
2526 aRefCxt.mnRowDelta = nDy;
2527 aRefCxt.mnTabDelta = nDz;
2528 if (rCxt.getClipDoc()->GetClipParam().mbCutMode)
2530 bool bOldInserting = IsInsertingFromOtherDoc();
2531 SetInsertingFromOtherDoc( true);
2532 aRefCxt.meMode = URM_MOVE;
2533 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2534 SetInsertingFromOtherDoc( bOldInserting);
2536 else
2538 aRefCxt.meMode = URM_COPY;
2539 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2542 nClipTab = (nClipTab+nFollow+1) % (static_cast<SCTAB>(rClipTabs.size()));
2543 i = sal::static_int_cast<SCTAB>( i + nFollow );
2550 void ScDocument::CopyNonFilteredFromClip(
2551 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2552 const ScMarkData& rMark, SCsCOL nDx, SCROW & rClipStartRow )
2554 // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2555 // nCol1/nRow1 etc. is in target doc
2557 // filtered state is taken from first used table in clipboard (as in GetClipArea)
2558 SCTAB nFlagTab = 0;
2559 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2560 while ( nFlagTab < static_cast<SCTAB>(rClipTabs.size()) && !rClipTabs[nFlagTab] )
2561 ++nFlagTab;
2563 SCROW nSourceRow = rClipStartRow;
2564 SCROW nSourceEnd = 0;
2565 if (!rCxt.getClipDoc()->GetClipParam().maRanges.empty())
2566 nSourceEnd = rCxt.getClipDoc()->GetClipParam().maRanges.front()->aEnd.Row();
2567 SCROW nDestRow = nRow1;
2569 while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2571 // skip filtered rows
2572 nSourceRow = rCxt.getClipDoc()->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2574 if ( nSourceRow <= nSourceEnd )
2576 // look for more non-filtered rows following
2577 SCROW nLastRow = nSourceRow;
2578 rCxt.getClipDoc()->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2579 SCROW nFollow = nLastRow - nSourceRow;
2581 if (nFollow > nSourceEnd - nSourceRow)
2582 nFollow = nSourceEnd - nSourceRow;
2583 if (nFollow > nRow2 - nDestRow)
2584 nFollow = nRow2 - nDestRow;
2586 SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2587 CopyBlockFromClip(
2588 rCxt, nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy);
2590 nSourceRow += nFollow + 1;
2591 nDestRow += nFollow + 1;
2594 rClipStartRow = nSourceRow;
2598 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2599 sal_uInt16 nInsFlag,
2600 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
2601 bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
2602 const ScRangeList * pDestRanges )
2604 if (bIsClip)
2605 return;
2607 if (!pClipDoc)
2609 OSL_FAIL("CopyFromClip: no ClipDoc");
2610 pClipDoc = SC_MOD()->GetClipDoc();
2613 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2614 return;
2616 bool bOldAutoCalc = GetAutoCalc();
2617 SetAutoCalc( false ); // avoid multiple recalculations
2619 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2621 SCCOL nAllCol1 = rDestRange.aStart.Col();
2622 SCROW nAllRow1 = rDestRange.aStart.Row();
2623 SCCOL nAllCol2 = rDestRange.aEnd.Col();
2624 SCROW nAllRow2 = rDestRange.aEnd.Row();
2626 SCCOL nXw = 0;
2627 SCROW nYw = 0;
2628 ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2629 for (SCTAB nTab = 0; nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
2630 if (pClipDoc->maTabs[nTab]) // all sheets of the clipboard content
2632 SCCOL nThisEndX = aClipRange.aEnd.Col();
2633 SCROW nThisEndY = aClipRange.aEnd.Row();
2634 pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2635 aClipRange.aStart.Row(),
2636 nThisEndX, nThisEndY, nTab );
2637 // only extra value from ExtendMerge
2638 nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2639 nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2640 if ( nThisEndX > nXw )
2641 nXw = nThisEndX;
2642 if ( nThisEndY > nYw )
2643 nYw = nThisEndY;
2646 SCCOL nDestAddX;
2647 SCROW nDestAddY;
2648 pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2649 nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2650 nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2652 /* Decide which contents to delete before copying. Delete all
2653 contents if nInsFlag contains any real content flag.
2654 #i102056# Notes are pasted from clipboard in a second pass,
2655 together with the special flag IDF_ADDNOTES that states to not
2656 overwrite/delete existing cells but to insert the notes into
2657 these cells. In this case, just delete old notes from the
2658 destination area. */
2659 sal_uInt16 nDelFlag = IDF_NONE;
2660 if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2661 nDelFlag |= IDF_NOTE;
2662 else if ( nInsFlag & IDF_CONTENTS )
2663 nDelFlag |= IDF_CONTENTS;
2664 // With bSkipAttrForEmpty, don't remove attributes, copy
2665 // on top of existing attributes instead.
2666 if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2667 nDelFlag |= IDF_ATTRIB;
2669 sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2670 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2671 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2673 ScRangeList aLocalRangeList;
2674 if (!pDestRanges)
2676 aLocalRangeList.Append( rDestRange);
2677 pDestRanges = &aLocalRangeList;
2680 bInsertingFromOtherDoc = true; // kein Broadcast/Listener aufbauen bei Insert
2682 SCCOL nClipStartCol = aClipRange.aStart.Col();
2683 SCROW nClipStartRow = aClipRange.aStart.Row();
2684 SCROW nClipEndRow = aClipRange.aEnd.Row();
2685 for ( size_t nRange = 0; nRange < pDestRanges->size(); ++nRange )
2687 const ScRange* pRange = (*pDestRanges)[nRange];
2688 SCCOL nCol1 = pRange->aStart.Col();
2689 SCROW nRow1 = pRange->aStart.Row();
2690 SCCOL nCol2 = pRange->aEnd.Col();
2691 SCROW nRow2 = pRange->aEnd.Row();
2693 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2695 SCCOL nC1 = nCol1;
2696 SCROW nR1 = nRow1;
2697 SCCOL nC2 = nC1 + nXw;
2698 if (nC2 > nCol2)
2699 nC2 = nCol2;
2700 SCROW nR2 = nR1 + nYw;
2701 if (nR2 > nRow2)
2702 nR2 = nRow2;
2706 // Pasting is done column-wise, when pasting to a filtered
2707 // area this results in partitioning and we have to
2708 // remember and reset the start row for each column until
2709 // it can be advanced for the next chunk of unfiltered
2710 // rows.
2711 SCROW nSaveClipStartRow = nClipStartRow;
2714 nClipStartRow = nSaveClipStartRow;
2715 SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2716 SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2717 if ( bIncludeFiltered )
2719 CopyBlockFromClip(
2720 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nDy);
2721 nClipStartRow += nR2 - nR1 + 1;
2723 else
2725 CopyNonFilteredFromClip(
2726 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nClipStartRow);
2728 nC1 = nC2 + 1;
2729 nC2 = std::min((SCCOL)(nC1 + nXw), nCol2);
2730 } while (nC1 <= nCol2);
2731 if (nClipStartRow > nClipEndRow)
2732 nClipStartRow = aClipRange.aStart.Row();
2733 nC1 = nCol1;
2734 nC2 = nC1 + nXw;
2735 if (nC2 > nCol2)
2736 nC2 = nCol2;
2737 nR1 = nR2 + 1;
2738 nR2 = std::min((SCROW)(nR1 + nYw), nRow2);
2739 } while (nR1 <= nRow2);
2742 bInsertingFromOtherDoc = false;
2744 // Listener aufbauen nachdem alles inserted wurde
2745 StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2746 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2747 BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2748 if (bResetCut)
2749 pClipDoc->GetClipParam().mbCutMode = false;
2750 SetAutoCalc( bOldAutoCalc );
2753 static SCROW lcl_getLastNonFilteredRow(
2754 const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
2755 SCROW nRowCount)
2757 SCROW nFilteredRow = rFlags.GetFirstForCondition(
2758 nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
2760 SCROW nRow = nFilteredRow - 1;
2761 if (nRow - nBegRow + 1 > nRowCount)
2762 // make sure the row range stays within the data size.
2763 nRow = nBegRow + nRowCount - 1;
2765 return nRow;
2768 void ScDocument::CopyMultiRangeFromClip(
2769 const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2770 bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2772 if (bIsClip)
2773 return;
2775 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2776 // There is nothing in the clip doc to copy.
2777 return;
2779 bool bOldAutoCalc = GetAutoCalc();
2780 SetAutoCalc( false ); // avoid multiple recalculations
2782 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2784 SCCOL nCol1 = rDestPos.Col();
2785 SCROW nRow1 = rDestPos.Row();
2786 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2788 sc::CopyFromClipContext aCxt(*this, NULL, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2789 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2790 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2792 ScRange aDestRange;
2793 rMark.GetMarkArea(aDestRange);
2794 SCROW nLastMarkedRow = aDestRange.aEnd.Row();
2796 bInsertingFromOtherDoc = true; // kein Broadcast/Listener aufbauen bei Insert
2798 SCROW nBegRow = nRow1;
2799 sal_uInt16 nDelFlag = IDF_CONTENTS;
2800 const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCxt.getTabStart());
2802 for ( size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i )
2804 ScRange* p = rClipParam.maRanges[ i ];
2805 // The begin row must not be filtered.
2807 SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2809 SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2810 SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
2811 SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2813 SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2815 if (!bSkipAttrForEmpty)
2816 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2818 CopyBlockFromClip(aCxt, nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy);
2819 nRowCount -= nEndRow - nBegRow + 1;
2821 while (nRowCount > 0)
2823 // Get the first non-filtered row.
2824 SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2825 if (nNonFilteredRow > nLastMarkedRow)
2826 return;
2828 SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
2829 nDy += nRowsSkipped;
2831 nBegRow = nNonFilteredRow;
2832 nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2834 if (!bSkipAttrForEmpty)
2835 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2837 CopyBlockFromClip(aCxt, nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy);
2838 nRowCount -= nEndRow - nBegRow + 1;
2841 if (rClipParam.meDirection == ScClipParam::Row)
2842 // Begin row for the next range being pasted.
2843 nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2844 else
2845 nBegRow = nRow1;
2847 if (rClipParam.meDirection == ScClipParam::Column)
2848 nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2851 bInsertingFromOtherDoc = false;
2853 ScRangeList aRanges;
2854 aRanges.Append(aDestRange);
2856 // Listener aufbauen nachdem alles inserted wurde
2857 StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2858 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2859 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2860 BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2861 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2863 if (bResetCut)
2864 pClipDoc->GetClipParam().mbCutMode = false;
2865 SetAutoCalc( bOldAutoCalc );
2868 void ScDocument::SetClipArea( const ScRange& rArea, bool bCut )
2870 if (bIsClip)
2872 ScClipParam& rClipParam = GetClipParam();
2873 rClipParam.maRanges.RemoveAll();
2874 rClipParam.maRanges.Append(rArea);
2875 rClipParam.mbCutMode = bCut;
2877 else
2879 OSL_FAIL("SetClipArea: No Clip");
2884 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered)
2886 if (!bIsClip)
2888 OSL_FAIL("GetClipArea: No Clip");
2889 return;
2892 ScRangeList& rClipRanges = GetClipParam().maRanges;
2893 if (rClipRanges.empty())
2894 // No clip range. Bail out.
2895 return;
2897 ScRange* p = rClipRanges.front();
2898 SCCOL nStartCol = p->aStart.Col();
2899 SCCOL nEndCol = p->aEnd.Col();
2900 SCROW nStartRow = p->aStart.Row();
2901 SCROW nEndRow = p->aEnd.Row();
2902 for ( size_t i = 1, n = rClipRanges.size(); i < n; ++i )
2904 p = rClipRanges[ i ];
2905 if (p->aStart.Col() < nStartCol)
2906 nStartCol = p->aStart.Col();
2907 if (p->aStart.Row() < nStartRow)
2908 nStartRow = p->aStart.Row();
2909 if (p->aEnd.Col() > nEndCol)
2910 nEndCol = p->aEnd.Col();
2911 if (p->aEnd.Row() < nEndRow)
2912 nEndRow = p->aEnd.Row();
2915 nClipX = nEndCol - nStartCol;
2917 if ( bIncludeFiltered )
2918 nClipY = nEndRow - nStartRow;
2919 else
2921 // count non-filtered rows
2922 // count on first used table in clipboard
2923 SCTAB nCountTab = 0;
2924 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
2925 ++nCountTab;
2927 SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
2929 if ( nResult > 0 )
2930 nClipY = nResult - 1;
2931 else
2932 nClipY = 0; // always return at least 1 row
2937 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2939 if (bIsClip)
2941 ScRangeList& rClipRanges = GetClipParam().maRanges;
2942 if ( !rClipRanges.empty() )
2944 nClipX = rClipRanges.front()->aStart.Col();
2945 nClipY = rClipRanges.front()->aStart.Row();
2948 else
2950 OSL_FAIL("GetClipStart: No Clip");
2955 bool ScDocument::HasClipFilteredRows()
2957 // count on first used table in clipboard
2958 SCTAB nCountTab = 0;
2959 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
2960 ++nCountTab;
2962 ScRangeList& rClipRanges = GetClipParam().maRanges;
2963 if ( rClipRanges.empty() )
2964 return false;
2966 for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
2968 ScRange* p = rClipRanges[ i ];
2969 bool bAnswer = maTabs[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
2970 if (bAnswer)
2971 return true;
2973 return false;
2977 void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, bool bSkipEmpty,
2978 ScDocument* pSrcDoc )
2980 SCTAB nTab1 = rRange.aStart.Tab();
2981 SCTAB nTab2 = rRange.aEnd.Tab();
2982 sc::MixDocContext aCxt(*this);
2983 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pSrcDoc->maTabs.size()));
2984 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
2986 ScTable* pTab = FetchTable(i);
2987 const ScTable* pSrcTab = pSrcDoc->FetchTable(i);
2988 if (!pTab || !pSrcTab)
2989 continue;
2991 pTab->MixData(
2992 aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
2993 nFunction, bSkipEmpty, pSrcTab);
2998 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2999 sal_uInt16 nFlags, sal_uInt16 nFunction,
3000 bool bSkipEmpty, bool bAsLink )
3002 sal_uInt16 nDelFlags = nFlags;
3003 if (nDelFlags & IDF_CONTENTS)
3004 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
3006 SCTAB nSrcTab = rSrcArea.aStart.Tab();
3008 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3010 SCCOL nStartCol = rSrcArea.aStart.Col();
3011 SCROW nStartRow = rSrcArea.aStart.Row();
3012 SCCOL nEndCol = rSrcArea.aEnd.Col();
3013 SCROW nEndRow = rSrcArea.aEnd.Row();
3014 boost::scoped_ptr<ScDocument> pMixDoc;
3015 bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
3017 bool bOldAutoCalc = GetAutoCalc();
3018 SetAutoCalc( false ); // avoid multiple calculations
3020 sc::CopyToDocContext aCxt(*this);
3021 sc::MixDocContext aMixDocCxt(*this);
3023 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3024 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
3025 for (; itr != itrEnd && *itr < nCount; ++itr)
3026 if ( *itr!=nSrcTab && maTabs[*itr])
3028 SCTAB i = *itr;
3029 if (bDoMix)
3031 if (!pMixDoc)
3033 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3034 pMixDoc->InitUndo( this, i, i );
3036 else
3037 pMixDoc->AddUndoTab( i, i );
3039 // context used for copying content to the temporary mix document.
3040 sc::CopyToDocContext aMixCxt(*pMixDoc);
3041 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3042 IDF_CONTENTS, false, pMixDoc->maTabs[i] );
3044 maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
3045 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3046 nFlags, false, maTabs[i], NULL, bAsLink );
3048 if (bDoMix)
3049 maTabs[i]->MixData(aMixDocCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3050 nFunction, bSkipEmpty, pMixDoc->maTabs[i] );
3053 SetAutoCalc( bOldAutoCalc );
3055 else
3057 OSL_FAIL("wrong table");
3062 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
3063 sal_uInt16 nFlags, sal_uInt16 nFunction,
3064 bool bSkipEmpty, bool bAsLink )
3066 sal_uInt16 nDelFlags = nFlags;
3067 if (nDelFlags & IDF_CONTENTS)
3068 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
3070 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3072 boost::scoped_ptr<ScDocument> pMixDoc;
3073 bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
3075 bool bOldAutoCalc = GetAutoCalc();
3076 SetAutoCalc( false ); // avoid multiple calculations
3078 ScRange aArea;
3079 rMark.GetMultiMarkArea( aArea );
3080 SCCOL nStartCol = aArea.aStart.Col();
3081 SCROW nStartRow = aArea.aStart.Row();
3082 SCCOL nEndCol = aArea.aEnd.Col();
3083 SCROW nEndRow = aArea.aEnd.Row();
3085 sc::CopyToDocContext aCxt(*this);
3086 sc::MixDocContext aMixDocCxt(*this);
3087 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3088 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
3089 for (; itr != itrEnd && *itr < nCount; ++itr)
3090 if ( *itr!=nSrcTab && maTabs[*itr] )
3092 SCTAB i = *itr;
3093 if (bDoMix)
3095 if (!pMixDoc)
3097 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3098 pMixDoc->InitUndo( this, i, i );
3100 else
3101 pMixDoc->AddUndoTab( i, i );
3103 sc::CopyToDocContext aMixCxt(*pMixDoc);
3104 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3105 IDF_CONTENTS, true, pMixDoc->maTabs[i], &rMark );
3108 maTabs[i]->DeleteSelection( nDelFlags, rMark );
3109 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3110 nFlags, true, maTabs[i], &rMark, bAsLink );
3112 if (bDoMix)
3113 maTabs[i]->MixMarked(aMixDocCxt, rMark, nFunction, bSkipEmpty, pMixDoc->maTabs[i]);
3116 SetAutoCalc( bOldAutoCalc );
3118 else
3120 OSL_FAIL("wrong table");
3125 bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
3126 ScSetStringParam* pParam )
3128 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3129 return maTabs[nTab]->SetString( nCol, nRow, nTab, rString, pParam );
3130 else
3131 return false;
3134 bool ScDocument::SetString(
3135 const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam )
3137 return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam);
3140 void ScDocument::SetEditText( const ScAddress& rPos, EditTextObject* pEditText )
3142 if (!TableExists(rPos.Tab()))
3144 delete pEditText;
3145 return;
3148 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), pEditText);
3151 void ScDocument::SetEditText( const ScAddress& rPos, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
3153 if (!TableExists(rPos.Tab()))
3154 return;
3156 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
3159 void ScDocument::SetEditText( const ScAddress& rPos, const OUString& rStr )
3161 if (!TableExists(rPos.Tab()))
3162 return;
3164 ScFieldEditEngine& rEngine = GetEditEngine();
3165 rEngine.SetText(rStr);
3166 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3169 void ScDocument::SetTextCell( const ScAddress& rPos, const OUString& rStr )
3171 if (!TableExists(rPos.Tab()))
3172 return;
3174 if (ScStringUtil::isMultiline(rStr))
3176 ScFieldEditEngine& rEngine = GetEditEngine();
3177 rEngine.SetText(rStr);
3178 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3180 else
3182 ScSetStringParam aParam;
3183 aParam.setTextInput();
3184 maTabs[rPos.Tab()]->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
3188 void ScDocument::SetEmptyCell( const ScAddress& rPos )
3190 if (!TableExists(rPos.Tab()))
3191 return;
3193 maTabs[rPos.Tab()]->SetEmptyCell(rPos.Col(), rPos.Row());
3196 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
3198 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
3199 if (maTabs[nTab])
3200 maTabs[nTab]->SetValue( nCol, nRow, rVal );
3203 void ScDocument::SetValue( const ScAddress& rPos, double fVal )
3205 if (!TableExists(rPos.Tab()))
3206 return;
3208 maTabs[rPos.Tab()]->SetValue(rPos.Col(), rPos.Row(), fVal);
3211 OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3213 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3215 OUString aStr;
3216 maTabs[nTab]->GetString(nCol, nRow, aStr);
3217 return aStr;
3219 else
3220 return EMPTY_OUSTRING;
3223 OUString ScDocument::GetString( const ScAddress& rPos ) const
3225 if (!TableExists(rPos.Tab()))
3226 return EMPTY_OUSTRING;
3228 OUString aStr;
3229 maTabs[rPos.Tab()]->GetString(rPos.Col(), rPos.Row(), aStr);
3230 return aStr;
3233 double* ScDocument::GetValueCell( const ScAddress& rPos )
3235 if (!TableExists(rPos.Tab()))
3236 return NULL;
3238 return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
3241 svl::SharedString ScDocument::GetSharedString( const ScAddress& rPos ) const
3243 if (!TableExists(rPos.Tab()))
3244 return svl::SharedString();
3246 return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
3249 sc::FormulaGroupContext& ScDocument::GetFormulaGroupContext()
3251 if (!mpFormulaGroupCxt)
3252 mpFormulaGroupCxt.reset(new sc::FormulaGroupContext);
3254 return *mpFormulaGroupCxt;
3257 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
3259 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3260 maTabs[nTab]->GetInputString( nCol, nRow, rString );
3261 else
3262 rString = OUString();
3265 sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& rString )
3267 // Used in formulas (add-in parameters etc), so it must use the same semantics as
3268 // ScInterpreter::GetCellString: always format values as numbers.
3269 // The return value is the error code.
3271 ScRefCellValue aCell;
3272 aCell.assign(*this, rPos);
3273 if (aCell.isEmpty())
3275 rString = EMPTY_OUSTRING;
3276 return 0;
3279 sal_uInt16 nErr = 0;
3280 OUString aStr;
3281 SvNumberFormatter* pFormatter = GetFormatTable();
3282 switch (aCell.meType)
3284 case CELLTYPE_STRING:
3285 case CELLTYPE_EDIT:
3286 aStr = aCell.getString(this);
3287 break;
3288 case CELLTYPE_FORMULA:
3290 ScFormulaCell* pFCell = aCell.mpFormula;
3291 nErr = pFCell->GetErrCode();
3292 if (pFCell->IsValue())
3294 double fVal = pFCell->GetValue();
3295 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3296 NUMBERFORMAT_NUMBER,
3297 ScGlobal::eLnge);
3298 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3300 else
3301 aStr = pFCell->GetString().getString();
3303 break;
3304 case CELLTYPE_VALUE:
3306 double fVal = aCell.mfValue;
3307 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3308 NUMBERFORMAT_NUMBER,
3309 ScGlobal::eLnge);
3310 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3312 break;
3313 default:
3317 rString = aStr;
3318 return nErr;
3322 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ) const
3324 if (TableExists(nTab))
3325 rValue = maTabs[nTab]->GetValue( nCol, nRow );
3326 else
3327 rValue = 0.0;
3330 const EditTextObject* ScDocument::GetEditText( const ScAddress& rPos ) const
3332 SCTAB nTab = rPos.Tab();
3333 if (!TableExists(nTab))
3334 return NULL;
3336 return maTabs[nTab]->GetEditText(rPos.Col(), rPos.Row());
3339 void ScDocument::RemoveEditTextCharAttribs( const ScAddress& rPos, const ScPatternAttr& rAttr )
3341 if (!TableExists(rPos.Tab()))
3342 return;
3344 return maTabs[rPos.Tab()]->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
3347 double ScDocument::GetValue( const ScAddress& rPos ) const
3349 SCTAB nTab = rPos.Tab();
3350 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3351 return maTabs[nTab]->GetValue(rPos.Col(), rPos.Row());
3352 return 0.0;
3355 double ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3357 ScAddress aAdr(nCol, nRow, nTab); return GetValue(aAdr);
3360 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
3361 sal_uInt32& rFormat ) const
3363 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
3364 if (maTabs[nTab])
3366 rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
3367 return ;
3369 rFormat = 0;
3372 sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
3374 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
3375 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
3376 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3378 if (!ValidTab(nTab1) || !ValidTab(nTab2) || !maTabs[nTab1] || !maTabs[nTab2])
3379 return 0;
3381 sal_uInt32 nFormat = 0;
3382 bool bFirstItem = true;
3383 for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
3384 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
3386 sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
3387 if (bFirstItem)
3389 nFormat = nThisFormat;
3390 bFirstItem = false;
3392 else if (nThisFormat != nFormat)
3393 return 0;
3396 return nFormat;
3399 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
3401 SCTAB nTab = rPos.Tab();
3402 if ( maTabs[nTab] )
3403 return maTabs[nTab]->GetNumberFormat( rPos );
3404 return 0;
3407 void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
3409 if (!TableExists(rPos.Tab()))
3410 return;
3412 maTabs[rPos.Tab()]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
3415 void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
3416 const ScAddress& rPos ) const
3418 SCTAB nTab = rPos.Tab();
3419 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3421 nIndex = maTabs[nTab]->GetNumberFormat( rPos );
3422 nType = GetFormatTable()->GetType( nIndex );
3424 else
3426 nType = NUMBERFORMAT_UNDEFINED;
3427 nIndex = 0;
3432 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const
3434 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3435 maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
3436 else
3437 rFormula = OUString();
3441 const ScTokenArray* ScDocument::GetFormulaTokens( const ScAddress& rPos ) const
3443 if (!TableExists(rPos.Tab()))
3444 return NULL;
3446 return maTabs[rPos.Tab()]->GetFormulaTokens(rPos.Col(), rPos.Row());
3449 const ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos ) const
3451 if (!TableExists(rPos.Tab()))
3452 return NULL;
3454 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3457 ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos )
3459 if (!TableExists(rPos.Tab()))
3460 return NULL;
3462 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3465 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
3467 SCTAB nTab = rPos.Tab();
3468 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3469 return maTabs[nTab]->GetCellType( rPos );
3470 return CELLTYPE_NONE;
3474 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
3475 CellType& rCellType ) const
3477 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3478 rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
3479 else
3480 rCellType = CELLTYPE_NONE;
3483 bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3485 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3486 return maTabs[nTab]->HasStringData( nCol, nRow );
3487 else
3488 return false;
3492 bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3494 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3495 return maTabs[nTab]->HasValueData( nCol, nRow );
3496 else
3497 return false;
3500 bool ScDocument::HasValueData( const ScAddress& rPos ) const
3502 return HasValueData(rPos.Col(), rPos.Row(), rPos.Tab());
3505 bool ScDocument::HasStringCells( const ScRange& rRange ) const
3507 // true, wenn String- oder Editzellen im Bereich
3509 SCCOL nStartCol = rRange.aStart.Col();
3510 SCROW nStartRow = rRange.aStart.Row();
3511 SCTAB nStartTab = rRange.aStart.Tab();
3512 SCCOL nEndCol = rRange.aEnd.Col();
3513 SCROW nEndRow = rRange.aEnd.Row();
3514 SCTAB nEndTab = rRange.aEnd.Tab();
3516 for ( SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
3517 if ( maTabs[nTab] && maTabs[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
3518 return true;
3520 return false;
3524 bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3526 sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
3527 if( nValidation )
3529 const ScValidationData* pData = GetValidationEntry( nValidation );
3530 if( pData && pData->HasSelectionList() )
3531 return true;
3533 return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
3537 void ScDocument::SetDirty()
3539 bool bOldAutoCalc = GetAutoCalc();
3540 bAutoCalc = false; // keine Mehrfachberechnung
3541 { // scope for bulk broadcast
3542 ScBulkBroadcast aBulkBroadcast( GetBASM());
3543 TableContainer::iterator it = maTabs.begin();
3544 for (;it != maTabs.end(); ++it)
3545 if (*it)
3546 (*it)->SetDirty();
3549 // Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
3550 // wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
3551 // (#45205#) - darum alle Charts nochmal explizit
3552 if (pChartListenerCollection)
3553 pChartListenerCollection->SetDirty();
3555 SetAutoCalc( bOldAutoCalc );
3559 void ScDocument::SetDirty( const ScRange& rRange )
3561 bool bOldAutoCalc = GetAutoCalc();
3562 bAutoCalc = false; // keine Mehrfachberechnung
3563 { // scope for bulk broadcast
3564 ScBulkBroadcast aBulkBroadcast( GetBASM());
3565 SCTAB nTab2 = rRange.aEnd.Tab();
3566 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3567 if (maTabs[i]) maTabs[i]->SetDirty( rRange );
3569 SetAutoCalc( bOldAutoCalc );
3573 void ScDocument::SetTableOpDirty( const ScRange& rRange )
3575 bool bOldAutoCalc = GetAutoCalc();
3576 bAutoCalc = false; // no multiple recalculation
3577 SCTAB nTab2 = rRange.aEnd.Tab();
3578 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3579 if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
3580 SetAutoCalc( bOldAutoCalc );
3583 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3585 if (!GetAutoCalc())
3586 return;
3588 mpFormulaGroupCxt.reset();
3590 for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
3592 const ScRange& rRange = *rRanges[nPos];
3593 for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
3595 ScTable* pTab = FetchTable(nTab);
3596 if (!pTab)
3597 return;
3599 pTab->InterpretDirtyCells(
3600 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3604 mpFormulaGroupCxt.reset();
3608 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3610 if ( !aTableOpList.empty() )
3612 ScInterpreterTableOpParams* p = &aTableOpList.back();
3613 if ( p->bCollectNotifications )
3615 if ( p->bRefresh )
3616 { // refresh pointers only
3617 p->aNotifiedFormulaCells.push_back( pCell );
3619 else
3620 { // init both, address and pointer
3621 p->aNotifiedFormulaCells.push_back( pCell );
3622 p->aNotifiedFormulaPos.push_back( pCell->aPos );
3629 void ScDocument::CalcAll()
3631 ClearLookupCaches(); // Ensure we don't deliver zombie data.
3632 sc::AutoCalcSwitch aSwitch(*this, true);
3633 TableContainer::iterator it = maTabs.begin();
3634 for (; it != maTabs.end(); ++it)
3635 if (*it)
3636 (*it)->SetDirtyVar();
3637 for (it = maTabs.begin(); it != maTabs.end(); ++it)
3638 if (*it)
3639 (*it)->CalcAll();
3640 ClearFormulaTree();
3641 mpFormulaGroupCxt.reset();
3645 void ScDocument::CompileAll()
3647 TableContainer::iterator it = maTabs.begin();
3648 for (; it != maTabs.end(); ++it)
3649 if (*it)
3650 (*it)->CompileAll();
3651 SetDirty();
3655 void ScDocument::CompileXML()
3657 bool bOldAutoCalc = GetAutoCalc();
3658 SetAutoCalc( false );
3659 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3660 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3662 // set AutoNameCache to speed up automatic name lookup
3663 OSL_ENSURE( !pAutoNameCache, "AutoNameCache already set" );
3664 pAutoNameCache = new ScAutoNameCache( this );
3666 if (pRangeName)
3667 pRangeName->CompileUnresolvedXML();
3669 TableContainer::iterator it = maTabs.begin();
3670 for (; it != maTabs.end(); ++it)
3671 if (*it)
3672 (*it)->CompileXML( aProgress );
3674 DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
3676 if ( pValidationList )
3677 pValidationList->CompileXML();
3679 SetAutoCalc( bOldAutoCalc );
3682 bool ScDocument::CompileErrorCells(sal_uInt16 nErrCode)
3684 bool bCompiled = false;
3685 TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
3686 for (; it != itEnd; ++it)
3688 ScTable* pTab = *it;
3689 if (!pTab)
3690 continue;
3692 if (pTab->CompileErrorCells(nErrCode))
3693 bCompiled = true;
3696 return bCompiled;
3699 void ScDocument::CalcAfterLoad()
3701 if (bIsClip) // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3702 return; // dann wird erst beim Einfuegen in das richtige Doc berechnet
3704 bCalcingAfterLoad = true;
3706 TableContainer::iterator it = maTabs.begin();
3707 for (; it != maTabs.end(); ++it)
3708 if (*it)
3709 (*it)->CalcAfterLoad();
3710 for (it = maTabs.begin(); it != maTabs.end(); ++it)
3711 if (*it)
3712 (*it)->SetDirtyAfterLoad();
3714 bCalcingAfterLoad = false;
3716 SetDetectiveDirty(false); // noch keine wirklichen Aenderungen
3718 // #i112436# If formula cells are already dirty, they don't broadcast further changes.
3719 // So the source ranges of charts must be interpreted even if they are not visible,
3720 // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
3721 if (pChartListenerCollection)
3723 const ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners();
3724 ScChartListenerCollection::ListenersType::const_iterator it = rListeners.begin(), itEnd = rListeners.end();
3725 for (; it != itEnd; ++it)
3727 const ScChartListener* p = it->second;
3728 InterpretDirtyCells(*p->GetRangeList());
3734 sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
3736 SCTAB nTab = rPos.Tab();
3737 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3738 return maTabs[nTab]->GetErrCode( rPos );
3739 return 0;
3743 void ScDocument::ResetChanged( const ScRange& rRange )
3745 SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
3746 SCTAB nTab1 = rRange.aStart.Tab();
3747 SCTAB nTab2 = rRange.aEnd.Tab();
3748 for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
3749 if (maTabs[nTab])
3750 maTabs[nTab]->ResetChanged(rRange);
3754 // Spaltenbreiten / Zeilenhoehen --------------------------------------
3758 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3760 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3761 maTabs[nTab]->SetColWidth( nCol, nNewWidth );
3764 void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3766 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3767 maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
3770 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
3772 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3773 maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
3777 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3779 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3780 maTabs[nTab]->SetRowHeightRange
3781 ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3784 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3786 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3787 maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
3790 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
3792 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3793 maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3797 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
3799 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3800 return maTabs[nTab]->GetColWidth( nCol, bHiddenAsZero );
3801 OSL_FAIL("wrong table number");
3802 return 0;
3806 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3808 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3809 return maTabs[nTab]->GetOriginalWidth( nCol );
3810 OSL_FAIL("wrong table number");
3811 return 0;
3815 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3817 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3818 return maTabs[nTab]->GetCommonWidth( nEndCol );
3819 OSL_FAIL("Wrong table number");
3820 return 0;
3824 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3826 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3827 return maTabs[nTab]->GetOriginalHeight( nRow );
3828 OSL_FAIL("Wrong table number");
3829 return 0;
3833 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
3835 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3836 return maTabs[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
3837 OSL_FAIL("Wrong sheet number");
3838 return 0;
3842 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
3844 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3845 return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
3846 OSL_FAIL("Wrong sheet number");
3847 return 0;
3851 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
3853 if (nStartRow == nEndRow)
3854 return GetRowHeight( nStartRow, nTab, bHiddenAsZero ); // faster for a single row
3856 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3857 if (nStartRow > nEndRow)
3858 return 0;
3860 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3861 return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
3863 OSL_FAIL("wrong sheet number");
3864 return 0;
3867 SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
3869 return maTabs[nTab]->GetRowForHeight(nHeight);
3872 sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3873 SCTAB nTab, double fScale ) const
3875 // faster for a single row
3876 if (nStartRow == nEndRow)
3877 return (sal_uLong) (GetRowHeight( nStartRow, nTab) * fScale);
3879 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3880 if (nStartRow > nEndRow)
3881 return 0;
3883 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3884 return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3886 OSL_FAIL("wrong sheet number");
3887 return 0;
3890 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3892 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3893 return maTabs[nTab]->GetHiddenRowCount( nRow );
3894 OSL_FAIL("wrong table number");
3895 return 0;
3899 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
3901 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3902 return maTabs[nTab]->GetColOffset( nCol, bHiddenAsZero );
3903 OSL_FAIL("wrong table number");
3904 return 0;
3908 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
3910 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3911 return maTabs[nTab]->GetRowOffset( nRow, bHiddenAsZero );
3912 OSL_FAIL("wrong table number");
3913 return 0;
3917 sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3918 double nPPTX, double nPPTY,
3919 const Fraction& rZoomX, const Fraction& rZoomY,
3920 bool bFormula, const ScMarkData* pMarkData,
3921 const ScColWidthParam* pParam )
3923 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3924 return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3925 rZoomX, rZoomY, bFormula, pMarkData, pParam );
3926 OSL_FAIL("wrong table number");
3927 return 0;
3931 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3932 OutputDevice* pDev,
3933 double nPPTX, double nPPTY,
3934 const Fraction& rZoomX, const Fraction& rZoomY,
3935 bool bWidth, bool bTotalSize )
3937 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3938 return maTabs[nTab]->GetNeededSize
3939 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3940 OSL_FAIL("wrong table number");
3941 return 0;
3945 bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
3946 OutputDevice* pDev,
3947 double nPPTX, double nPPTY,
3948 const Fraction& rZoomX, const Fraction& rZoomY,
3949 bool bShrink )
3951 //! MarkToMulti();
3952 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3953 return maTabs[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3954 pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3955 OSL_FAIL("wrong table number");
3956 return false;
3960 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3961 const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3963 // one progress across all (selected) sheets
3965 sal_uLong nCellCount = 0;
3966 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
3967 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3968 nCellCount += maTabs[nTab]->GetWeightedCount();
3970 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3972 sal_uLong nProgressStart = 0;
3973 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
3974 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3976 maTabs[nTab]->SetOptimalHeightOnly( 0, MAXROW, 0,
3977 pDev, nPPTX, nPPTY, rZoomX, rZoomY, false, &aProgress, nProgressStart );
3978 maTabs[nTab]->SetDrawPageSize(true, true);
3979 nProgressStart += maTabs[nTab]->GetWeightedCount();
3985 // Spalten-/Zeilen-Flags ----------------------------------------------
3988 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
3990 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3991 maTabs[nTab]->ShowCol( nCol, bShow );
3995 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
3997 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3998 maTabs[nTab]->ShowRow( nRow, bShow );
4002 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
4004 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4005 maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
4009 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
4011 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4012 maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
4016 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
4018 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4019 maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
4023 sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
4025 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4026 return maTabs[nTab]->GetColFlags( nCol );
4027 OSL_FAIL("wrong table number");
4028 return 0;
4031 sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
4033 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4034 return maTabs[nTab]->GetRowFlags( nRow );
4035 OSL_FAIL("wrong table number");
4036 return 0;
4039 const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
4040 SCTAB nTab ) const
4042 const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pFlags;
4043 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4044 pFlags = maTabs[nTab]->GetRowFlagsArray();
4045 else
4047 OSL_FAIL("wrong sheet number");
4048 pFlags = 0;
4050 if (!pFlags)
4052 OSL_FAIL("no row flags at sheet");
4053 static ScBitMaskCompressedArray< SCROW, sal_uInt8> aDummy( MAXROW, 0);
4054 pFlags = &aDummy;
4056 return *pFlags;
4059 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4061 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4062 return;
4063 maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
4066 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4068 if (!ValidTab(nTab) || !maTabs[nTab])
4069 return;
4071 maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
4074 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
4076 ScBreakType nType = BREAK_NONE;
4077 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4078 return nType;
4080 if (maTabs[nTab]->HasRowPageBreak(nRow))
4081 nType |= BREAK_PAGE;
4083 if (maTabs[nTab]->HasRowManualBreak(nRow))
4084 nType |= BREAK_MANUAL;
4086 return nType;
4089 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
4091 ScBreakType nType = BREAK_NONE;
4092 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4093 return nType;
4095 if (maTabs[nTab]->HasColPageBreak(nCol))
4096 nType |= BREAK_PAGE;
4098 if (maTabs[nTab]->HasColManualBreak(nCol))
4099 nType |= BREAK_MANUAL;
4101 return nType;
4104 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4106 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4107 return;
4109 maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
4112 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4114 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4115 return;
4117 maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
4120 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4122 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4123 return;
4125 maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
4128 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4130 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4131 return;
4133 maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
4136 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
4138 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4139 return Sequence<TablePageBreakData>();
4141 return maTabs[nTab]->GetRowBreakData();
4144 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4146 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4147 return false;
4149 return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
4152 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4154 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4155 return false;
4157 return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
4160 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4162 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4164 if (pFirstCol)
4165 *pFirstCol = nCol;
4166 if (pLastCol)
4167 *pLastCol = nCol;
4168 return false;
4171 return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
4174 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
4176 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4177 return;
4179 maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
4182 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
4184 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4185 return;
4187 maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
4190 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4192 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4193 return ::std::numeric_limits<SCROW>::max();;
4195 return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
4198 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4200 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4201 return ::std::numeric_limits<SCROW>::max();;
4203 return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
4206 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4208 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4209 return 0;
4211 return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
4214 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4216 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4217 return false;
4219 return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
4222 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4224 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4225 return false;
4227 return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
4230 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4232 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4233 return false;
4235 return maTabs[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
4238 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
4240 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4241 return;
4243 maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
4247 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4249 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4250 return ::std::numeric_limits<SCROW>::max();;
4252 return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
4255 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4257 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4258 return ::std::numeric_limits<SCROW>::max();;
4260 return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
4263 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4265 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4266 return 0;
4268 return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
4271 bool ScDocument::IsManualRowHeight(SCROW nRow, SCTAB nTab) const
4273 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4274 return false;
4276 return maTabs[nTab]->IsManualRowHeight(nRow);
4279 void ScDocument::SyncColRowFlags()
4281 TableContainer::iterator it = maTabs.begin();
4282 for (; it != maTabs.end(); ++it)
4284 if (*it)
4285 (*it)->SyncColRowFlags();
4289 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
4291 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4292 return maTabs[nTab]->GetLastFlaggedRow();
4293 return 0;
4297 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
4299 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4300 return maTabs[nTab]->GetLastChangedCol();
4301 return 0;
4304 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
4306 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4307 return maTabs[nTab]->GetLastChangedRow();
4308 return 0;
4312 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
4314 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4316 sal_uInt8 nStartFlags = maTabs[nTab]->GetColFlags(nStart);
4317 sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
4318 for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
4320 if (((nStartFlags & CR_MANUALBREAK) != (maTabs[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
4321 (nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
4322 ((nStartFlags & CR_HIDDEN) != (maTabs[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
4323 return nCol;
4325 return MAXCOL+1;
4327 return 0;
4330 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
4332 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4333 return 0;
4335 const ScBitMaskCompressedArray<SCROW, sal_uInt8>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
4336 if (!pRowFlagsArray)
4337 return 0;
4339 if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
4340 return 0;
4342 size_t nIndex; // ignored
4343 SCROW nFlagsEndRow;
4344 SCROW nHiddenEndRow;
4345 SCROW nHeightEndRow;
4346 sal_uInt8 nFlags;
4347 bool bHidden;
4348 sal_uInt16 nHeight;
4349 sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
4350 bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
4351 sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
4352 SCROW nRow;
4353 while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
4355 if (nFlagsEndRow < nRow)
4356 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
4357 if (nHiddenEndRow < nRow)
4358 bHidden = maTabs[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
4359 if (nHeightEndRow < nRow)
4360 nHeight = maTabs[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
4362 if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
4363 ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
4364 (bStartHidden != bHidden) ||
4365 (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
4366 (!bCareManualSize && ((nStartHeight != nHeight))))
4367 return nRow;
4370 return MAXROW+1;
4373 bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
4375 bool bRet(false);
4376 nDefault = 0;
4377 ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
4378 SCCOL nColumn;
4379 SCROW nStartRow;
4380 SCROW nEndRow;
4381 const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4382 if (nEndRow < nLastRow)
4384 ScDefaultAttrSet aSet;
4385 ScDefaultAttrSet::iterator aItr = aSet.end();
4386 while (pAttr)
4388 ScDefaultAttr aAttr(pAttr);
4389 aItr = aSet.find(aAttr);
4390 if (aItr == aSet.end())
4392 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4393 aAttr.nFirst = nStartRow;
4394 aSet.insert(aAttr);
4396 else
4398 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4399 aAttr.nFirst = aItr->nFirst;
4400 aSet.erase(aItr);
4401 aSet.insert(aAttr);
4403 pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4405 ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
4406 aItr = aDefaultItr;
4407 ++aItr;
4408 while (aItr != aSet.end())
4410 // for entries with equal count, use the one with the lowest start row,
4411 // don't use the random order of pointer comparisons
4412 if ( aItr->nCount > aDefaultItr->nCount ||
4413 ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
4414 aDefaultItr = aItr;
4415 ++aItr;
4417 nDefault = aDefaultItr->nFirst;
4418 bRet = true;
4420 else
4421 bRet = true;
4422 return bRet;
4425 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4427 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4428 maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
4432 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4434 if ( ValidTab(nTab) && maTabs[nTab] )
4435 maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
4439 // Attribute ----------------------------------------------------------
4442 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
4444 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4446 const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
4447 if (pTemp)
4448 return pTemp;
4449 else
4451 OSL_FAIL( "Attribut Null" );
4454 return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
4457 const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich ) const
4459 return GetAttr(rPos.Col(), rPos.Row(), rPos.Tab(), nWhich);
4462 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4464 if (TableExists(nTab))
4465 return maTabs[nTab]->GetPattern( nCol, nRow );
4466 return NULL;
4469 const ScPatternAttr* ScDocument::GetPattern( const ScAddress& rPos ) const
4471 if (TableExists(rPos.Tab()))
4472 return maTabs[rPos.Tab()]->GetPattern(rPos.Col(), rPos.Row());
4474 return NULL;
4477 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
4479 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4480 return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
4481 return NULL;
4485 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
4487 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4488 maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
4492 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
4494 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4495 maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
4499 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
4500 SCCOL nEndCol, SCROW nEndRow,
4501 const ScMarkData& rMark,
4502 const ScPatternAttr& rAttr,
4503 ScEditDataArray* pDataArray )
4505 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4506 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4507 for (; itr != itrEnd && *itr < nMax; ++itr)
4508 if (maTabs[*itr])
4509 maTabs[*itr]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray );
4513 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
4514 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
4516 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4517 if (maTabs[nTab])
4518 maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
4521 bool ScDocument::SetAttrEntries(SCCOL nCol, SCTAB nTab, ScAttrEntry* pData, SCSIZE nSize)
4523 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4524 return false;
4526 return maTabs[nTab]->SetAttrEntries(nCol, pData, nSize);
4529 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
4530 const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
4532 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4533 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4534 for (; itr != itrEnd && *itr < nMax; ++itr)
4535 if (maTabs[*itr])
4536 maTabs[*itr]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
4539 void ScDocument::AddCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4541 if(!(static_cast<size_t>(nTab) < maTabs.size()))
4542 return;
4544 if(!maTabs[nTab])
4545 return;
4547 maTabs[nTab]->AddCondFormatData(rRange, nIndex);
4550 void ScDocument::RemoveCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4552 if(!(static_cast<size_t>(nTab) < maTabs.size()))
4553 return;
4555 if(!maTabs[nTab])
4556 return;
4558 maTabs[nTab]->RemoveCondFormatData(rRange, nIndex);
4562 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
4564 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4565 if (maTabs[nTab])
4566 maTabs[nTab]->ApplyStyle( nCol, nRow, rStyle );
4570 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
4571 SCCOL nEndCol, SCROW nEndRow,
4572 const ScMarkData& rMark,
4573 const ScStyleSheet& rStyle)
4575 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4576 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4577 for (; itr != itrEnd && *itr < nMax; ++itr)
4578 if (maTabs[*itr])
4579 maTabs[*itr]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4583 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
4584 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
4586 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4587 if (maTabs[nTab])
4588 maTabs[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4592 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
4594 // ApplySelectionStyle needs multi mark
4595 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4597 ScRange aRange;
4598 rMark.GetMarkArea( aRange );
4599 ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
4600 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
4602 else
4604 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4605 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4606 for (; itr != itrEnd && *itr < nMax; ++itr)
4607 if ( maTabs[*itr] )
4608 maTabs[*itr]->ApplySelectionStyle( rStyle, rMark );
4613 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4614 const SvxBorderLine* pLine, bool bColorOnly )
4616 if ( bColorOnly && !pLine )
4617 return;
4619 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4620 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4621 for (; itr != itrEnd && *itr < nMax; ++itr)
4622 if (maTabs[*itr])
4623 maTabs[*itr]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4627 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4629 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4630 return maTabs[nTab]->GetStyle(nCol, nRow);
4631 else
4632 return NULL;
4636 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4638 bool bEqual = true;
4639 bool bFound;
4641 const ScStyleSheet* pStyle = NULL;
4642 const ScStyleSheet* pNewStyle;
4644 if ( rMark.IsMultiMarked() )
4646 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4647 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4648 for (; itr != itrEnd && *itr < nMax; ++itr)
4649 if (maTabs[*itr])
4651 pNewStyle = maTabs[*itr]->GetSelectionStyle( rMark, bFound );
4652 if (bFound)
4654 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4655 bEqual = false; // unterschiedliche
4656 pStyle = pNewStyle;
4660 if ( rMark.IsMarked() )
4662 ScRange aRange;
4663 rMark.GetMarkArea( aRange );
4664 for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual && i < static_cast<SCTAB>(maTabs.size()); i++)
4665 if (maTabs[i] && rMark.GetTableSelect(i))
4667 pNewStyle = maTabs[i]->GetAreaStyle( bFound,
4668 aRange.aStart.Col(), aRange.aStart.Row(),
4669 aRange.aEnd.Col(), aRange.aEnd.Row() );
4670 if (bFound)
4672 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4673 bEqual = false; // unterschiedliche
4674 pStyle = pNewStyle;
4679 return bEqual ? pStyle : NULL;
4683 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, bool bRemoved,
4684 OutputDevice* pDev,
4685 double nPPTX, double nPPTY,
4686 const Fraction& rZoomX, const Fraction& rZoomY )
4688 TableContainer::iterator it = maTabs.begin();
4689 for (; it != maTabs.end(); ++it)
4690 if (*it)
4691 (*it)->StyleSheetChanged
4692 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4694 if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4696 // update attributes for all note objects
4697 ScDetectiveFunc::UpdateAllComments( *this );
4702 bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
4704 if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4706 if ( bGatherAllStyles )
4708 SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4709 SFX_STYLE_FAMILY_PARA );
4710 for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4711 pStyle = aIter.Next() )
4713 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4714 if ( pScStyle )
4715 pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4719 bool bIsUsed = false;
4721 TableContainer::const_iterator it = maTabs.begin();
4722 for (; it != maTabs.end(); ++it)
4723 if (*it)
4725 if ( (*it)->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4727 if ( !bGatherAllStyles )
4728 return true;
4729 bIsUsed = true;
4733 if ( bGatherAllStyles )
4734 bStyleSheetUsageInvalid = false;
4736 return bIsUsed;
4739 return rStyle.GetUsage() == ScStyleSheet::USED;
4743 bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4744 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4746 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4747 if (maTabs[nTab])
4748 return maTabs[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4750 OSL_FAIL("ApplyFlags: wrong table");
4751 return false;
4755 bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4756 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4758 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4759 if (maTabs[nTab])
4760 return maTabs[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4762 OSL_FAIL("RemoveFlags: wrong table");
4763 return false;
4767 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4768 bool bPutToPool )
4770 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4771 if (maTabs[nTab])
4772 maTabs[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4776 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4777 bool bPutToPool )
4779 SCTAB nTab = rPos.Tab();
4780 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
4781 maTabs[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4785 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, bool bDeep )
4787 ScMergePatternState aState;
4789 if ( rMark.IsMultiMarked() ) // multi selection
4791 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4792 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4793 for (; itr != itrEnd && *itr < nMax; ++itr)
4794 if (maTabs[*itr])
4795 maTabs[*itr]->MergeSelectionPattern( aState, rMark, bDeep );
4797 if ( rMark.IsMarked() ) // simle selection
4799 ScRange aRange;
4800 rMark.GetMarkArea(aRange);
4801 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4802 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4803 for (; itr != itrEnd && *itr < nMax; ++itr)
4804 if (maTabs[*itr])
4805 maTabs[*itr]->MergePatternArea( aState,
4806 aRange.aStart.Col(), aRange.aStart.Row(),
4807 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4810 OSL_ENSURE( aState.pItemSet, "SelectionPattern Null" );
4811 if (aState.pItemSet)
4812 return new ScPatternAttr( aState.pItemSet );
4813 else
4814 return new ScPatternAttr( GetPool() ); // empty
4818 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, bool bDeep )
4820 delete pSelectionAttr;
4821 pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4822 return pSelectionAttr;
4826 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4827 SvxBoxItem& rLineOuter,
4828 SvxBoxInfoItem& rLineInner )
4830 rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4831 rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4832 rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4833 rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4834 rLineOuter.SetDistance(0);
4836 rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4837 rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4838 rLineInner.SetTable(true);
4839 rLineInner.SetDist(true);
4840 rLineInner.SetMinDist(false);
4842 ScLineFlags aFlags;
4844 if (rMark.IsMarked())
4846 ScRange aRange;
4847 rMark.GetMarkArea(aRange);
4848 rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4849 rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4850 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4851 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
4852 for (; itr != itrEnd && *itr < nMax; ++itr)
4853 if (maTabs[*itr])
4854 maTabs[*itr]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4855 aRange.aStart.Col(), aRange.aStart.Row(),
4856 aRange.aEnd.Col(), aRange.aEnd.Row() );
4859 // Don't care Status auswerten
4861 rLineInner.SetValid( VALID_LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4862 rLineInner.SetValid( VALID_RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
4863 rLineInner.SetValid( VALID_TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
4864 rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4865 rLineInner.SetValid( VALID_HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
4866 rLineInner.SetValid( VALID_VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
4870 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4871 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask ) const
4873 if ( nMask & HASATTR_ROTATE )
4875 // Attribut im Dokument ueberhaupt verwendet?
4876 // (wie in fillinfo)
4878 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4880 bool bAnyItem = false;
4881 sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4882 for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4884 const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4885 if ( pItem )
4887 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4888 // (see ScPatternAttr::GetCellOrientation)
4889 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4890 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4892 bAnyItem = true;
4893 break;
4897 if (!bAnyItem)
4898 nMask &= ~HASATTR_ROTATE;
4901 if ( nMask & HASATTR_RTL )
4903 // first check if right-to left is in the pool at all
4904 // (the same item is used in cell and page format)
4906 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4908 bool bHasRtl = false;
4909 sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
4910 for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
4912 const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
4913 if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4915 bHasRtl = true;
4916 break;
4919 if (!bHasRtl)
4920 nMask &= ~HASATTR_RTL;
4923 if (!nMask)
4924 return false;
4926 bool bFound = false;
4927 for (SCTAB i=nTab1; i<=nTab2 && !bFound && i < static_cast<SCTAB>(maTabs.size()); i++)
4928 if (maTabs[i])
4930 if ( nMask & HASATTR_RTL )
4932 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
4933 bFound = true;
4935 if ( nMask & HASATTR_RIGHTORCENTER )
4937 // On a RTL sheet, don't start to look for the default left value
4938 // (which is then logically right), instead always assume true.
4939 // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4941 if ( IsLayoutRTL(i) )
4942 bFound = true;
4945 if ( !bFound )
4946 bFound = maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4949 return bFound;
4952 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask ) const
4954 return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4955 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
4956 nMask );
4959 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4960 SCCOL nX1, SCCOL nX2 ) const
4962 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4963 maTabs[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4964 else
4966 OSL_FAIL("FindMaxRotCol: wrong table");
4970 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4971 const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4972 const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4974 //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
4976 const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4977 OSL_ENSURE(pThisAttr,"where is the attribute?");
4979 const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
4980 const SvxBorderLine* pTopLine = pThisAttr->GetTop();
4981 const SvxBorderLine* pRightLine = pThisAttr->GetRight();
4982 const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4984 if ( nCol > 0 )
4986 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4987 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4988 if ( ScHasPriority( pOther, pLeftLine ) )
4989 pLeftLine = pOther;
4991 if ( nRow > 0 )
4993 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4994 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4995 if ( ScHasPriority( pOther, pTopLine ) )
4996 pTopLine = pOther;
4998 if ( nCol < MAXCOL )
5000 const SvxBorderLine* pOther = ((const SvxBoxItem*)
5001 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
5002 if ( ScHasPriority( pOther, pRightLine ) )
5003 pRightLine = pOther;
5005 if ( nRow < MAXROW )
5007 const SvxBorderLine* pOther = ((const SvxBoxItem*)
5008 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
5009 if ( ScHasPriority( pOther, pBottomLine ) )
5010 pBottomLine = pOther;
5013 if (ppLeft)
5014 *ppLeft = pLeftLine;
5015 if (ppTop)
5016 *ppTop = pTopLine;
5017 if (ppRight)
5018 *ppRight = pRightLine;
5019 if (ppBottom)
5020 *ppBottom = pBottomLine;
5023 bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5024 SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
5026 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5027 if (maTabs[nTab])
5028 return maTabs[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
5030 OSL_FAIL("wrong table number");
5031 return false;
5035 void ScDocument::LockTable(SCTAB nTab)
5037 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5038 maTabs[nTab]->LockTable();
5039 else
5041 OSL_FAIL("wrong table number");
5046 void ScDocument::UnlockTable(SCTAB nTab)
5048 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5049 maTabs[nTab]->UnlockTable();
5050 else
5052 OSL_FAIL("wrong table number");
5057 bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5058 SCCOL nEndCol, SCROW nEndRow,
5059 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
5061 // import into read-only document is possible
5062 if (!bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly())
5064 if ( pOnlyNotBecauseOfMatrix )
5065 *pOnlyNotBecauseOfMatrix = false;
5066 return false;
5069 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5070 if (maTabs[nTab])
5071 return maTabs[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
5072 nEndRow, pOnlyNotBecauseOfMatrix );
5074 OSL_FAIL("wrong table number");
5075 if ( pOnlyNotBecauseOfMatrix )
5076 *pOnlyNotBecauseOfMatrix = false;
5077 return false;
5081 bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
5082 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
5084 // import into read-only document is possible
5085 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
5087 if ( pOnlyNotBecauseOfMatrix )
5088 *pOnlyNotBecauseOfMatrix = false;
5089 return false;
5092 ScRange aRange;
5093 rMark.GetMarkArea(aRange);
5095 bool bOk = true;
5096 bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
5097 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5098 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5099 for (; itr != itrEnd && *itr < nMax && (bOk || bMatrix); ++itr)
5101 if ( maTabs[*itr] )
5103 if (rMark.IsMarked())
5105 if ( !maTabs[*itr]->IsBlockEditable( aRange.aStart.Col(),
5106 aRange.aStart.Row(), aRange.aEnd.Col(),
5107 aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
5109 bOk = false;
5110 if ( pOnlyNotBecauseOfMatrix )
5111 bMatrix = *pOnlyNotBecauseOfMatrix;
5114 if (rMark.IsMultiMarked())
5116 if ( !maTabs[*itr]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
5118 bOk = false;
5119 if ( pOnlyNotBecauseOfMatrix )
5120 bMatrix = *pOnlyNotBecauseOfMatrix;
5126 if ( pOnlyNotBecauseOfMatrix )
5127 *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
5129 return bOk;
5133 bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
5134 SCCOL nEndCol, SCROW nEndRow,
5135 const ScMarkData& rMark ) const
5137 bool bOk = true;
5138 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5139 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5140 for (; itr != itrEnd && *itr < nMax && bOk; ++itr)
5141 if (maTabs[*itr])
5142 if (maTabs[*itr]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
5143 bOk = false;
5145 return !bOk;
5148 bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
5150 // if rCell is part of a matrix formula, return its complete range
5152 ScFormulaCell* pFCell = GetFormulaCell(rCellPos);
5153 if (!pFCell)
5154 // not a formula cell. Bail out.
5155 return false;
5157 ScAddress aOrigin = rCellPos;
5158 if (!pFCell->GetMatrixOrigin(aOrigin))
5159 // Failed to get the address of the matrix origin.
5160 return false;
5162 if (aOrigin != rCellPos)
5164 pFCell = GetFormulaCell(aOrigin);
5165 if (!pFCell)
5166 // The matrix origin cell is not a formula cell !? Something is up...
5167 return false;
5170 SCCOL nSizeX;
5171 SCROW nSizeY;
5172 pFCell->GetMatColsRows(nSizeX, nSizeY);
5173 if (nSizeX <= 0 || nSizeY <= 0)
5175 // GetMatrixEdge computes also dimensions of the matrix
5176 // if not already done (may occur if document is loaded
5177 // from old file format).
5178 // Needs an "invalid" initialized address.
5179 aOrigin.SetInvalid();
5180 pFCell->GetMatrixEdge(aOrigin);
5181 pFCell->GetMatColsRows(nSizeX, nSizeY);
5184 if (nSizeX <= 0 || nSizeY <= 0)
5185 // Matrix size is still invalid. Give up.
5186 return false;
5188 ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
5189 aOrigin.Row() + nSizeY - 1,
5190 aOrigin.Tab() );
5192 rMatrix.aStart = aOrigin;
5193 rMatrix.aEnd = aEnd;
5195 return true;
5199 bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
5200 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab ) const
5202 bool bFound = false;
5203 if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
5205 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5207 SCCOL nCol;
5208 SCCOL nOldCol = rStartCol;
5209 SCROW nOldRow = rStartRow;
5210 for (nCol=nOldCol; nCol<=nEndCol; nCol++)
5211 while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
5212 IsVerOverlapped())
5213 --rStartRow;
5215 //! weiterreichen ?
5217 ScAttrArray* pAttrArray = maTabs[nTab]->aCol[nOldCol].pAttrArray;
5218 SCSIZE nIndex;
5219 pAttrArray->Search( nOldRow, nIndex );
5220 SCROW nAttrPos = nOldRow;
5221 while (nAttrPos<=nEndRow)
5223 OSL_ENSURE( nIndex < pAttrArray->nCount, "Wrong index in AttrArray" );
5225 if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
5226 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
5228 SCROW nLoopEndRow = std::min( nEndRow, pAttrArray->pData[nIndex].nRow );
5229 for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
5231 SCCOL nTempCol = nOldCol;
5233 --nTempCol;
5234 while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
5235 ->IsHorOverlapped());
5236 if (nTempCol < rStartCol)
5237 rStartCol = nTempCol;
5240 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
5241 ++nIndex;
5245 else
5247 OSL_FAIL("ExtendOverlapped: invalid range");
5250 return bFound;
5254 bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
5255 SCCOL& rEndCol, SCROW& rEndRow,
5256 const ScMarkData& rMark, bool bRefresh )
5258 // use all selected sheets from rMark
5260 bool bFound = false;
5261 SCCOL nOldEndCol = rEndCol;
5262 SCROW nOldEndRow = rEndRow;
5264 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5265 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5266 for (; itr != itrEnd && *itr < nMax; ++itr)
5267 if ( maTabs[*itr] )
5269 SCCOL nThisEndCol = nOldEndCol;
5270 SCROW nThisEndRow = nOldEndRow;
5271 if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, *itr, bRefresh ) )
5272 bFound = true;
5273 if ( nThisEndCol > rEndCol )
5274 rEndCol = nThisEndCol;
5275 if ( nThisEndRow > rEndRow )
5276 rEndRow = nThisEndRow;
5279 return bFound;
5283 bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
5284 SCCOL& rEndCol, SCROW& rEndRow,
5285 SCTAB nTab, bool bRefresh )
5287 bool bFound = false;
5288 if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
5290 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5291 bFound = maTabs[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
5293 if (bRefresh)
5294 RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
5296 else
5298 OSL_FAIL("ExtendMerge: invalid range");
5301 return bFound;
5305 bool ScDocument::ExtendMerge( ScRange& rRange, bool bRefresh )
5307 bool bFound = false;
5308 SCTAB nStartTab = rRange.aStart.Tab();
5309 SCTAB nEndTab = rRange.aEnd.Tab();
5310 SCCOL nEndCol = rRange.aEnd.Col();
5311 SCROW nEndRow = rRange.aEnd.Row();
5313 PutInOrder( nStartTab, nEndTab );
5314 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5316 SCCOL nExtendCol = rRange.aEnd.Col();
5317 SCROW nExtendRow = rRange.aEnd.Row();
5318 if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
5319 nExtendCol, nExtendRow,
5320 nTab, bRefresh ) )
5322 bFound = true;
5323 if (nExtendCol > nEndCol) nEndCol = nExtendCol;
5324 if (nExtendRow > nEndRow) nEndRow = nExtendRow;
5328 rRange.aEnd.SetCol(nEndCol);
5329 rRange.aEnd.SetRow(nEndRow);
5331 return bFound;
5334 bool ScDocument::ExtendTotalMerge( ScRange& rRange ) const
5336 // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
5337 // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
5339 bool bRet = false;
5340 ScRange aExt = rRange;
5341 // ExtendMerge() is non-const, but called withouth refresh.
5342 if (const_cast<ScDocument*>(this)->ExtendMerge( aExt, false))
5344 if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
5346 ScRange aTest = aExt;
5347 aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
5348 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
5349 aExt.aEnd.SetRow(rRange.aEnd.Row());
5351 if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
5353 ScRange aTest = aExt;
5354 aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
5355 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
5356 aExt.aEnd.SetCol(rRange.aEnd.Col());
5359 bRet = ( aExt.aEnd != rRange.aEnd );
5360 rRange = aExt;
5362 return bRet;
5365 bool ScDocument::ExtendOverlapped( ScRange& rRange ) const
5367 bool bFound = false;
5368 SCTAB nStartTab = rRange.aStart.Tab();
5369 SCTAB nEndTab = rRange.aEnd.Tab();
5370 SCCOL nStartCol = rRange.aStart.Col();
5371 SCROW nStartRow = rRange.aStart.Row();
5373 PutInOrder( nStartTab, nEndTab );
5374 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5376 SCCOL nExtendCol = rRange.aStart.Col();
5377 SCROW nExtendRow = rRange.aStart.Row();
5378 ExtendOverlapped( nExtendCol, nExtendRow,
5379 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
5380 if (nExtendCol < nStartCol)
5382 nStartCol = nExtendCol;
5383 bFound = true;
5385 if (nExtendRow < nStartRow)
5387 nStartRow = nExtendRow;
5388 bFound = true;
5392 rRange.aStart.SetCol(nStartCol);
5393 rRange.aStart.SetRow(nStartRow);
5395 return bFound;
5398 bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
5399 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
5401 SCTAB nDBTab;
5402 SCCOL nDBStartCol;
5403 SCROW nDBStartRow;
5404 SCCOL nDBEndCol;
5405 SCROW nDBEndRow;
5407 // Autofilter loeschen
5409 bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
5411 // Autofilter setzen
5413 const ScDBData* pData = NULL;
5414 ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
5415 ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(), itrEnd = rDBs.end();
5416 for (; itr != itrEnd; ++itr)
5418 if (itr->HasAutoFilter())
5420 itr->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
5421 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5422 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5424 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5425 nDBTab, SC_MF_AUTO ))
5426 bChange = true;
5430 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5431 pData = maTabs[nTab]->GetAnonymousDBData();
5432 else
5433 pData=NULL;
5434 if (pData)
5436 if (pData->HasAutoFilter())
5438 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
5439 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5440 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5442 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5443 nDBTab, SC_MF_AUTO ))
5444 bChange = true;
5448 return bChange;
5451 void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
5453 while (IsHorOverlapped(rCol, rRow, nTab))
5454 --rCol;
5455 while (IsVerOverlapped(rCol, rRow, nTab))
5456 --rRow;
5459 bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5461 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
5462 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
5463 if (pAttr)
5464 return pAttr->IsHorOverlapped();
5465 else
5467 OSL_FAIL("Overlapped: Attr==0");
5468 return false;
5473 bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5475 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
5476 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
5477 if (pAttr)
5478 return pAttr->IsVerOverlapped();
5479 else
5481 OSL_FAIL("Overlapped: Attr==0");
5482 return false;
5487 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
5488 const SvxBoxItem* pLineOuter,
5489 const SvxBoxInfoItem* pLineInner )
5491 ScRangeList aRangeList;
5492 rMark.FillRangeListWithMarks( &aRangeList, false );
5493 size_t nRangeCount = aRangeList.size();
5494 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5495 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5496 for (; itr != itrEnd && *itr < nMax; ++itr)
5498 if (maTabs[*itr])
5500 for ( size_t j=0; j < nRangeCount; j++ )
5502 ScRange aRange = *aRangeList[ j ];
5503 maTabs[*itr]->ApplyBlockFrame( pLineOuter, pLineInner,
5504 aRange.aStart.Col(), aRange.aStart.Row(),
5505 aRange.aEnd.Col(), aRange.aEnd.Row() );
5512 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
5513 const SvxBoxItem* pLineOuter,
5514 const SvxBoxInfoItem* pLineInner )
5516 SCTAB nStartTab = rRange.aStart.Tab();
5517 SCTAB nEndTab = rRange.aStart.Tab();
5518 for (SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
5519 if (maTabs[nTab])
5520 maTabs[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
5521 rRange.aStart.Col(), rRange.aStart.Row(),
5522 rRange.aEnd.Col(), rRange.aEnd.Row() );
5526 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark, ScEditDataArray* pDataArray )
5528 const SfxItemSet* pSet = &rAttr.GetItemSet();
5529 bool bSet = false;
5530 sal_uInt16 i;
5531 for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
5532 if (pSet->GetItemState(i) == SFX_ITEM_SET)
5533 bSet = true;
5535 if (bSet)
5537 // ApplySelectionCache needs multi mark
5538 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
5540 ScRange aRange;
5541 rMark.GetMarkArea( aRange );
5542 ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
5543 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray );
5545 else
5547 SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
5548 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5549 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5550 for (; itr != itrEnd && *itr < nMax; ++itr)
5551 if (maTabs[*itr])
5552 maTabs[*itr]->ApplySelectionCache( &aCache, rMark, pDataArray );
5558 void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
5560 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5561 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5562 for (; itr != itrEnd && *itr < nMax; ++itr)
5563 if (maTabs[*itr])
5564 maTabs[*itr]->ChangeSelectionIndent( bIncrement, rMark );
5568 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
5570 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5571 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5572 for (; itr != itrEnd && *itr < nMax; ++itr)
5573 if (maTabs[*itr])
5574 maTabs[*itr]->ClearSelectionItems( pWhich, rMark );
5578 void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
5580 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5581 ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
5582 for (; itr != itrEnd && *itr < nMax; ++itr)
5583 if (maTabs[*itr])
5584 maTabs[*itr]->DeleteSelection( nDelFlag, rMark );
5588 void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
5590 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5591 maTabs[nTab]->DeleteSelection( nDelFlag, rMark );
5592 else
5594 OSL_FAIL("wrong table");
5599 ScPatternAttr* ScDocument::GetDefPattern() const
5601 return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
5605 ScDocumentPool* ScDocument::GetPool()
5607 return xPoolHelper->GetDocPool();
5612 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
5614 return xPoolHelper->GetStylePool();
5618 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
5619 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
5621 PutInOrder(nStartCol, nEndCol);
5622 PutInOrder(nStartRow, nEndRow);
5623 PutInOrder(nStartTab, nEndTab);
5624 if (ValidTab(nStartTab) && nStartTab < static_cast<SCTAB>(maTabs.size()))
5626 if (maTabs[nStartTab])
5627 return maTabs[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
5628 else
5629 return 0;
5631 else
5632 return 0;
5636 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, ScMoveDirection eDirection ) const
5638 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5639 maTabs[nTab]->FindAreaPos( rCol, rRow, eDirection );
5643 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
5644 bool bMarked, bool bUnprotected, const ScMarkData& rMark ) const
5646 OSL_ENSURE( !nMovX || !nMovY, "GetNextPos: only X or Y" );
5648 ScMarkData aCopyMark = rMark;
5649 aCopyMark.SetMarking(false);
5650 aCopyMark.MarkToMulti();
5652 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5653 maTabs[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
5657 // Datei-Operationen
5661 void ScDocument::UpdStlShtPtrsFrmNms()
5663 ScPatternAttr::pDoc = this;
5665 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5667 sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5668 ScPatternAttr* pPattern;
5669 for (sal_uInt32 i=0; i<nCount; i++)
5671 pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5672 if (pPattern)
5673 pPattern->UpdateStyleSheet();
5675 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
5679 void ScDocument::StylesToNames()
5681 ScPatternAttr::pDoc = this;
5683 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5685 sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5686 ScPatternAttr* pPattern;
5687 for (sal_uInt32 i=0; i<nCount; i++)
5689 pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5690 if (pPattern)
5691 pPattern->StyleToName();
5693 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
5697 sal_uLong ScDocument::GetCellCount() const
5699 sal_uLong nCellCount = 0L;
5701 TableContainer::const_iterator it = maTabs.begin();
5702 for (; it != maTabs.end(); ++it)
5703 if ( *it )
5704 nCellCount += (*it)->GetCellCount();
5706 return nCellCount;
5709 SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
5711 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
5712 return 0;
5714 return maTabs[nTab]->GetCellCount(nCol);
5717 sal_uLong ScDocument::GetCodeCount() const
5719 sal_uLong nCodeCount = 0;
5721 TableContainer::const_iterator it = maTabs.begin();
5722 for (; it != maTabs.end(); ++it)
5723 if ( *it )
5724 nCodeCount += (*it)->GetCodeCount();
5726 return nCodeCount;
5730 void ScDocument::PageStyleModified( SCTAB nTab, const OUString& rNewName )
5732 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5733 maTabs[nTab]->PageStyleModified( rNewName );
5737 void ScDocument::SetPageStyle( SCTAB nTab, const OUString& rName )
5739 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5740 maTabs[nTab]->SetPageStyle( rName );
5744 const OUString ScDocument::GetPageStyle( SCTAB nTab ) const
5746 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5747 return maTabs[nTab]->GetPageStyle();
5749 return OUString();
5753 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5755 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5756 maTabs[nTab]->SetPageSize( rSize );
5759 Size ScDocument::GetPageSize( SCTAB nTab ) const
5761 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5762 return maTabs[nTab]->GetPageSize();
5764 OSL_FAIL("invalid tab");
5765 return Size();
5769 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5771 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5772 maTabs[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5775 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5777 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5778 maTabs[nTab]->InvalidatePageBreaks();
5781 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5783 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5784 maTabs[nTab]->UpdatePageBreaks( pUserArea );
5787 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5789 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5790 maTabs[nTab]->RemoveManualBreaks();
5793 bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5795 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5796 return maTabs[nTab]->HasManualBreaks();
5798 OSL_FAIL("invalid tab");
5799 return false;
5803 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5805 rDocStat.nTableCount = GetTableCount();
5806 rDocStat.aDocName = aDocName;
5807 rDocStat.nCellCount = GetCellCount();
5811 bool ScDocument::HasPrintRange()
5813 bool bResult = false;
5815 TableContainer::iterator it = maTabs.begin();
5816 for (; it != maTabs.end() && !bResult; ++it)
5817 if ( *it )
5818 bResult = (*it)->IsPrintEntireSheet() || ((*it)->GetPrintRangeCount() > 0);
5820 return bResult;
5824 bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5826 return (ValidTab(nTab) ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsPrintEntireSheet();
5830 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5832 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5833 return maTabs[nTab]->GetPrintRangeCount();
5835 return 0;
5839 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5841 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5842 return maTabs[nTab]->GetPrintRange(nPos);
5844 return NULL;
5848 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5850 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5851 return maTabs[nTab]->GetRepeatColRange();
5853 return NULL;
5857 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5859 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5860 return maTabs[nTab]->GetRepeatRowRange();
5862 return NULL;
5866 void ScDocument::ClearPrintRanges( SCTAB nTab )
5868 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5869 maTabs[nTab]->ClearPrintRanges();
5873 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5875 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5876 maTabs[nTab]->AddPrintRange( rNew );
5880 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5882 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5883 maTabs[nTab]->SetPrintEntireSheet();
5887 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5889 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5890 maTabs[nTab]->SetRepeatColRange( pNew );
5894 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5896 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5897 maTabs[nTab]->SetRepeatRowRange( pNew );
5901 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5903 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
5904 ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5905 for (SCTAB i=0; i<nCount; i++)
5906 if (maTabs[i])
5907 maTabs[i]->FillPrintSaver( pNew->GetTabData(i) );
5908 return pNew;
5912 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5914 SCTAB nCount = rSaver.GetTabCount();
5915 for (SCTAB i=0; i<nCount && i < static_cast<SCTAB>(maTabs.size()); i++)
5916 if (maTabs[i])
5917 maTabs[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5921 bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5923 // Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5924 // andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5925 // und eine Seitennummer angegeben ist (nicht 0)
5927 if ( nTab + 1 < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab+1] )
5929 OUString aNew = maTabs[nTab+1]->GetPageStyle();
5930 if ( aNew != maTabs[nTab]->GetPageStyle() )
5932 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5933 if ( pStyle )
5935 const SfxItemSet& rSet = pStyle->GetItemSet();
5936 sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5937 if ( nFirst != 0 )
5938 return true; // Seitennummer in neuer Vorlage angegeben
5943 return false; // sonst nicht
5946 SfxUndoManager* ScDocument::GetUndoManager()
5948 if (!mpUndoManager)
5950 // to support enhanced text edit for draw objects, use an SdrUndoManager
5951 mpUndoManager = new SdrUndoManager;
5954 return mpUndoManager;
5957 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
5959 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5960 return new ScRowBreakIterator(maTabs[nTab]->maRowPageBreaks);
5961 return NULL;
5964 void ScDocument::AddSubTotalCell(ScFormulaCell* pCell)
5966 maSubTotalCells.insert(pCell);
5969 void ScDocument::RemoveSubTotalCell(ScFormulaCell* pCell)
5971 maSubTotalCells.erase(pCell);
5974 namespace {
5976 bool lcl_hasDirtyRange(ScFormulaCell* pCell, const ScRange& rDirtyRange)
5978 ScDetectiveRefIter aRefIter(pCell);
5979 ScRange aRange;
5980 while (aRefIter.GetNextRef(aRange))
5982 if (aRange.Intersects(rDirtyRange))
5983 return true;
5985 return false;
5990 void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
5992 // to update the list by skipping cells that no longer contain subtotal function.
5993 set<ScFormulaCell*> aNewSet;
5995 bool bOldRecalc = GetAutoCalc();
5996 SetAutoCalc(false);
5997 set<ScFormulaCell*>::iterator itr = maSubTotalCells.begin(), itrEnd = maSubTotalCells.end();
5998 for (; itr != itrEnd; ++itr)
6000 ScFormulaCell* pCell = *itr;
6001 if (pCell->IsSubTotal())
6003 aNewSet.insert(pCell);
6004 if (lcl_hasDirtyRange(pCell, rDirtyRange))
6005 pCell->SetDirty();
6009 SetAutoCalc(bOldRecalc);
6010 maSubTotalCells.swap(aNewSet); // update the list.
6013 void ScDocument::MarkSubTotalCells( sc::ColumnSpanSet& rSet, const ScRange& rRange, bool bVal ) const
6015 for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
6017 const ScTable* pTab = FetchTable(nTab);
6018 if (!pTab)
6019 continue;
6021 pTab->MarkSubTotalCells(
6022 rSet, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), bVal);
6026 sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const
6028 SCTAB nTab = rPos.Tab();
6029 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6030 return maTabs[nTab]->GetTextWidth(rPos.Col(), rPos.Row());
6032 return 0;
6035 sal_uInt8 ScDocument::GetScriptType( const ScAddress& rPos ) const
6037 SCTAB nTab = rPos.Tab();
6038 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6039 return maTabs[nTab]->GetScriptType(rPos.Col(), rPos.Row());
6041 return 0;
6044 void ScDocument::SetScriptType( const ScAddress& rPos, sal_uInt8 nType )
6046 SCTAB nTab = rPos.Tab();
6047 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6048 maTabs[nTab]->SetScriptType(rPos.Col(), rPos.Row(), nType);
6051 void ScDocument::EnableUndo( bool bVal )
6053 // The undo manager increases lock count every time undo is disabled.
6054 // Because of this, we shouldn't disable undo unless it's currently
6055 // enabled, or else re-enabling it may not actually re-enable undo unless
6056 // the lock count becomes zero.
6058 if (bVal != GetUndoManager()->IsUndoEnabled())
6060 GetUndoManager()->EnableUndo(bVal);
6061 if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
6064 mbUndoEnabled = bVal;
6067 bool ScDocument::IsUserInteractionEnabled() const
6069 return mbUserInteractionEnabled;
6072 void ScDocument::EnableUserInteraction( bool bVal )
6074 mbUserInteractionEnabled = bVal;
6077 bool ScDocument::IsInVBAMode() const
6079 if (!pShell)
6080 return false;
6084 uno::Reference<script::vba::XVBACompatibility> xVBA(
6085 pShell->GetBasicContainer(), uno::UNO_QUERY);
6087 return xVBA.is() && xVBA->getVBACompatibilityMode();
6089 catch (const lang::NotInitializedException&) {}
6091 return false;
6094 ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
6096 return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
6099 ScPostIt* ScDocument::GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
6101 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
6102 return maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
6103 else
6104 return NULL;
6108 void ScDocument::SetNote(const ScAddress& rPos, ScPostIt* pNote)
6110 return SetNote(rPos.Col(), rPos.Row(), rPos.Tab(), pNote);
6113 void ScDocument::SetNote(SCCOL nCol, SCROW nRow, SCTAB nTab, ScPostIt* pNote)
6115 return maTabs[nTab]->aCol[nCol].SetCellNote(nRow, pNote);
6118 bool ScDocument::HasNote(const ScAddress& rPos)
6120 return HasNote(rPos.Col(), rPos.Row(), rPos.Tab());
6122 bool ScDocument::HasNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
6124 ScPostIt* pNote = maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
6125 return pNote != NULL;
6127 bool ScDocument::HasColNotes(SCCOL nCol, SCTAB nTab)
6129 return maTabs[nTab]->aCol[nCol].HasCellNotes();
6132 bool ScDocument::HasTabNotes(SCTAB nTab)
6134 bool hasNotes = false;
6135 for (SCCOL nCol=0; nCol<MAXCOLCOUNT && !hasNotes; ++nCol)
6136 hasNotes = HasColNotes(nCol, nTab);
6138 return hasNotes;
6141 ScPostIt* ScDocument::ReleaseNote(const ScAddress& rPos)
6143 return ReleaseNote(rPos.Col(), rPos.Row(), rPos.Tab());
6145 ScPostIt* ScDocument::ReleaseNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
6148 ScPostIt* pPostIt = GetNote(nCol, nRow, nTab);
6149 if (pPostIt != NULL)
6150 maTabs[nTab]->aCol[nCol].DeleteCellNote(nRow);
6152 return pPostIt;
6155 ScPostIt* ScDocument::GetOrCreateNote(const ScAddress& rPos)
6157 if (HasNote(rPos))
6158 return GetNote(rPos);
6159 else
6160 return CreateNote(rPos);
6162 ScPostIt* ScDocument::CreateNote(const ScAddress& rPos)
6164 ScPostIt* pPostIt = new ScPostIt(*this, rPos, false);
6165 SetNote(rPos, pPostIt);
6166 return pPostIt;
6169 size_t ScDocument::CountNotes() const
6171 size_t nCount = 0;
6172 SCTAB nTabCount = GetTableCount();
6173 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
6175 for (SCCOL nCol=0; nCol<MAXCOLCOUNT; nCol++)
6176 nCount += GetNoteCount(nTab, nCol);
6178 return nCount;
6181 size_t ScDocument::GetNoteCount( SCTAB nTab, SCCOL nCol ) const
6183 const ScTable* pTab = FetchTable(nTab);
6184 if (!pTab)
6185 return 0;
6187 return pTab->GetNoteCount(nCol);
6190 ScAddress ScDocument::GetNotePosition( size_t nIndex ) const
6192 for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
6194 for (SCCOL nCol=0; nCol<MAXCOLCOUNT; nCol++)
6196 size_t nColNoteCount = GetNoteCount(nTab, nCol);
6197 if (!nColNoteCount)
6198 continue;
6200 if (nIndex >= nColNoteCount)
6202 nIndex -= nColNoteCount;
6203 continue;
6206 SCROW nRow = GetNotePosition(nTab, nCol, nIndex);
6207 if (nRow >= 0)
6208 return ScAddress(nCol, nRow, nTab);
6210 OSL_FAIL("note not found");
6211 return ScAddress(ScAddress::INITIALIZE_INVALID);
6215 OSL_FAIL("note not found");
6216 return ScAddress(ScAddress::INITIALIZE_INVALID);
6219 SCROW ScDocument::GetNotePosition( SCTAB nTab, SCCOL nCol, size_t nIndex ) const
6221 const ScTable* pTab = FetchTable(nTab);
6222 if (!pTab)
6223 return -1;
6225 return pTab->GetNotePosition(nCol, nIndex);
6228 void ScDocument::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
6230 for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
6232 const ScTable* pTab = maTabs[nTab];
6233 if (!pTab)
6234 continue;
6236 pTab->GetAllNoteEntries(rNotes);
6240 void ScDocument::GetNotesInRange( const ScRangeList& rRange, std::vector<sc::NoteEntry>& rNotes ) const
6242 for( size_t i = 0; i < rRange.size(); ++i)
6244 const ScRange* pRange = rRange[i];
6245 for( SCTAB nTab = pRange->aStart.Tab(); nTab <= pRange->aEnd.Tab(); ++nTab )
6247 maTabs[nTab]->GetNotesInRange( *pRange, rNotes );
6252 bool ScDocument::ContainsNotesInRange( const ScRangeList& rRange ) const
6254 for( size_t i = 0; i < rRange.size(); ++i)
6256 const ScRange* pRange = rRange[i];
6257 for( SCTAB nTab = pRange->aStart.Tab(); nTab < pRange->aEnd.Tab(); ++nTab )
6259 bool bContainsNote = maTabs[nTab]->ContainsNotesInRange( *pRange );
6260 if(bContainsNote)
6261 return true;
6265 return false;
6268 void ScDocument::SetAutoNameCache( ScAutoNameCache* pCache )
6270 delete pAutoNameCache;
6271 pAutoNameCache = pCache;
6274 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */