update dev300-m57
[ooovba.git] / sc / source / core / data / document.cxx
bloba457512cefc57c4bb9c8f5e3c552459a60a5d81f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: document.cxx,v $
10 * $Revision: 1.90.36.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #define _ZFORLIST_DECLARE_TABLE
37 #include "scitems.hxx"
38 #include <svx/eeitem.hxx>
40 #include <svx/boxitem.hxx>
41 #include <svx/frmdiritem.hxx>
42 #include <svx/pageitem.hxx>
43 #include <svx/editeng.hxx>
44 #include <svx/svditer.hxx>
45 #include <svx/svdpage.hxx>
46 #include <svx/svdocapt.hxx>
47 #include <sfx2/app.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <svtools/poolcach.hxx>
50 #include <svtools/saveopt.hxx>
51 #include <svtools/zforlist.hxx>
52 #include <unotools/charclass.hxx>
53 #include <unotools/transliterationwrapper.hxx>
54 #include <tools/tenccvt.hxx>
56 #include <com/sun/star/text/WritingMode2.hpp>
58 #include "document.hxx"
59 #include "table.hxx"
60 #include "attrib.hxx"
61 #include "attarray.hxx"
62 #include "markarr.hxx"
63 #include "patattr.hxx"
64 #include "rangenam.hxx"
65 #include "poolhelp.hxx"
66 #include "docpool.hxx"
67 #include "stlpool.hxx"
68 #include "stlsheet.hxx"
69 #include "globstr.hrc"
70 #include "rechead.hxx"
71 #include "dbcolect.hxx"
72 #include "pivot.hxx"
73 #include "chartlis.hxx"
74 #include "rangelst.hxx"
75 #include "markdata.hxx"
76 #include "drwlayer.hxx"
77 #include "conditio.hxx"
78 #include "validat.hxx"
79 #include "prnsave.hxx"
80 #include "chgtrack.hxx"
81 #include "sc.hrc"
82 #include "scresid.hxx"
83 #include "hints.hxx"
84 #include "detdata.hxx"
85 #include "cell.hxx"
86 #include "dpobject.hxx"
87 #include "indexmap.hxx"
88 #include "detfunc.hxx" // for UpdateAllComments
89 #include "scmod.hxx"
90 #include "dociter.hxx"
91 #include "progress.hxx"
92 #include "autonamecache.hxx"
93 #include "bcaslot.hxx"
94 #include "postit.hxx"
95 #include "externalrefmgr.hxx"
96 #include "tabprotection.hxx"
97 #include "clipparam.hxx"
98 #include <basic/basmgr.hxx>
99 #include <com/sun/star/container/XContainer.hpp>
101 #include <map>
103 using namespace ::com::sun::star;
105 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
107 struct ScDefaultAttr
109 const ScPatternAttr* pAttr;
110 SCROW nFirst;
111 SCSIZE nCount;
112 ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
115 struct ScLessDefaultAttr
117 sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
119 return rValue1.pAttr < rValue2.pAttr;
123 typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
125 void ScDocument::MakeTable( SCTAB nTab )
127 if ( ValidTab(nTab) && !pTab[nTab] )
129 String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
130 aString += String::CreateFromInt32(nTab+1);
131 CreateValidTabName( aString ); // keine doppelten
133 pTab[nTab] = new ScTable(this, nTab, aString);
134 ++nMaxTableNumber;
139 BOOL ScDocument::HasTable( SCTAB nTab ) const
141 if (VALIDTAB(nTab))
142 if (pTab[nTab])
143 return TRUE;
145 return FALSE;
149 BOOL ScDocument::GetName( SCTAB nTab, String& rName ) const
151 if (VALIDTAB(nTab))
152 if (pTab[nTab])
154 pTab[nTab]->GetName( rName );
155 return TRUE;
157 rName.Erase();
158 return FALSE;
161 BOOL ScDocument::SetCodeName( SCTAB nTab, String& rName )
163 if (VALIDTAB(nTab))
165 if (pTab[nTab])
167 pTab[nTab]->SetCodeName( rName );
168 return TRUE;
171 OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
172 return FALSE;
175 BOOL ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
177 if (VALIDTAB(nTab))
178 if (pTab[nTab])
180 pTab[nTab]->GetCodeName( rName );
181 return TRUE;
183 rName.Erase();
184 return FALSE;
188 BOOL ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
190 String aUpperName = rName;
191 ScGlobal::pCharClass->toUpper(aUpperName);
193 for (SCTAB i=0; i<=MAXTAB; i++)
194 if (pTab[i])
196 if ( pTab[i]->GetUpperName() == aUpperName )
198 rTab = i;
199 return TRUE;
202 rTab = 0;
203 return FALSE;
207 BOOL ScDocument::ValidTabName( const String& rName ) const
209 xub_StrLen nLen = rName.Len();
210 if (!nLen)
211 return false;
213 #if 1
214 // Restrict sheet names to what Excel accepts.
215 /* TODO: We may want to remove this restriction for full ODFF compliance.
216 * Merely loading and calculating ODF documents using these characters in
217 * sheet names is not affected by this, but all sheet name editing and
218 * copying functionality is, maybe falling back to "Sheet4" or similar. */
219 for (xub_StrLen i = 0; i < nLen; ++i)
221 const sal_Unicode c = rName.GetChar(i);
222 switch (c)
224 case ':':
225 case '\\':
226 case '/':
227 case '?':
228 case '*':
229 case '[':
230 case ']':
231 // these characters are not allowed to match XL's convention.
232 return false;
233 case '\'':
234 if (i == 0 || i == nLen - 1)
235 // single quote is not allowed at the first or last
236 // character position.
237 return false;
238 break;
241 #endif
243 return true;
247 BOOL ScDocument::ValidNewTabName( const String& rName ) const
249 BOOL bValid = ValidTabName(rName);
250 for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
251 if (pTab[i])
253 String aOldName;
254 pTab[i]->GetName(aOldName);
255 bValid = !ScGlobal::pTransliteration->isEqual( rName, aOldName );
257 return bValid;
261 void ScDocument::CreateValidTabName(String& rName) const
263 if ( !ValidTabName(rName) )
265 // neu erzeugen
267 const String aStrTable( ScResId(SCSTR_TABLE) );
268 BOOL bOk = FALSE;
270 // vorneweg testen, ob der Prefix als gueltig erkannt wird
271 // wenn nicht, nur doppelte vermeiden
272 BOOL bPrefix = ValidTabName( aStrTable );
273 DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
274 SCTAB nDummy;
276 SCTAB nLoops = 0; // "zur Sicherheit"
277 for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
279 rName = aStrTable;
280 rName += String::CreateFromInt32(i);
281 if (bPrefix)
282 bOk = ValidNewTabName( rName );
283 else
284 bOk = !GetTable( rName, nDummy );
285 ++nLoops;
288 DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
289 if ( !bOk )
290 rName = aStrTable;
292 else
294 // uebergebenen Namen ueberpruefen
296 if ( !ValidNewTabName(rName) )
298 SCTAB i = 1;
299 String aName;
302 i++;
303 aName = rName;
304 aName += '_';
305 aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
307 while (!ValidNewTabName(aName) && (i < MAXTAB+1));
308 rName = aName;
314 BOOL ScDocument::InsertTab( SCTAB nPos, const String& rName,
315 BOOL bExternalDocument )
317 SCTAB nTabCount = GetTableCount();
318 BOOL bValid = ValidTab(nTabCount);
319 if ( !bExternalDocument ) // sonst rName == "'Doc'!Tab", vorher pruefen
320 bValid = (bValid && ValidNewTabName(rName));
321 if (bValid)
323 if (nPos == SC_TAB_APPEND || nPos == nTabCount)
325 pTab[nTabCount] = new ScTable(this, nTabCount, rName);
326 pTab[nTabCount]->SetCodeName( rName );
327 ++nMaxTableNumber;
328 if ( bExternalDocument )
329 pTab[nTabCount]->SetVisible( FALSE );
331 else
333 if (VALIDTAB(nPos) && (nPos < nTabCount))
335 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
336 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
337 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
338 pRangeName->UpdateTabRef( nPos, 1 );
339 pDBCollection->UpdateReference(
340 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
341 if (pDPCollection)
342 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
343 if (pDetOpList)
344 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
345 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
346 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
347 if ( pUnoBroadcaster )
348 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
350 SCTAB i;
351 for (i = 0; i <= MAXTAB; i++)
352 if (pTab[i])
353 pTab[i]->UpdateInsertTab(nPos);
355 for (i = nTabCount; i > nPos; i--)
357 pTab[i] = pTab[i - 1];
360 pTab[nPos] = new ScTable(this, nPos, rName);
361 pTab[nPos]->SetCodeName( rName );
362 ++nMaxTableNumber;
364 // UpdateBroadcastAreas must be called between UpdateInsertTab,
365 // which ends listening, and StartAllListeners, to not modify
366 // areas that are to be inserted by starting listeners.
367 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
368 for (i = 0; i <= MAXTAB; i++)
369 if (pTab[i])
370 pTab[i]->UpdateCompile();
371 for (i = 0; i <= MAXTAB; i++)
372 if (pTab[i])
373 pTab[i]->StartAllListeners();
375 // update conditional formats after table is inserted
376 if ( pCondFormList )
377 pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
378 if ( pValidationList )
379 pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
380 // #81844# sheet names of references are not valid until sheet is inserted
381 if ( pChartListenerCollection )
382 pChartListenerCollection->UpdateScheduledSeriesRanges();
384 // Update cells containing external references.
385 if (pExternalRefMgr.get())
386 pExternalRefMgr->updateRefInsertTable(nPos);
388 SetDirty();
389 bValid = TRUE;
391 else
392 bValid = FALSE;
395 return bValid;
399 BOOL ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
401 BOOL bValid = FALSE;
402 if (VALIDTAB(nTab))
404 if (pTab[nTab])
406 SCTAB nTabCount = GetTableCount();
407 if (nTabCount > 1)
409 BOOL bOldAutoCalc = GetAutoCalc();
410 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
411 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
412 DelBroadcastAreasInRange( aRange );
414 // #i8180# remove database ranges etc. that are on the deleted tab
415 // (restored in undo with ScRefUndoData)
417 xColNameRanges->DeleteOnTab( nTab );
418 xRowNameRanges->DeleteOnTab( nTab );
419 pDBCollection->DeleteOnTab( nTab );
420 if (pDPCollection)
421 pDPCollection->DeleteOnTab( nTab );
422 if (pDetOpList)
423 pDetOpList->DeleteOnTab( nTab );
424 DeleteAreaLinksOnTab( nTab );
426 // normal reference update
428 aRange.aEnd.SetTab( MAXTAB );
429 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
430 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
431 pRangeName->UpdateTabRef( nTab, 2 );
432 pDBCollection->UpdateReference(
433 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
434 if (pDPCollection)
435 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
436 if (pDetOpList)
437 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
438 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
439 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
440 if ( pCondFormList )
441 pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
442 if ( pValidationList )
443 pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
444 if ( pUnoBroadcaster )
445 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
447 SCTAB i;
448 for (i=0; i<=MAXTAB; i++)
449 if (pTab[i])
450 pTab[i]->UpdateDeleteTab(nTab,FALSE,
451 pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
452 delete pTab[nTab];
453 for (i=nTab + 1; i < nTabCount; i++)
455 pTab[i - 1] = pTab[i];
458 pTab[nTabCount - 1] = NULL;
459 --nMaxTableNumber;
460 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
461 // which ends listening, and StartAllListeners, to not modify
462 // areas that are to be inserted by starting listeners.
463 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
464 for (i = 0; i <= MAXTAB; i++)
465 if (pTab[i])
466 pTab[i]->UpdateCompile();
467 // Excel-Filter loescht einige Tables waehrend des Ladens,
468 // Listener werden erst nach dem Laden aufgesetzt
469 if ( !bInsertingFromOtherDoc )
471 for (i = 0; i <= MAXTAB; i++)
472 if (pTab[i])
473 pTab[i]->StartAllListeners();
474 SetDirty();
476 // #81844# sheet names of references are not valid until sheet is deleted
477 pChartListenerCollection->UpdateScheduledSeriesRanges();
480 // Update cells containing external references.
481 if (pExternalRefMgr.get())
482 pExternalRefMgr->updateRefDeleteTable(nTab);
484 SetAutoCalc( bOldAutoCalc );
485 bValid = TRUE;
489 return bValid;
493 BOOL ScDocument::RenameTab( SCTAB nTab, const String& rName, BOOL /* bUpdateRef */,
494 BOOL bExternalDocument )
496 BOOL bValid = FALSE;
497 SCTAB i;
498 if VALIDTAB(nTab)
499 if (pTab[nTab])
501 if ( bExternalDocument )
502 bValid = TRUE; // zusammengesetzter Name
503 else
504 bValid = ValidTabName(rName);
505 for (i=0; (i<=MAXTAB) && bValid; i++)
506 if (pTab[i] && (i != nTab))
508 String aOldName;
509 pTab[i]->GetName(aOldName);
510 bValid = !ScGlobal::pTransliteration->isEqual( rName, aOldName );
512 if (bValid)
514 // #i75258# update charts before renaming, so they can get their live data objects.
515 // Once the charts are live, the sheet can be renamed without problems.
516 if ( pChartListenerCollection )
517 pChartListenerCollection->UpdateChartsContainingTab( nTab );
518 pTab[nTab]->SetName(rName);
521 return bValid;
525 void ScDocument::SetVisible( SCTAB nTab, BOOL bVisible )
527 if (VALIDTAB(nTab))
528 if (pTab[nTab])
529 pTab[nTab]->SetVisible(bVisible);
533 BOOL ScDocument::IsVisible( SCTAB nTab ) const
535 if (VALIDTAB(nTab))
536 if (pTab[nTab])
537 return pTab[nTab]->IsVisible();
539 return FALSE;
543 BOOL ScDocument::IsPendingRowHeights( SCTAB nTab ) const
545 if ( ValidTab(nTab) && pTab[nTab] )
546 return pTab[nTab]->IsPendingRowHeights();
548 return FALSE;
552 void ScDocument::SetPendingRowHeights( SCTAB nTab, BOOL bSet )
554 if ( ValidTab(nTab) && pTab[nTab] )
555 pTab[nTab]->SetPendingRowHeights( bSet );
559 void ScDocument::SetLayoutRTL( SCTAB nTab, BOOL bRTL )
561 if ( ValidTab(nTab) && pTab[nTab] )
563 if ( bImportingXML )
565 // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
566 // is applied in SetImportingXML(FALSE). This is so the shapes can be loaded in
567 // normal LTR mode.
569 pTab[nTab]->SetLoadingRTL( bRTL );
570 return;
573 pTab[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
574 pTab[nTab]->SetDrawPageSize();
576 // mirror existing objects:
578 if (pDrawLayer)
580 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
581 DBG_ASSERT(pPage,"Page ?");
582 if (pPage)
584 SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
585 SdrObject* pObject = aIter.Next();
586 while (pObject)
588 // objects with ScDrawObjData are re-positioned in SetPageSize,
589 // don't mirror again
590 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
591 if ( !pData )
592 pDrawLayer->MirrorRTL( pObject );
594 pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
596 pObject = aIter.Next();
604 BOOL ScDocument::IsLayoutRTL( SCTAB nTab ) const
606 if ( ValidTab(nTab) && pTab[nTab] )
607 return pTab[nTab]->IsLayoutRTL();
609 return FALSE;
613 BOOL ScDocument::IsNegativePage( SCTAB nTab ) const
615 // Negative page area is always used for RTL layout.
616 // The separate method is used to find all RTL handling of drawing objects.
617 return IsLayoutRTL( nTab );
621 /* ----------------------------------------------------------------------------
622 benutzten Bereich suchen:
624 GetCellArea - nur Daten
625 GetTableArea - Daten / Attribute
626 GetPrintArea - beruecksichtigt auch Zeichenobjekte,
627 streicht Attribute bis ganz rechts / unten
628 ---------------------------------------------------------------------------- */
631 BOOL ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
633 if (VALIDTAB(nTab))
634 if (pTab[nTab])
635 return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
637 rEndCol = 0;
638 rEndRow = 0;
639 return FALSE;
643 BOOL ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
645 if (VALIDTAB(nTab))
646 if (pTab[nTab])
647 return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
649 rEndCol = 0;
650 rEndRow = 0;
651 return FALSE;
654 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
656 if (!ValidTab(nTab) || !pTab[nTab])
657 return false;
659 SCCOL nCol1, nCol2;
660 SCROW nRow1, nRow2;
661 pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
662 pTab[nTab]->GetLastDataPos(nCol2, nRow2);
664 if (nCol1 > nCol2 || nRow1 > nRow2)
665 // invalid range.
666 return false;
668 // Make sure the area only shrinks, and doesn't grow.
669 if (rStartCol < nCol1)
670 rStartCol = nCol1;
671 if (nCol2 < rEndCol)
672 rEndCol = nCol2;
673 if (rStartRow < nRow1)
674 rStartRow = nRow1;
675 if (nRow2 < rEndRow)
676 rEndRow = nRow2;
678 return true; // success!
681 // zusammenhaengender Bereich
683 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
684 SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld ) const
686 if (VALIDTAB(nTab))
687 if (pTab[nTab])
688 pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld );
692 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
693 SCCOL& rEndCol, SCROW& rEndRow )
695 if (VALIDTAB(nTab))
696 if (pTab[nTab])
697 pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
701 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
703 ScRangeListRef aNew = new ScRangeList;
704 if (rRangeList.Is())
706 ULONG nCount = rRangeList->Count();
707 for (ULONG i=0; i<nCount; i++)
709 ScRange aRange(*rRangeList->GetObject( i ));
710 if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
711 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
713 SCCOL nStartCol = aRange.aStart.Col();
714 SCROW nStartRow = aRange.aStart.Row();
715 SCCOL nEndCol = aRange.aEnd.Col();
716 SCROW nEndRow = aRange.aEnd.Row();
717 SCTAB nTab = aRange.aStart.Tab();
718 if (pTab[nTab])
719 pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
720 aRange.aStart.SetCol( nStartCol );
721 aRange.aStart.SetRow( nStartRow );
722 aRange.aEnd.SetCol( nEndCol );
723 aRange.aEnd.SetRow( nEndRow );
725 aNew->Append(aRange);
728 else
730 DBG_ERROR("LimitChartIfAll: Ref==0");
732 rRangeList = aNew;
736 void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
738 // without ScMarkData, leave start/end unchanged
739 if ( pTabMark )
741 for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
742 if (pTabMark->GetTableSelect(nTab))
744 // find first range of consecutive selected sheets
745 rTabRangeStart = nTab;
746 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
747 ++nTab;
748 rTabRangeEnd = nTab;
749 return;
754 bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
756 if ( pTabMark )
758 // find next range of consecutive selected sheets after rTabRangeEnd
759 for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
760 if (pTabMark->GetTableSelect(nTab))
762 rTabRangeStart = nTab;
763 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
764 ++nTab;
765 rTabRangeEnd = nTab;
766 return true;
769 return false;
773 BOOL ScDocument::CanInsertRow( const ScRange& rRange ) const
775 SCCOL nStartCol = rRange.aStart.Col();
776 SCROW nStartRow = rRange.aStart.Row();
777 SCTAB nStartTab = rRange.aStart.Tab();
778 SCCOL nEndCol = rRange.aEnd.Col();
779 SCROW nEndRow = rRange.aEnd.Row();
780 SCTAB nEndTab = rRange.aEnd.Tab();
781 PutInOrder( nStartCol, nEndCol );
782 PutInOrder( nStartRow, nEndRow );
783 PutInOrder( nStartTab, nEndTab );
784 SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
786 BOOL bTest = TRUE;
787 for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
788 if (pTab[i])
789 bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
791 return bTest;
795 BOOL ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
796 SCCOL nEndCol, SCTAB nEndTab,
797 SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
798 const ScMarkData* pTabMark )
800 SCTAB i;
802 PutInOrder( nStartCol, nEndCol );
803 PutInOrder( nStartTab, nEndTab );
804 if ( pTabMark )
806 nStartTab = 0;
807 nEndTab = MAXTAB;
810 BOOL bTest = TRUE;
811 BOOL bRet = FALSE;
812 BOOL bOldAutoCalc = GetAutoCalc();
813 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
814 for ( i = nStartTab; i <= nEndTab && bTest; i++)
815 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
816 bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
817 if (bTest)
819 // UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
820 // Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
822 // handle chunks of consecutive selected sheets together
823 SCTAB nTabRangeStart = nStartTab;
824 SCTAB nTabRangeEnd = nEndTab;
825 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
828 UpdateBroadcastAreas( URM_INSDEL, ScRange(
829 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
830 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
832 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
834 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
837 UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
838 nEndCol, MAXROW, nTabRangeEnd,
839 0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, FALSE ); // without drawing objects
841 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
843 for (i=nStartTab; i<=nEndTab; i++)
844 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
845 pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
847 // #82991# UpdateRef for drawing layer must be after inserting,
848 // when the new row heights are known.
849 for (i=nStartTab; i<=nEndTab; i++)
850 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
851 pTab[i]->UpdateDrawRef( URM_INSDEL,
852 nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
853 0, static_cast<SCsROW>(nSize), 0 );
855 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
856 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
857 // ein neues Listening faellig, bisherige Listener wurden in
858 // FormulaCell UpdateReference abgehaengt
859 StartAllListeners();
861 else
862 { // Listeners have been removed in UpdateReference
863 for (i=0; i<=MAXTAB; i++)
864 if (pTab[i])
865 pTab[i]->StartNeededListeners();
866 // #69592# at least all cells using range names pointing relative
867 // to the moved range must recalculate
868 for (i=0; i<=MAXTAB; i++)
869 if (pTab[i])
870 pTab[i]->SetRelNameDirty();
872 bRet = TRUE;
874 SetAutoCalc( bOldAutoCalc );
875 if ( bRet )
876 pChartListenerCollection->UpdateDirtyCharts();
877 return bRet;
881 BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
883 return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
884 rRange.aEnd.Col(), rRange.aEnd.Tab(),
885 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
886 pRefUndoDoc );
890 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
891 SCCOL nEndCol, SCTAB nEndTab,
892 SCROW nStartRow, SCSIZE nSize,
893 ScDocument* pRefUndoDoc, BOOL* pUndoOutline,
894 const ScMarkData* pTabMark )
896 SCTAB i;
898 PutInOrder( nStartCol, nEndCol );
899 PutInOrder( nStartTab, nEndTab );
900 if ( pTabMark )
902 nStartTab = 0;
903 nEndTab = MAXTAB;
906 BOOL bOldAutoCalc = GetAutoCalc();
907 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
909 // handle chunks of consecutive selected sheets together
910 SCTAB nTabRangeStart = nStartTab;
911 SCTAB nTabRangeEnd = nEndTab;
912 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
915 if ( ValidRow(nStartRow+nSize) )
917 DelBroadcastAreasInRange( ScRange(
918 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
919 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
920 UpdateBroadcastAreas( URM_INSDEL, ScRange(
921 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
922 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
924 else
925 DelBroadcastAreasInRange( ScRange(
926 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
927 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
929 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
931 if ( ValidRow(nStartRow+nSize) )
933 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
936 UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
937 nEndCol, MAXROW, nTabRangeEnd,
938 0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc );
940 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
943 if (pUndoOutline)
944 *pUndoOutline = FALSE;
946 for ( i = nStartTab; i <= nEndTab; i++)
947 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
948 pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
950 if ( ValidRow(nStartRow+nSize) )
951 { // Listeners have been removed in UpdateReference
952 for (i=0; i<=MAXTAB; i++)
953 if (pTab[i])
954 pTab[i]->StartNeededListeners();
955 // #69592# at least all cells using range names pointing relative to
956 // the moved range must recalculate
957 for (i=0; i<=MAXTAB; i++)
958 if (pTab[i])
959 pTab[i]->SetRelNameDirty();
962 SetAutoCalc( bOldAutoCalc );
963 pChartListenerCollection->UpdateDirtyCharts();
967 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
969 DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
970 rRange.aEnd.Col(), rRange.aEnd.Tab(),
971 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
972 pRefUndoDoc, pUndoOutline );
976 BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
978 SCCOL nStartCol = rRange.aStart.Col();
979 SCROW nStartRow = rRange.aStart.Row();
980 SCTAB nStartTab = rRange.aStart.Tab();
981 SCCOL nEndCol = rRange.aEnd.Col();
982 SCROW nEndRow = rRange.aEnd.Row();
983 SCTAB nEndTab = rRange.aEnd.Tab();
984 PutInOrder( nStartCol, nEndCol );
985 PutInOrder( nStartRow, nEndRow );
986 PutInOrder( nStartTab, nEndTab );
987 SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
989 BOOL bTest = TRUE;
990 for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
991 if (pTab[i])
992 bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
994 return bTest;
998 BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
999 SCROW nEndRow, SCTAB nEndTab,
1000 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1001 const ScMarkData* pTabMark )
1003 SCTAB i;
1005 PutInOrder( nStartRow, nEndRow );
1006 PutInOrder( nStartTab, nEndTab );
1007 if ( pTabMark )
1009 nStartTab = 0;
1010 nEndTab = MAXTAB;
1013 BOOL bTest = TRUE;
1014 BOOL bRet = FALSE;
1015 BOOL bOldAutoCalc = GetAutoCalc();
1016 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1017 for ( i = nStartTab; i <= nEndTab && bTest; i++)
1018 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1019 bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1020 if (bTest)
1022 // handle chunks of consecutive selected sheets together
1023 SCTAB nTabRangeStart = nStartTab;
1024 SCTAB nTabRangeEnd = nEndTab;
1025 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1028 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1029 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1030 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1032 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1034 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1037 UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
1038 MAXCOL, nEndRow, nTabRangeEnd,
1039 static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
1041 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1043 for (i=nStartTab; i<=nEndTab; i++)
1044 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1045 pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
1047 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1048 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1049 // ein neues Listening faellig, bisherige Listener wurden in
1050 // FormulaCell UpdateReference abgehaengt
1051 StartAllListeners();
1053 else
1054 { // Listeners have been removed in UpdateReference
1055 for (i=0; i<=MAXTAB; i++)
1056 if (pTab[i])
1057 pTab[i]->StartNeededListeners();
1058 // #69592# at least all cells using range names pointing relative
1059 // to the moved range must recalculate
1060 for (i=0; i<=MAXTAB; i++)
1061 if (pTab[i])
1062 pTab[i]->SetRelNameDirty();
1064 bRet = TRUE;
1066 SetAutoCalc( bOldAutoCalc );
1067 if ( bRet )
1068 pChartListenerCollection->UpdateDirtyCharts();
1069 return bRet;
1073 BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1075 return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1076 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1077 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1078 pRefUndoDoc );
1082 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1083 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1084 BOOL* pUndoOutline, const ScMarkData* pTabMark )
1086 SCTAB i;
1088 PutInOrder( nStartRow, nEndRow );
1089 PutInOrder( nStartTab, nEndTab );
1090 if ( pTabMark )
1092 nStartTab = 0;
1093 nEndTab = MAXTAB;
1096 BOOL bOldAutoCalc = GetAutoCalc();
1097 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1099 // handle chunks of consecutive selected sheets together
1100 SCTAB nTabRangeStart = nStartTab;
1101 SCTAB nTabRangeEnd = nEndTab;
1102 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1105 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1107 DelBroadcastAreasInRange( ScRange(
1108 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1109 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1110 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1111 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1112 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1114 else
1115 DelBroadcastAreasInRange( ScRange(
1116 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1117 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1119 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1121 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1123 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1126 UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1127 MAXCOL, nEndRow, nTabRangeEnd,
1128 -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
1130 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1133 if (pUndoOutline)
1134 *pUndoOutline = FALSE;
1136 for ( i = nStartTab; i <= nEndTab; i++)
1137 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1138 pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
1140 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1141 { // Listeners have been removed in UpdateReference
1142 for (i=0; i<=MAXTAB; i++)
1143 if (pTab[i])
1144 pTab[i]->StartNeededListeners();
1145 // #69592# at least all cells using range names pointing relative to
1146 // the moved range must recalculate
1147 for (i=0; i<=MAXTAB; i++)
1148 if (pTab[i])
1149 pTab[i]->SetRelNameDirty();
1152 SetAutoCalc( bOldAutoCalc );
1153 pChartListenerCollection->UpdateDirtyCharts();
1157 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
1159 DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1160 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1161 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1162 pRefUndoDoc, pUndoOutline );
1166 // fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
1167 // (ohne Paint)
1170 void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1171 ScRange& rColRange, BOOL& rInsCol, BOOL& rDelCol,
1172 ScRange& rRowRange, BOOL& rInsRow, BOOL& rDelRow )
1174 DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
1176 rInsCol = rDelCol = rInsRow = rDelRow = FALSE;
1178 SCCOL nStartX = rOld.aStart.Col();
1179 SCROW nStartY = rOld.aStart.Row();
1180 SCCOL nOldEndX = rOld.aEnd.Col();
1181 SCROW nOldEndY = rOld.aEnd.Row();
1182 SCCOL nNewEndX = rNew.aEnd.Col();
1183 SCROW nNewEndY = rNew.aEnd.Row();
1184 SCTAB nTab = rOld.aStart.Tab();
1186 // wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
1187 BOOL bGrowY = ( nNewEndY > nOldEndY );
1188 SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1189 SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1191 // Spalten
1193 if ( nNewEndX > nOldEndX ) // Spalten einfuegen
1195 rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1196 rInsCol = TRUE;
1198 else if ( nNewEndX < nOldEndX ) // Spalten loeschen
1200 rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1201 rDelCol = TRUE;
1204 // Zeilen
1206 if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
1208 rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1209 rInsRow = TRUE;
1211 else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
1213 rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1214 rDelRow = TRUE;
1219 BOOL ScDocument::HasPartOfMerged( const ScRange& rRange )
1221 BOOL bPart = FALSE;
1222 SCTAB nTab = rRange.aStart.Tab();
1224 SCCOL nStartX = rRange.aStart.Col();
1225 SCROW nStartY = rRange.aStart.Row();
1226 SCCOL nEndX = rRange.aEnd.Col();
1227 SCROW nEndY = rRange.aEnd.Row();
1229 if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1230 HASATTR_MERGED | HASATTR_OVERLAPPED ))
1232 ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1233 ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1235 bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1236 nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1238 return bPart;
1242 BOOL ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1244 if ( rOld == rNew )
1245 return TRUE;
1247 BOOL bOk = TRUE;
1248 BOOL bInsCol,bDelCol,bInsRow,bDelRow;
1249 ScRange aColRange,aRowRange;
1250 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1252 if ( bInsCol && !CanInsertCol( aColRange ) ) // Zellen am Rand ?
1253 bOk = FALSE;
1254 if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
1255 bOk = FALSE;
1257 if ( bInsCol || bDelCol )
1259 aColRange.aEnd.SetCol(MAXCOL);
1260 if ( HasPartOfMerged(aColRange) )
1261 bOk = FALSE;
1263 if ( bInsRow || bDelRow )
1265 aRowRange.aEnd.SetRow(MAXROW);
1266 if ( HasPartOfMerged(aRowRange) )
1267 bOk = FALSE;
1270 return bOk;
1274 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, BOOL bClear )
1276 if (bClear)
1277 DeleteAreaTab( rOld, IDF_ALL );
1279 BOOL bInsCol,bDelCol,bInsRow,bDelRow;
1280 ScRange aColRange,aRowRange;
1281 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1283 if ( bInsCol )
1284 InsertCol( aColRange ); // Spalten zuerst einfuegen
1285 if ( bInsRow )
1286 InsertRow( aRowRange );
1288 if ( bDelRow )
1289 DeleteRow( aRowRange ); // Zeilen zuerst loeschen
1290 if ( bDelCol )
1291 DeleteCol( aColRange );
1293 // Referenzen um eingefuegte Zeilen erweitern
1295 if ( bInsCol || bInsRow )
1297 ScRange aGrowSource = rOld;
1298 aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1299 aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1300 SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1301 SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1302 UpdateGrow( aGrowSource, nGrowX, nGrowY );
1307 void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
1308 SCCOL nCol2, SCROW nRow2,
1309 const ScMarkData& rMark, USHORT nDelFlag)
1311 PutInOrder( nCol1, nCol2 );
1312 PutInOrder( nRow1, nRow2 );
1313 BOOL bOldAutoCalc = GetAutoCalc();
1314 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1315 for (SCTAB i = 0; i <= MAXTAB; i++)
1316 if (pTab[i])
1317 if ( rMark.GetTableSelect(i) || bIsUndo )
1318 pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1319 SetAutoCalc( bOldAutoCalc );
1323 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1324 SCCOL nCol2, SCROW nRow2,
1325 SCTAB nTab, USHORT nDelFlag)
1327 PutInOrder( nCol1, nCol2 );
1328 PutInOrder( nRow1, nRow2 );
1329 if ( VALIDTAB(nTab) && pTab[nTab] )
1331 BOOL bOldAutoCalc = GetAutoCalc();
1332 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1333 pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1334 SetAutoCalc( bOldAutoCalc );
1339 void ScDocument::DeleteAreaTab( const ScRange& rRange, USHORT nDelFlag )
1341 for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1342 DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1343 rRange.aEnd.Col(), rRange.aEnd.Row(),
1344 nTab, nDelFlag );
1348 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1349 BOOL bColInfo, BOOL bRowInfo )
1351 if (bIsUndo)
1353 Clear();
1355 xPoolHelper = pSrcDoc->xPoolHelper;
1357 String aString;
1358 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
1359 if ( rTabSelection.GetTableSelect( nTab ) )
1361 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1362 nMaxTableNumber = nTab + 1;
1365 else
1367 DBG_ERROR("InitUndo");
1372 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1373 BOOL bColInfo, BOOL bRowInfo )
1375 if (bIsUndo)
1377 Clear();
1379 xPoolHelper = pSrcDoc->xPoolHelper;
1381 String aString;
1382 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1383 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1385 nMaxTableNumber = nTab2 + 1;
1387 else
1389 DBG_ERROR("InitUndo");
1394 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, BOOL bColInfo, BOOL bRowInfo )
1396 if (bIsUndo)
1398 String aString;
1399 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1400 if (!pTab[nTab])
1401 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1403 if ( nMaxTableNumber <= nTab2 )
1404 nMaxTableNumber = nTab2 + 1;
1406 else
1408 DBG_ERROR("InitUndo");
1413 void ScDocument::SetCutMode( BOOL bVal )
1415 if (bIsClip)
1416 GetClipParam().mbCutMode = bVal;
1417 else
1419 DBG_ERROR("SetCutMode without bIsClip");
1424 BOOL ScDocument::IsCutMode()
1426 if (bIsClip)
1427 return GetClipParam().mbCutMode;
1428 else
1430 DBG_ERROR("IsCutMode ohne bIsClip");
1431 return FALSE;
1436 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1437 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1438 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1439 const ScMarkData* pMarks, BOOL bColRowFlags )
1441 PutInOrder( nCol1, nCol2 );
1442 PutInOrder( nRow1, nRow2 );
1443 PutInOrder( nTab1, nTab2 );
1444 if( !pDestDoc->aDocName.Len() )
1445 pDestDoc->aDocName = aDocName;
1446 if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1448 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1449 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1450 for (SCTAB i = nTab1; i <= nTab2; i++)
1452 if (pTab[i] && pDestDoc->pTab[i])
1453 pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
1454 bOnlyMarked, pDestDoc->pTab[i], pMarks,
1455 FALSE, bColRowFlags );
1457 pDestDoc->SetAutoCalc( bOldAutoCalc );
1462 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1463 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1464 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1465 const ScMarkData* pMarks)
1467 PutInOrder( nCol1, nCol2 );
1468 PutInOrder( nRow1, nRow2 );
1469 PutInOrder( nTab1, nTab2 );
1470 if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1472 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1473 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1474 if (nTab1 > 0)
1475 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1477 for (SCTAB i = nTab1; i <= nTab2; i++)
1479 if (pTab[i] && pDestDoc->pTab[i])
1480 pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
1481 bOnlyMarked, pDestDoc->pTab[i], pMarks);
1484 if (nTab2 < MAXTAB)
1485 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1486 pDestDoc->SetAutoCalc( bOldAutoCalc );
1491 void ScDocument::CopyToDocument(const ScRange& rRange,
1492 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1493 const ScMarkData* pMarks, BOOL bColRowFlags)
1495 ScRange aNewRange = rRange;
1496 aNewRange.Justify();
1498 if( !pDestDoc->aDocName.Len() )
1499 pDestDoc->aDocName = aDocName;
1500 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1501 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1502 for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
1503 if (pTab[i] && pDestDoc->pTab[i])
1504 pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1505 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1506 nFlags, bOnlyMarked, pDestDoc->pTab[i],
1507 pMarks, FALSE, bColRowFlags);
1508 pDestDoc->SetAutoCalc( bOldAutoCalc );
1512 void ScDocument::UndoToDocument(const ScRange& rRange,
1513 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1514 const ScMarkData* pMarks)
1516 ScRange aNewRange = rRange;
1517 aNewRange.Justify();
1518 SCTAB nTab1 = aNewRange.aStart.Tab();
1519 SCTAB nTab2 = aNewRange.aEnd.Tab();
1521 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1522 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1523 if (nTab1 > 0)
1524 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1526 for (SCTAB i = nTab1; i <= nTab2; i++)
1528 if (pTab[i] && pDestDoc->pTab[i])
1529 pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1530 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1531 nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
1534 if (nTab2 < MAXTAB)
1535 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1536 pDestDoc->SetAutoCalc( bOldAutoCalc );
1540 void ScDocument::CopyToClip(SCCOL nCol1, SCROW nRow1,
1541 SCCOL nCol2, SCROW nRow2,
1542 BOOL bCut, ScDocument* pClipDoc,
1543 BOOL bAllTabs, const ScMarkData* pMarks,
1544 BOOL bKeepScenarioFlags, BOOL bIncludeObjects, BOOL bCloneNoteCaptions)
1546 DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
1548 if (!bIsClip)
1550 PutInOrder( nCol1, nCol2 );
1551 PutInOrder( nRow1, nRow2 );
1552 if (!pClipDoc)
1554 DBG_ERROR("CopyToClip: no ClipDoc");
1555 pClipDoc = SC_MOD()->GetClipDoc();
1558 ScRange aClipRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1559 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1560 rClipParam.maRanges.RemoveAll();
1561 rClipParam.maRanges.Append(aClipRange);
1562 pClipDoc->aDocName = aDocName;
1563 pClipDoc->ResetClip( this, pMarks );
1565 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
1567 for (SCTAB j = 0; j <= MAXTAB; j++)
1568 if (pTab[j] && pClipDoc->pTab[j])
1569 if ( bAllTabs || !pMarks || pMarks->GetTableSelect(j) )
1571 pTab[j]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[j], bKeepScenarioFlags, bCloneNoteCaptions);
1573 if ( pDrawLayer && bIncludeObjects )
1575 // also copy drawing objects
1577 Rectangle aObjRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, j );
1578 pDrawLayer->CopyToClip( pClipDoc, j, aObjRect );
1582 pClipDoc->GetClipParam().mbCutMode = bCut;
1586 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
1587 ScDocument* pClipDoc, const ScMarkData* pMarks,
1588 bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
1590 if (bIsClip)
1591 return;
1593 if (!pClipDoc)
1595 DBG_ERROR("CopyToClip: no ClipDoc");
1596 pClipDoc = SC_MOD()->GetClipDoc();
1599 pClipDoc->aDocName = aDocName;
1600 pClipDoc->SetClipParam(rClipParam);
1601 pClipDoc->ResetClip(this, pMarks);
1603 ScRange aClipRange = rClipParam.getWholeRange();
1604 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, false);
1606 for (SCTAB i = 0; i <= MAXTAB; ++i)
1608 if (!pTab[i] || !pClipDoc->pTab[i])
1609 continue;
1611 if (pMarks && !pMarks->GetTableSelect(i))
1612 continue;
1614 pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
1616 if (pDrawLayer && bIncludeObjects)
1618 // also copy drawing objects
1619 const ScRange aRange = rClipParam.getWholeRange();
1620 Rectangle aObjRect = GetMMRect(
1621 aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), i);
1622 pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
1626 // Make sure to mark overlapped cells.
1627 pClipDoc->ExtendMerge(aClipRange, true);
1630 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
1631 SCCOL nCol2, SCROW nRow2,
1632 SCTAB nTab, ScDocument* pClipDoc)
1634 if (!bIsClip)
1636 PutInOrder( nCol1, nCol2 );
1637 PutInOrder( nRow1, nRow2 );
1638 if (!pClipDoc)
1640 DBG_ERROR("CopyTabToClip: no ClipDoc");
1641 pClipDoc = SC_MOD()->GetClipDoc();
1644 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1645 pClipDoc->aDocName = aDocName;
1646 rClipParam.maRanges.RemoveAll();
1647 rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
1648 pClipDoc->ResetClip( this, nTab );
1650 if (pTab[nTab] && pClipDoc->pTab[nTab])
1651 pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], FALSE, TRUE);
1653 pClipDoc->GetClipParam().mbCutMode = false;
1658 void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsLink )
1660 DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
1661 "TransposeClip mit falschem Dokument" );
1663 // initialisieren
1664 // -> pTransClip muss vor dem Original-Dokument geloescht werden!
1666 pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
1668 // Bereiche uebernehmen
1670 pTransClip->pRangeName->FreeAll();
1671 for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
1673 USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1674 ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1675 if (!pTransClip->pRangeName->Insert(pData))
1676 delete pData;
1677 else
1678 pData->SetIndex(nIndex);
1681 // Daten
1683 ScRange aClipRange = GetClipParam().getWholeRange();
1684 if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
1686 for (SCTAB i=0; i<=MAXTAB; i++)
1687 if (pTab[i])
1689 DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
1690 pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1691 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
1692 pTransClip->pTab[i], nFlags, bAsLink );
1694 if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
1696 // Drawing objects are copied to the new area without transposing.
1697 // CopyFromClip is used to adjust the objects to the transposed block's
1698 // cell range area.
1699 // (pDrawLayer in the original clipboard document is set only if there
1700 // are drawing objects to copy)
1702 pTransClip->InitDrawLayer();
1703 Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1704 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
1705 Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
1706 static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
1707 static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
1708 pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
1712 pTransClip->SetClipParam(GetClipParam());
1713 pTransClip->GetClipParam().transpose();
1715 else
1717 DBG_ERROR("TransposeClip: zu gross");
1720 // Dies passiert erst beim Einfuegen...
1722 GetClipParam().mbCutMode = false;
1725 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
1727 std::set<USHORT> aUsedNames; // indexes of named ranges that are used in the copied cells
1728 for (SCTAB i = 0; i <= MAXTAB; ++i)
1729 if (pTab[i] && pClipDoc->pTab[i])
1730 if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
1731 pTab[i]->FindRangeNamesInUse(
1732 rClipRange.aStart.Col(), rClipRange.aStart.Row(),
1733 rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
1735 pClipDoc->pRangeName->FreeAll();
1736 for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
1738 USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1739 bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
1740 if (bInUse)
1742 ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1743 if (!pClipDoc->pRangeName->Insert(pData))
1744 delete pData;
1745 else
1746 pData->SetIndex(nIndex);
1751 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
1752 mpDoc(pDoc)
1754 mpDoc->MergeNumberFormatter(pSrcDoc);
1757 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
1759 mpDoc->pFormatExchangeList = NULL;
1762 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
1764 SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
1765 SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
1766 if (pOtherFormatter && pOtherFormatter != pThisFormatter)
1768 SvNumberFormatterIndexTable* pExchangeList =
1769 pThisFormatter->MergeFormatter(*(pOtherFormatter));
1770 if (pExchangeList->Count() > 0)
1771 pFormatExchangeList = pExchangeList;
1775 void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
1777 sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
1778 ScClipRangeNameData aClipRangeNames;
1780 // array containing range names which might need update of indices
1781 aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
1783 for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
1785 /* Copy only if the name doesn't exist in this document.
1786 If it exists we use the already existing name instead,
1787 another possibility could be to create new names if
1788 documents differ.
1789 A proper solution would ask the user how to proceed.
1790 The adjustment of the indices in the formulas is done later.
1792 ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
1793 USHORT k;
1794 if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
1796 aClipRangeNames.mpRangeNames[i] = NULL; // range name not inserted
1797 USHORT nOldIndex = pClipRangeData->GetIndex();
1798 USHORT nNewIndex = ((*pRangeName)[k])->GetIndex();
1799 aClipRangeNames.insert(nOldIndex, nNewIndex);
1800 if ( !aClipRangeNames.mbReplace )
1801 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1803 else
1805 ScRangeData* pData = new ScRangeData( *pClipRangeData );
1806 pData->SetDocument(this);
1807 if ( pRangeName->FindIndex( pData->GetIndex() ) )
1808 pData->SetIndex(0); // need new index, done in Insert
1809 if ( pRangeName->Insert( pData ) )
1811 aClipRangeNames.mpRangeNames[i] = pData;
1812 USHORT nOldIndex = pClipRangeData->GetIndex();
1813 USHORT nNewIndex = pData->GetIndex();
1814 aClipRangeNames.insert(nOldIndex, nNewIndex);
1815 if ( !aClipRangeNames.mbReplace )
1816 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1818 else
1819 { // must be an overflow
1820 delete pData;
1821 aClipRangeNames.mpRangeNames[i] = NULL;
1822 aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
1823 aClipRangeNames.mbReplace = true;
1827 rRangeNames = aClipRangeNames;
1830 void ScDocument::UpdateRangeNamesInFormulas(
1831 ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
1832 SCCOL nXw, SCROW nYw)
1834 // nXw and nYw are the extra width and height of the destination range
1835 // extended due to presence of merged cell(s).
1837 if (!rRangeNames.mbReplace)
1838 return;
1840 // first update all inserted named formulas if they contain other
1841 // range names and used indices changed
1842 sal_uInt16 nRangeNameCount = rRangeNames.mpRangeNames.size();
1843 for (sal_uInt16 i = 0; i < nRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
1845 if ( rRangeNames.mpRangeNames[i] )
1846 rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
1848 // then update the formulas, they might need just the updated range names
1849 for (ULONG nRange = 0; nRange < rDestRanges.Count(); ++nRange)
1851 const ScRange* pRange = rDestRanges.GetObject( nRange);
1852 SCCOL nCol1 = pRange->aStart.Col();
1853 SCROW nRow1 = pRange->aStart.Row();
1854 SCCOL nCol2 = pRange->aEnd.Col();
1855 SCROW nRow2 = pRange->aEnd.Row();
1857 SCCOL nC1 = nCol1;
1858 SCROW nR1 = nRow1;
1859 SCCOL nC2 = nC1 + nXw;
1860 if (nC2 > nCol2)
1861 nC2 = nCol2;
1862 SCROW nR2 = nR1 + nYw;
1863 if (nR2 > nRow2)
1864 nR2 = nRow2;
1869 for (SCTAB k = 0; k <= MAXTAB; k++)
1871 if ( pTab[k] && rMark.GetTableSelect(k) )
1872 pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
1873 nC2, nR2, rRangeNames.maRangeMap);
1875 nC1 = nC2 + 1;
1876 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
1877 } while (nC1 <= nCol2);
1878 nC1 = nCol1;
1879 nC2 = nC1 + nXw;
1880 if (nC2 > nCol2)
1881 nC2 = nCol2;
1882 nR1 = nR2 + 1;
1883 nR2 = Min((SCROW)(nR1 + nYw), nRow2);
1884 } while (nR1 <= nRow2);
1888 ScClipParam& ScDocument::GetClipParam()
1890 if (!mpClipParam.get())
1891 mpClipParam.reset(new ScClipParam);
1893 return *mpClipParam;
1896 void ScDocument::SetClipParam(const ScClipParam& rParam)
1898 mpClipParam.reset(new ScClipParam(rParam));
1901 BOOL ScDocument::IsClipboardSource() const
1903 ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
1904 return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
1905 xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
1909 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
1910 SCCOL nCol2, SCROW nRow2,
1911 const ScMarkData& rMark, USHORT nInsFlag )
1913 if (nInsFlag & IDF_CONTENTS)
1915 for (SCTAB i = 0; i <= MAXTAB; i++)
1916 if (pTab[i])
1917 if (rMark.GetTableSelect(i))
1918 pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
1923 void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
1924 SCCOL nCol2, SCROW nRow2,
1925 const ScMarkData& rMark, USHORT nInsFlag )
1927 if (nInsFlag & IDF_CONTENTS)
1929 ScBulkBroadcast aBulkBroadcast( GetBASM());
1930 for (SCTAB i = 0; i <= MAXTAB; i++)
1931 if (pTab[i])
1932 if (rMark.GetTableSelect(i))
1933 pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
1938 void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
1939 SCCOL nCol2, SCROW nRow2,
1940 const ScMarkData& rMark,
1941 SCsCOL nDx, SCsROW nDy,
1942 const ScCopyBlockFromClipParams* pCBFCP )
1944 ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
1945 SCTAB nTabEnd = pCBFCP->nTabEnd;
1946 SCTAB nClipTab = 0;
1947 for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1949 if (pTab[i] && rMark.GetTableSelect(i) )
1951 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1953 pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
1954 pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
1956 if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
1958 // also copy drawing objects
1960 // drawing layer must be created before calling CopyFromClip
1961 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
1962 DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
1963 if ( pDrawLayer )
1965 // For GetMMRect, the row heights in the target document must already be valid
1966 // (copied in an extra step before pasting, or updated after pasting cells, but
1967 // before pasting objects).
1969 Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
1970 nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
1971 Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
1972 pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
1973 ScAddress( nCol1, nRow1, i ), aDestRect );
1977 nClipTab = (nClipTab+1) % (MAXTAB+1);
1980 if ( pCBFCP->nInsFlag & IDF_CONTENTS )
1982 nClipTab = 0;
1983 for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1985 if (pTab[i] && rMark.GetTableSelect(i) )
1987 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1988 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
1990 // #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
1991 // must be handled in one UpdateReference call
1992 SCTAB nFollow = 0;
1993 while ( i + nFollow < nTabEnd
1994 && rMark.GetTableSelect( i + nFollow + 1 )
1995 && nClipTab + nFollow < MAXTAB
1996 && ppClipTab[nClipTab + nFollow + 1] )
1997 ++nFollow;
1999 if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
2001 BOOL bOldInserting = IsInsertingFromOtherDoc();
2002 SetInsertingFromOtherDoc( TRUE);
2003 UpdateReference( URM_MOVE,
2004 nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
2005 nDx, nDy, nDz, pCBFCP->pRefUndoDoc );
2006 SetInsertingFromOtherDoc( bOldInserting);
2008 else
2009 UpdateReference( URM_COPY,
2010 nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
2011 nDx, nDy, nDz, pCBFCP->pRefUndoDoc, FALSE );
2013 nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
2014 i = sal::static_int_cast<SCTAB>( i + nFollow );
2021 void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
2022 SCCOL nCol2, SCROW nRow2,
2023 const ScMarkData& rMark,
2024 SCsCOL nDx, SCsROW /* nDy */,
2025 const ScCopyBlockFromClipParams* pCBFCP,
2026 SCROW & rClipStartRow )
2028 // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2029 // nCol1/nRow1 etc. is in target doc
2031 // filtered state is taken from first used table in clipboard (as in GetClipArea)
2032 SCTAB nFlagTab = 0;
2033 ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
2034 while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
2035 ++nFlagTab;
2037 const ScBitMaskCompressedArray< SCROW, BYTE> & rSourceFlags =
2038 pCBFCP->pClipDoc->GetRowFlagsArray( nFlagTab);
2040 SCROW nSourceRow = rClipStartRow;
2041 SCROW nSourceEnd = 0;
2042 if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
2043 nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
2044 SCROW nDestRow = nRow1;
2046 while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2048 // skip filtered rows
2049 nSourceRow = rSourceFlags.GetFirstForCondition( nSourceRow, nSourceEnd, CR_FILTERED, 0);
2051 if ( nSourceRow <= nSourceEnd )
2053 // look for more non-filtered rows following
2054 SCROW nFollow = rSourceFlags.GetBitStateEnd( nSourceRow, CR_FILTERED, 0) - nSourceRow;
2055 if (nFollow > nSourceEnd - nSourceRow)
2056 nFollow = nSourceEnd - nSourceRow;
2057 if (nFollow > nRow2 - nDestRow)
2058 nFollow = nRow2 - nDestRow;
2060 SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2061 CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
2063 nSourceRow += nFollow + 1;
2064 nDestRow += nFollow + 1;
2067 rClipStartRow = nSourceRow;
2071 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2072 USHORT nInsFlag,
2073 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, BOOL bResetCut,
2074 BOOL bAsLink, BOOL bIncludeFiltered, BOOL bSkipAttrForEmpty,
2075 const ScRangeList * pDestRanges )
2077 if (!bIsClip)
2079 if (!pClipDoc)
2081 DBG_ERROR("CopyFromClip: no ClipDoc");
2082 pClipDoc = SC_MOD()->GetClipDoc();
2084 if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
2086 BOOL bOldAutoCalc = GetAutoCalc();
2087 SetAutoCalc( FALSE ); // avoid multiple recalculations
2089 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2091 ScClipRangeNameData aClipRangeNames;
2092 CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2094 SCCOL nAllCol1 = rDestRange.aStart.Col();
2095 SCROW nAllRow1 = rDestRange.aStart.Row();
2096 SCCOL nAllCol2 = rDestRange.aEnd.Col();
2097 SCROW nAllRow2 = rDestRange.aEnd.Row();
2099 SCCOL nXw = 0;
2100 SCROW nYw = 0;
2101 ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2102 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) // find largest merge overlap
2103 if (pClipDoc->pTab[nTab]) // all sheets of the clipboard content
2105 SCCOL nThisEndX = aClipRange.aEnd.Col();
2106 SCROW nThisEndY = aClipRange.aEnd.Row();
2107 pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2108 aClipRange.aStart.Row(),
2109 nThisEndX, nThisEndY, nTab );
2110 // only extra value from ExtendMerge
2111 nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2112 nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2113 if ( nThisEndX > nXw )
2114 nXw = nThisEndX;
2115 if ( nThisEndY > nYw )
2116 nYw = nThisEndY;
2119 SCCOL nDestAddX;
2120 SCROW nDestAddY;
2121 pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2122 nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2123 nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2125 /* Decide which contents to delete before copying. Delete all
2126 contents if nInsFlag contains any real content flag.
2127 #i102056# Notes are pasted from clipboard in a second pass,
2128 together with the special flag IDF_ADDNOTES that states to not
2129 overwrite/delete existing cells but to insert the notes into
2130 these cells. In this case, just delete old notes from the
2131 destination area. */
2132 USHORT nDelFlag = IDF_NONE;
2133 if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2134 nDelFlag |= IDF_NOTE;
2135 else if ( nInsFlag & IDF_CONTENTS )
2136 nDelFlag |= IDF_CONTENTS;
2137 // With bSkipAttrForEmpty, don't remove attributes, copy
2138 // on top of existing attributes instead.
2139 if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2140 nDelFlag |= IDF_ATTRIB;
2142 ScCopyBlockFromClipParams aCBFCP;
2143 aCBFCP.pRefUndoDoc = pRefUndoDoc;
2144 aCBFCP.pClipDoc = pClipDoc;
2145 aCBFCP.nInsFlag = nInsFlag;
2146 aCBFCP.bAsLink = bAsLink;
2147 aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2148 aCBFCP.nTabStart = MAXTAB; // wird in der Schleife angepasst
2149 aCBFCP.nTabEnd = 0; // wird in der Schleife angepasst
2151 // Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
2152 // die Draw-Seitengroesse neu berechnet werden muss
2153 //! nur wenn ganze Zeilen/Spalten kopiert werden?
2155 for (SCTAB j = 0; j <= MAXTAB; j++)
2156 if (pTab[j] && rMark.GetTableSelect(j))
2158 if ( j < aCBFCP.nTabStart )
2159 aCBFCP.nTabStart = j;
2160 aCBFCP.nTabEnd = j;
2161 pTab[j]->IncRecalcLevel();
2164 ScRangeList aLocalRangeList;
2165 if (!pDestRanges)
2167 aLocalRangeList.Append( rDestRange);
2168 pDestRanges = &aLocalRangeList;
2171 bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
2173 // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
2174 BOOL bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
2175 BOOL bOldDouble = ScColumn::bDoubleAlloc;
2176 if (bDoDouble)
2177 ScColumn::bDoubleAlloc = TRUE;
2179 SCCOL nClipStartCol = aClipRange.aStart.Col();
2180 SCROW nClipStartRow = aClipRange.aStart.Row();
2181 // WaE: commented because unused: SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
2182 SCROW nClipEndRow = aClipRange.aEnd.Row();
2183 for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
2185 const ScRange* pRange = pDestRanges->GetObject( nRange);
2186 SCCOL nCol1 = pRange->aStart.Col();
2187 SCROW nRow1 = pRange->aStart.Row();
2188 SCCOL nCol2 = pRange->aEnd.Col();
2189 SCROW nRow2 = pRange->aEnd.Row();
2191 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2193 SCCOL nC1 = nCol1;
2194 SCROW nR1 = nRow1;
2195 SCCOL nC2 = nC1 + nXw;
2196 if (nC2 > nCol2)
2197 nC2 = nCol2;
2198 SCROW nR2 = nR1 + nYw;
2199 if (nR2 > nRow2)
2200 nR2 = nRow2;
2204 // Pasting is done column-wise, when pasting to a filtered
2205 // area this results in partitioning and we have to
2206 // remember and reset the start row for each column until
2207 // it can be advanced for the next chunk of unfiltered
2208 // rows.
2209 SCROW nSaveClipStartRow = nClipStartRow;
2212 nClipStartRow = nSaveClipStartRow;
2213 SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2214 SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2215 if ( bIncludeFiltered )
2217 CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
2218 nDy, &aCBFCP );
2219 nClipStartRow += nR2 - nR1 + 1;
2221 else
2223 CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
2224 nDx, nDy, &aCBFCP, nClipStartRow );
2226 // Not needed for columns, but if it was this would be how to.
2227 //if (nClipStartCol > nClipEndCol)
2228 // nClipStartCol = pClipDoc->aClipRange.aStart.Col();
2229 nC1 = nC2 + 1;
2230 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
2231 } while (nC1 <= nCol2);
2232 if (nClipStartRow > nClipEndRow)
2233 nClipStartRow = aClipRange.aStart.Row();
2234 nC1 = nCol1;
2235 nC2 = nC1 + nXw;
2236 if (nC2 > nCol2)
2237 nC2 = nCol2;
2238 nR1 = nR2 + 1;
2239 nR2 = Min((SCROW)(nR1 + nYw), nRow2);
2240 } while (nR1 <= nRow2);
2243 ScColumn::bDoubleAlloc = bOldDouble;
2245 for (SCTAB k = 0; k <= MAXTAB; k++)
2246 if (pTab[k] && rMark.GetTableSelect(k))
2247 pTab[k]->DecRecalcLevel();
2249 bInsertingFromOtherDoc = FALSE;
2251 UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
2253 // Listener aufbauen nachdem alles inserted wurde
2254 StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2255 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2256 BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2257 if (bResetCut)
2258 pClipDoc->GetClipParam().mbCutMode = false;
2259 SetAutoCalc( bOldAutoCalc );
2264 void ScDocument::CopyMultiRangeFromClip(
2265 const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2266 bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2268 if (bIsClip)
2269 return;
2271 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2272 // There is nothing in the clip doc to copy.
2273 return;
2275 BOOL bOldAutoCalc = GetAutoCalc();
2276 SetAutoCalc( FALSE ); // avoid multiple recalculations
2278 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2280 ScClipRangeNameData aClipRangeNames;
2281 CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2283 SCCOL nCol1 = rDestPos.Col();
2284 SCROW nRow1 = rDestPos.Row();
2285 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2287 ScCopyBlockFromClipParams aCBFCP;
2288 aCBFCP.pRefUndoDoc = NULL;
2289 aCBFCP.pClipDoc = pClipDoc;
2290 aCBFCP.nInsFlag = nInsFlag;
2291 aCBFCP.bAsLink = bAsLink;
2292 aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2293 aCBFCP.nTabStart = MAXTAB;
2294 aCBFCP.nTabEnd = 0;
2296 SCCOL nCols = rClipParam.getPasteColSize();
2297 SCROW nRows = rClipParam.getPasteRowSize();
2298 for (SCTAB j = 0; j <= MAXTAB; ++j)
2300 if (pTab[j] && rMark.GetTableSelect(j))
2302 if ( j < aCBFCP.nTabStart )
2303 aCBFCP.nTabStart = j;
2304 aCBFCP.nTabEnd = j;
2305 pTab[j]->IncRecalcLevel();
2309 bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
2311 if (!bSkipAttrForEmpty)
2313 sal_uInt16 nDelFlag = IDF_CONTENTS;
2314 DeleteArea(nCol1, nRow1, nCol1+nCols-1, nRow1+nRows-1, rMark, nDelFlag);
2317 for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
2319 SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2320 SCsROW nDy = static_cast<SCsROW>(nRow1 - p->aStart.Row());
2321 SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2322 SCROW nRow2 = nRow1 + p->aEnd.Row() - p->aStart.Row();
2324 CopyBlockFromClip(nCol1, nRow1, nCol2, nRow2, rMark, nDx, nDy, &aCBFCP);
2326 if (rClipParam.meDirection == ScClipParam::Column)
2327 nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2328 if (rClipParam.meDirection == ScClipParam::Row)
2329 nRow1 += p->aEnd.Row() - p->aStart.Row() + 1;
2332 for (SCTAB i = 0; i <= MAXTAB; i++)
2333 if (pTab[i] && rMark.GetTableSelect(i))
2334 pTab[i]->DecRecalcLevel();
2336 bInsertingFromOtherDoc = FALSE;
2338 ScRange aDestRange(rDestPos.Col(), rDestPos.Row(), rDestPos.Tab(),
2339 rDestPos.Col()+nCols-1, rDestPos.Row()+nRows-1, rDestPos.Tab());
2340 ScRangeList aRanges;
2341 aRanges.Append(aDestRange);
2342 UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
2344 // Listener aufbauen nachdem alles inserted wurde
2345 StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2346 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2347 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2348 BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2349 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2351 if (bResetCut)
2352 pClipDoc->GetClipParam().mbCutMode = false;
2353 SetAutoCalc( bOldAutoCalc );
2356 void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
2358 if (bIsClip)
2360 ScClipParam& rClipParam = GetClipParam();
2361 rClipParam.maRanges.RemoveAll();
2362 rClipParam.maRanges.Append(rArea);
2363 rClipParam.mbCutMode = bCut;
2365 else
2367 DBG_ERROR("SetClipArea: kein Clip");
2372 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered)
2374 if (!bIsClip)
2376 DBG_ERROR("GetClipArea: kein Clip");
2377 return;
2380 ScRangeList& rClipRanges = GetClipParam().maRanges;
2381 if (!rClipRanges.Count())
2382 // No clip range. Bail out.
2383 return;
2385 ScRangePtr p = rClipRanges.First();
2386 SCCOL nStartCol = p->aStart.Col();
2387 SCCOL nEndCol = p->aEnd.Col();
2388 SCROW nStartRow = p->aStart.Row();
2389 SCROW nEndRow = p->aEnd.Row();
2390 for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
2392 if (p->aStart.Col() < nStartCol)
2393 nStartCol = p->aStart.Col();
2394 if (p->aStart.Row() < nStartRow)
2395 nStartRow = p->aStart.Row();
2396 if (p->aEnd.Col() > nEndCol)
2397 nEndCol = p->aEnd.Col();
2398 if (p->aEnd.Row() < nEndRow)
2399 nEndRow = p->aEnd.Row();
2402 nClipX = nEndCol - nStartCol;
2404 if ( bIncludeFiltered )
2405 nClipY = nEndRow - nStartRow;
2406 else
2408 // count non-filtered rows
2409 // count on first used table in clipboard
2410 SCTAB nCountTab = 0;
2411 while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2412 ++nCountTab;
2414 SCROW nResult = GetRowFlagsArray( nCountTab).CountForCondition(
2415 nStartRow, nEndRow, CR_FILTERED, 0);
2417 if ( nResult > 0 )
2418 nClipY = nResult - 1;
2419 else
2420 nClipY = 0; // always return at least 1 row
2425 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2427 if (bIsClip)
2429 ScRangeList& rClipRanges = GetClipParam().maRanges;
2430 if (rClipRanges.Count())
2432 nClipX = rClipRanges.First()->aStart.Col();
2433 nClipY = rClipRanges.First()->aStart.Row();
2436 else
2438 DBG_ERROR("GetClipStart: kein Clip");
2443 BOOL ScDocument::HasClipFilteredRows()
2445 // count on first used table in clipboard
2446 SCTAB nCountTab = 0;
2447 while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2448 ++nCountTab;
2450 ScRangeList& rClipRanges = GetClipParam().maRanges;
2451 if (!rClipRanges.Count())
2452 return false;
2454 return GetRowFlagsArray( nCountTab).HasCondition( rClipRanges.First()->aStart.Row(),
2455 rClipRanges.First()->aEnd.Row(), CR_FILTERED, CR_FILTERED);
2459 void ScDocument::MixDocument( const ScRange& rRange, USHORT nFunction, BOOL bSkipEmpty,
2460 ScDocument* pSrcDoc )
2462 SCTAB nTab1 = rRange.aStart.Tab();
2463 SCTAB nTab2 = rRange.aEnd.Tab();
2464 for (SCTAB i = nTab1; i <= nTab2; i++)
2465 if (pTab[i] && pSrcDoc->pTab[i])
2466 pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
2467 rRange.aEnd.Col(), rRange.aEnd.Row(),
2468 nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
2472 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2473 USHORT nFlags, USHORT nFunction,
2474 BOOL bSkipEmpty, BOOL bAsLink )
2476 USHORT nDelFlags = nFlags;
2477 if (nDelFlags & IDF_CONTENTS)
2478 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
2480 SCTAB nSrcTab = rSrcArea.aStart.Tab();
2482 if (ValidTab(nSrcTab) && pTab[nSrcTab])
2484 SCCOL nStartCol = rSrcArea.aStart.Col();
2485 SCROW nStartRow = rSrcArea.aStart.Row();
2486 SCCOL nEndCol = rSrcArea.aEnd.Col();
2487 SCROW nEndRow = rSrcArea.aEnd.Row();
2488 ScDocument* pMixDoc = NULL;
2489 BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2491 BOOL bOldAutoCalc = GetAutoCalc();
2492 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
2494 SCTAB nCount = GetTableCount();
2495 for (SCTAB i=0; i<nCount; i++)
2496 if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2498 if (bDoMix)
2500 if (!pMixDoc)
2502 pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2503 pMixDoc->InitUndo( this, i, i );
2505 else
2506 pMixDoc->AddUndoTab( i, i );
2507 pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2508 IDF_CONTENTS, FALSE, pMixDoc->pTab[i] );
2510 pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
2511 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2512 nFlags, FALSE, pTab[i], NULL, bAsLink );
2514 if (bDoMix)
2515 pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
2516 nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2519 delete pMixDoc;
2521 SetAutoCalc( bOldAutoCalc );
2523 else
2525 DBG_ERROR("falsche Tabelle");
2530 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
2531 USHORT nFlags, USHORT nFunction,
2532 BOOL bSkipEmpty, BOOL bAsLink )
2534 USHORT nDelFlags = nFlags;
2535 if (nDelFlags & IDF_CONTENTS)
2536 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
2538 if (ValidTab(nSrcTab) && pTab[nSrcTab])
2540 ScDocument* pMixDoc = NULL;
2541 BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2543 BOOL bOldAutoCalc = GetAutoCalc();
2544 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
2546 ScRange aArea;
2547 rMark.GetMultiMarkArea( aArea );
2548 SCCOL nStartCol = aArea.aStart.Col();
2549 SCROW nStartRow = aArea.aStart.Row();
2550 SCCOL nEndCol = aArea.aEnd.Col();
2551 SCROW nEndRow = aArea.aEnd.Row();
2553 SCTAB nCount = GetTableCount();
2554 for (SCTAB i=0; i<nCount; i++)
2555 if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2557 if (bDoMix)
2559 if (!pMixDoc)
2561 pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2562 pMixDoc->InitUndo( this, i, i );
2564 else
2565 pMixDoc->AddUndoTab( i, i );
2566 pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2567 IDF_CONTENTS, TRUE, pMixDoc->pTab[i], &rMark );
2570 pTab[i]->DeleteSelection( nDelFlags, rMark );
2571 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2572 nFlags, TRUE, pTab[i], &rMark, bAsLink );
2574 if (bDoMix)
2575 pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2578 delete pMixDoc;
2580 SetAutoCalc( bOldAutoCalc );
2582 else
2584 DBG_ERROR("falsche Tabelle");
2589 void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, BOOL bForceTab )
2591 if (VALIDTAB(nTab))
2593 if ( bForceTab && !pTab[nTab] )
2595 BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
2597 pTab[nTab] = new ScTable(this, nTab,
2598 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2599 bExtras, bExtras);
2600 ++nMaxTableNumber;
2603 if (pTab[nTab])
2604 pTab[nTab]->PutCell( nCol, nRow, pCell );
2609 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, BOOL bForceTab )
2611 SCTAB nTab = rPos.Tab();
2612 if ( bForceTab && !pTab[nTab] )
2614 BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
2616 pTab[nTab] = new ScTable(this, nTab,
2617 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2618 bExtras, bExtras);
2619 ++nMaxTableNumber;
2622 if (pTab[nTab])
2623 pTab[nTab]->PutCell( rPos, pCell );
2627 BOOL ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2628 SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
2630 if ( ValidTab(nTab) && pTab[nTab] )
2631 return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
2632 else
2633 return FALSE;
2637 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
2639 if (VALIDTAB(nTab))
2640 if (pTab[nTab])
2641 pTab[nTab]->SetValue( nCol, nRow, rVal );
2645 void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2647 if ( VALIDTAB(nTab) && pTab[nTab] )
2648 pTab[nTab]->GetString( nCol, nRow, rString );
2649 else
2650 rString.Erase();
2654 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2656 if ( VALIDTAB(nTab) && pTab[nTab] )
2657 pTab[nTab]->GetInputString( nCol, nRow, rString );
2658 else
2659 rString.Erase();
2663 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
2665 if ( VALIDTAB(nTab) && pTab[nTab] )
2666 rValue = pTab[nTab]->GetValue( nCol, nRow );
2667 else
2668 rValue = 0.0;
2672 double ScDocument::GetValue( const ScAddress& rPos )
2674 SCTAB nTab = rPos.Tab();
2675 if ( pTab[nTab] )
2676 return pTab[nTab]->GetValue( rPos );
2677 return 0.0;
2681 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
2682 sal_uInt32& rFormat )
2684 if (VALIDTAB(nTab))
2685 if (pTab[nTab])
2687 rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
2688 return ;
2690 rFormat = 0;
2693 sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
2695 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
2696 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
2697 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
2699 if (!ValidTab(nTab1) || !ValidTab(nTab2) || !pTab[nTab1] || !pTab[nTab2])
2700 return 0;
2702 sal_uInt32 nFormat = 0;
2703 bool bFirstItem = true;
2704 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
2705 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2707 sal_uInt32 nThisFormat = pTab[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
2708 if (bFirstItem)
2710 nFormat = nThisFormat;
2711 bFirstItem = false;
2713 else if (nThisFormat != nFormat)
2714 return 0;
2717 return nFormat;
2720 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
2722 SCTAB nTab = rPos.Tab();
2723 if ( pTab[nTab] )
2724 return pTab[nTab]->GetNumberFormat( rPos );
2725 return 0;
2729 void ScDocument::GetNumberFormatInfo( short& nType, ULONG& nIndex,
2730 const ScAddress& rPos, const ScBaseCell* pCell ) const
2732 SCTAB nTab = rPos.Tab();
2733 if ( pTab[nTab] )
2735 nIndex = pTab[nTab]->GetNumberFormat( rPos );
2736 if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
2737 pCell->GetCellType() == CELLTYPE_FORMULA )
2738 static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
2739 else
2740 nType = GetFormatTable()->GetType( nIndex );
2742 else
2744 nType = NUMBERFORMAT_UNDEFINED;
2745 nIndex = 0;
2750 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
2751 BOOL bAsciiExport ) const
2753 if ( VALIDTAB(nTab) && pTab[nTab] )
2754 pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
2755 else
2756 rFormula.Erase();
2760 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
2762 SCTAB nTab = rPos.Tab();
2763 if ( pTab[nTab] )
2764 return pTab[nTab]->GetCellType( rPos );
2765 return CELLTYPE_NONE;
2769 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
2770 CellType& rCellType ) const
2772 if (ValidTab(nTab) && pTab[nTab])
2773 rCellType = pTab[nTab]->GetCellType( nCol, nRow );
2774 else
2775 rCellType = CELLTYPE_NONE;
2779 void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
2780 ScBaseCell*& rpCell ) const
2782 if (ValidTab(nTab) && pTab[nTab])
2783 rpCell = pTab[nTab]->GetCell( nCol, nRow );
2784 else
2786 DBG_ERROR("GetCell ohne Tabelle");
2787 rpCell = NULL;
2792 ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
2794 SCTAB nTab = rPos.Tab();
2795 if (ValidTab(nTab) && pTab[nTab])
2796 return pTab[nTab]->GetCell( rPos );
2798 DBG_ERROR("GetCell ohne Tabelle");
2799 return NULL;
2803 BOOL ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2805 if ( VALIDTAB(nTab) && pTab[nTab] )
2806 return pTab[nTab]->HasStringData( nCol, nRow );
2807 else
2808 return FALSE;
2812 BOOL ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2814 if ( VALIDTAB(nTab) && pTab[nTab] )
2815 return pTab[nTab]->HasValueData( nCol, nRow );
2816 else
2817 return FALSE;
2821 BOOL ScDocument::HasStringCells( const ScRange& rRange ) const
2823 // TRUE, wenn String- oder Editzellen im Bereich
2825 SCCOL nStartCol = rRange.aStart.Col();
2826 SCROW nStartRow = rRange.aStart.Row();
2827 SCTAB nStartTab = rRange.aStart.Tab();
2828 SCCOL nEndCol = rRange.aEnd.Col();
2829 SCROW nEndRow = rRange.aEnd.Row();
2830 SCTAB nEndTab = rRange.aEnd.Tab();
2832 for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
2833 if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
2834 return TRUE;
2836 return FALSE;
2840 BOOL ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2842 sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
2843 if( nValidation )
2845 const ScValidationData* pData = GetValidationEntry( nValidation );
2846 if( pData && pData->HasSelectionList() )
2847 return TRUE;
2849 return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
2853 ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
2855 ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2856 return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
2860 void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
2862 if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2863 pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
2864 else
2865 DELETEZ( rpNote );
2869 ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
2871 ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2872 return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
2876 ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
2878 ScPostIt* pNote = GetNote( rPos );
2879 if( !pNote )
2881 pNote = new ScPostIt( *this, rPos, false );
2882 TakeNote( rPos, pNote );
2884 return pNote;
2888 void ScDocument::DeleteNote( const ScAddress& rPos )
2890 if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2891 pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
2895 void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
2897 if( ValidTab( nTab ) && pTab[ nTab ] )
2898 pTab[ nTab ]->InitializeNoteCaptions( bForced );
2901 void ScDocument::InitializeAllNoteCaptions( bool bForced )
2903 for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
2904 InitializeNoteCaptions( nTab, bForced );
2907 void ScDocument::SetDirty()
2909 BOOL bOldAutoCalc = GetAutoCalc();
2910 bAutoCalc = FALSE; // keine Mehrfachberechnung
2911 { // scope for bulk broadcast
2912 ScBulkBroadcast aBulkBroadcast( GetBASM());
2913 for (SCTAB i=0; i<=MAXTAB; i++)
2914 if (pTab[i]) pTab[i]->SetDirty();
2917 // Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
2918 // wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
2919 // (#45205#) - darum alle Charts nochmal explizit
2920 if (pChartListenerCollection)
2921 pChartListenerCollection->SetDirty();
2923 SetAutoCalc( bOldAutoCalc );
2927 void ScDocument::SetDirty( const ScRange& rRange )
2929 BOOL bOldAutoCalc = GetAutoCalc();
2930 bAutoCalc = FALSE; // keine Mehrfachberechnung
2931 { // scope for bulk broadcast
2932 ScBulkBroadcast aBulkBroadcast( GetBASM());
2933 SCTAB nTab2 = rRange.aEnd.Tab();
2934 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2935 if (pTab[i]) pTab[i]->SetDirty( rRange );
2937 SetAutoCalc( bOldAutoCalc );
2941 void ScDocument::SetTableOpDirty( const ScRange& rRange )
2943 BOOL bOldAutoCalc = GetAutoCalc();
2944 bAutoCalc = FALSE; // no multiple recalculation
2945 SCTAB nTab2 = rRange.aEnd.Tab();
2946 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2947 if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
2948 SetAutoCalc( bOldAutoCalc );
2952 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
2954 ScInterpreterTableOpParams* p = aTableOpList.Last();
2955 if ( p && p->bCollectNotifications )
2957 if ( p->bRefresh )
2958 { // refresh pointers only
2959 p->aNotifiedFormulaCells.push_back( pCell );
2961 else
2962 { // init both, address and pointer
2963 p->aNotifiedFormulaCells.push_back( pCell );
2964 p->aNotifiedFormulaPos.push_back( pCell->aPos );
2970 void ScDocument::CalcAll()
2972 ClearLookupCaches(); // Ensure we don't deliver zombie data.
2973 BOOL bOldAutoCalc = GetAutoCalc();
2974 SetAutoCalc( TRUE );
2975 SCTAB i;
2976 for (i=0; i<=MAXTAB; i++)
2977 if (pTab[i]) pTab[i]->SetDirtyVar();
2978 for (i=0; i<=MAXTAB; i++)
2979 if (pTab[i]) pTab[i]->CalcAll();
2980 ClearFormulaTree();
2981 SetAutoCalc( bOldAutoCalc );
2985 void ScDocument::CompileAll()
2987 if ( pCondFormList )
2988 pCondFormList->CompileAll();
2990 for (SCTAB i=0; i<=MAXTAB; i++)
2991 if (pTab[i]) pTab[i]->CompileAll();
2992 SetDirty();
2996 void ScDocument::CompileXML()
2998 BOOL bOldAutoCalc = GetAutoCalc();
2999 SetAutoCalc( FALSE );
3000 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3001 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3003 // #b6355215# set AutoNameCache to speed up automatic name lookup
3004 DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
3005 pAutoNameCache = new ScAutoNameCache( this );
3007 for (SCTAB i=0; i<=MAXTAB; i++)
3008 if (pTab[i]) pTab[i]->CompileXML( aProgress );
3010 DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
3012 if ( pCondFormList )
3013 pCondFormList->CompileXML();
3014 if ( pValidationList )
3015 pValidationList->CompileXML();
3017 SetDirty();
3018 SetAutoCalc( bOldAutoCalc );
3022 void ScDocument::CalcAfterLoad()
3024 SCTAB i;
3026 if (bIsClip) // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3027 return; // dann wird erst beim Einfuegen in das richtige Doc berechnet
3029 bCalcingAfterLoad = TRUE;
3030 for ( i = 0; i <= MAXTAB; i++)
3031 if (pTab[i]) pTab[i]->CalcAfterLoad();
3032 for (i=0; i<=MAXTAB; i++)
3033 if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
3034 bCalcingAfterLoad = FALSE;
3036 SetDetectiveDirty(FALSE); // noch keine wirklichen Aenderungen
3040 USHORT ScDocument::GetErrCode( const ScAddress& rPos ) const
3042 SCTAB nTab = rPos.Tab();
3043 if ( pTab[nTab] )
3044 return pTab[nTab]->GetErrCode( rPos );
3045 return 0;
3049 void ScDocument::ResetChanged( const ScRange& rRange )
3051 SCTAB nStartTab = rRange.aStart.Tab();
3052 SCTAB nEndTab = rRange.aEnd.Tab();
3053 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
3054 if (pTab[nTab])
3055 pTab[nTab]->ResetChanged( rRange );
3059 // Spaltenbreiten / Zeilenhoehen --------------------------------------
3063 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, USHORT nNewWidth )
3065 if ( ValidTab(nTab) && pTab[nTab] )
3066 pTab[nTab]->SetColWidth( nCol, nNewWidth );
3070 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, USHORT nNewHeight )
3072 if ( ValidTab(nTab) && pTab[nTab] )
3073 pTab[nTab]->SetRowHeight( nRow, nNewHeight );
3077 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nNewHeight )
3079 if ( ValidTab(nTab) && pTab[nTab] )
3080 pTab[nTab]->SetRowHeightRange
3081 ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3085 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BOOL bManual )
3087 if ( ValidTab(nTab) && pTab[nTab] )
3088 pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3092 USHORT ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
3094 if ( ValidTab(nTab) && pTab[nTab] )
3095 return pTab[nTab]->GetColWidth( nCol );
3096 DBG_ERROR("Falsche Tabellennummer");
3097 return 0;
3101 USHORT ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3103 if ( ValidTab(nTab) && pTab[nTab] )
3104 return pTab[nTab]->GetOriginalWidth( nCol );
3105 DBG_ERROR("Falsche Tabellennummer");
3106 return 0;
3110 USHORT ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3112 if ( ValidTab(nTab) && pTab[nTab] )
3113 return pTab[nTab]->GetCommonWidth( nEndCol );
3114 DBG_ERROR("Wrong table number");
3115 return 0;
3119 USHORT ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3121 if ( ValidTab(nTab) && pTab[nTab] )
3122 return pTab[nTab]->GetOriginalHeight( nRow );
3123 DBG_ERROR("Wrong table number");
3124 return 0;
3128 USHORT ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab ) const
3130 if ( ValidTab(nTab) && pTab[nTab] )
3131 return pTab[nTab]->GetRowHeight( nRow );
3132 DBG_ERROR("Falsche Tabellennummer");
3133 return 0;
3137 ULONG ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3139 if (nStartRow == nEndRow)
3140 return GetRowHeight( nStartRow, nTab); // faster for a single row
3142 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3143 if (nStartRow > nEndRow)
3144 return 0;
3146 if ( ValidTab(nTab) && pTab[nTab] )
3147 return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
3149 DBG_ERROR("wrong sheet number");
3150 return 0;
3153 ULONG ScDocument::FastGetRowHeight( SCROW nStartRow, SCROW nEndRow,
3154 SCTAB nTab ) const
3156 return pTab[nTab]->pRowFlags->SumCoupledArrayForCondition( nStartRow,
3157 nEndRow, CR_HIDDEN, 0, *(pTab[nTab]->pRowHeight));
3160 ULONG ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3161 SCTAB nTab, double fScale ) const
3163 // faster for a single row
3164 if (nStartRow == nEndRow)
3165 return (ULONG) (GetRowHeight( nStartRow, nTab) * fScale);
3167 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3168 if (nStartRow > nEndRow)
3169 return 0;
3171 if ( ValidTab(nTab) && pTab[nTab] )
3172 return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3174 DBG_ERROR("wrong sheet number");
3175 return 0;
3179 const ScSummableCompressedArray< SCROW, USHORT> & ScDocument::GetRowHeightArray(
3180 SCTAB nTab ) const
3182 const ScSummableCompressedArray< SCROW, USHORT> * pHeight;
3183 if ( ValidTab(nTab) && pTab[nTab] )
3184 pHeight = pTab[nTab]->GetRowHeightArray();
3185 else
3187 DBG_ERROR("wrong sheet number");
3188 pHeight = 0;
3190 if (!pHeight)
3192 DBG_ERROR("no row heights at sheet");
3193 static ScSummableCompressedArray< SCROW, USHORT> aDummy( MAXROW,
3194 ScGlobal::nStdRowHeight);
3195 pHeight = &aDummy;
3197 return *pHeight;
3201 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3203 if ( ValidTab(nTab) && pTab[nTab] )
3204 return pTab[nTab]->GetHiddenRowCount( nRow );
3205 DBG_ERROR("Falsche Tabellennummer");
3206 return 0;
3210 ULONG ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
3212 if ( ValidTab(nTab) && pTab[nTab] )
3213 return pTab[nTab]->GetColOffset( nCol );
3214 DBG_ERROR("Falsche Tabellennummer");
3215 return 0;
3219 ULONG ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
3221 if ( ValidTab(nTab) && pTab[nTab] )
3222 return pTab[nTab]->GetRowOffset( nRow );
3223 DBG_ERROR("Falsche Tabellennummer");
3224 return 0;
3228 USHORT ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3229 double nPPTX, double nPPTY,
3230 const Fraction& rZoomX, const Fraction& rZoomY,
3231 BOOL bFormula, const ScMarkData* pMarkData,
3232 BOOL bSimpleTextImport )
3234 if ( ValidTab(nTab) && pTab[nTab] )
3235 return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3236 rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
3237 DBG_ERROR("Falsche Tabellennummer");
3238 return 0;
3242 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3243 OutputDevice* pDev,
3244 double nPPTX, double nPPTY,
3245 const Fraction& rZoomX, const Fraction& rZoomY,
3246 BOOL bWidth, BOOL bTotalSize )
3248 if ( ValidTab(nTab) && pTab[nTab] )
3249 return pTab[nTab]->GetNeededSize
3250 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3251 DBG_ERROR("Falsche Tabellennummer");
3252 return 0;
3256 BOOL ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nExtra,
3257 OutputDevice* pDev,
3258 double nPPTX, double nPPTY,
3259 const Fraction& rZoomX, const Fraction& rZoomY,
3260 BOOL bShrink )
3262 //! MarkToMulti();
3263 if ( ValidTab(nTab) && pTab[nTab] )
3264 return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3265 pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3266 DBG_ERROR("Falsche Tabellennummer");
3267 return FALSE;
3271 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3272 const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3274 // one progress across all (selected) sheets
3276 ULONG nCellCount = 0;
3277 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3278 if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3279 nCellCount += pTab[nTab]->GetWeightedCount();
3281 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3283 ULONG nProgressStart = 0;
3284 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3285 if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3287 pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
3288 pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE, &aProgress, nProgressStart );
3289 nProgressStart += pTab[nTab]->GetWeightedCount();
3295 // Spalten-/Zeilen-Flags ----------------------------------------------
3298 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, BOOL bShow)
3300 if ( ValidTab(nTab) && pTab[nTab] )
3301 pTab[nTab]->ShowCol( nCol, bShow );
3305 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, BOOL bShow)
3307 if ( ValidTab(nTab) && pTab[nTab] )
3308 pTab[nTab]->ShowRow( nRow, bShow );
3312 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, BOOL bShow)
3314 if ( ValidTab(nTab) && pTab[nTab] )
3315 pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
3319 void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, BYTE nNewFlags )
3321 if ( ValidTab(nTab) && pTab[nTab] )
3322 pTab[nTab]->SetColFlags( nCol, nNewFlags );
3326 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, BYTE nNewFlags )
3328 if ( ValidTab(nTab) && pTab[nTab] )
3329 pTab[nTab]->SetRowFlags( nRow, nNewFlags );
3333 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BYTE nNewFlags )
3335 if ( ValidTab(nTab) && pTab[nTab] )
3336 pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
3340 BYTE ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
3342 if ( ValidTab(nTab) && pTab[nTab] )
3343 return pTab[nTab]->GetColFlags( nCol );
3344 DBG_ERROR("Falsche Tabellennummer");
3345 return 0;
3348 BYTE ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
3350 if ( ValidTab(nTab) && pTab[nTab] )
3351 return pTab[nTab]->GetRowFlags( nRow );
3352 DBG_ERROR("Falsche Tabellennummer");
3353 return 0;
3356 ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArrayModifiable(
3357 SCTAB nTab )
3359 return const_cast< ScBitMaskCompressedArray< SCROW, BYTE> & >(
3360 GetRowFlagsArray( nTab));
3363 const ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArray(
3364 SCTAB nTab ) const
3366 const ScBitMaskCompressedArray< SCROW, BYTE> * pFlags;
3367 if ( ValidTab(nTab) && pTab[nTab] )
3368 pFlags = pTab[nTab]->GetRowFlagsArray();
3369 else
3371 DBG_ERROR("wrong sheet number");
3372 pFlags = 0;
3374 if (!pFlags)
3376 DBG_ERROR("no row flags at sheet");
3377 static ScBitMaskCompressedArray< SCROW, BYTE> aDummy( MAXROW, 0);
3378 pFlags = &aDummy;
3380 return *pFlags;
3384 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
3386 if ( ValidTab(nTab) && pTab[nTab] )
3387 return pTab[nTab]->GetLastFlaggedRow();
3388 return 0;
3392 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
3394 if ( ValidTab(nTab) && pTab[nTab] )
3395 return pTab[nTab]->GetLastChangedCol();
3396 return 0;
3399 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
3401 if ( ValidTab(nTab) && pTab[nTab] )
3402 return pTab[nTab]->GetLastChangedRow();
3403 return 0;
3407 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
3409 if ( ValidTab(nTab) && pTab[nTab] )
3411 BYTE nStartFlags = pTab[nTab]->GetColFlags(nStart);
3412 USHORT nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
3413 for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
3415 if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
3416 (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
3417 ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
3418 return nCol;
3420 return MAXCOL+1;
3422 return 0;
3425 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
3427 if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->GetRowHeightArray() )
3429 BYTE nStartFlags = pTab[nTab]->GetRowFlags(nStart);
3430 USHORT nStartHeight = pTab[nTab]->GetOriginalHeight(nStart);
3431 for (SCROW nRow = nStart + 1; nRow <= MAXROW; nRow++)
3433 size_t nIndex; // ignored
3434 SCROW nFlagsEndRow;
3435 SCROW nHeightEndRow;
3436 BYTE nFlags = pTab[nTab]->GetRowFlagsArray()->GetValue( nRow, nIndex, nFlagsEndRow );
3437 USHORT nHeight = pTab[nTab]->GetRowHeightArray()->GetValue( nRow, nIndex, nHeightEndRow );
3438 if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
3439 ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
3440 (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
3441 (!bCareManualSize && ((nStartHeight != nHeight))))
3442 return nRow;
3444 nRow = std::min( nFlagsEndRow, nHeightEndRow );
3446 return MAXROW+1;
3448 return 0;
3451 BOOL ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
3453 BOOL bRet(FALSE);
3454 nDefault = 0;
3455 ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
3456 SCCOL nColumn;
3457 SCROW nStartRow;
3458 SCROW nEndRow;
3459 const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3460 if (nEndRow < nLastRow)
3462 ScDefaultAttrSet aSet;
3463 ScDefaultAttrSet::iterator aItr = aSet.end();
3464 while (pAttr)
3466 ScDefaultAttr aAttr(pAttr);
3467 aItr = aSet.find(aAttr);
3468 if (aItr == aSet.end())
3470 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3471 aAttr.nFirst = nStartRow;
3472 aSet.insert(aAttr);
3474 else
3476 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3477 aAttr.nFirst = aItr->nFirst;
3478 aSet.erase(aItr);
3479 aSet.insert(aAttr);
3481 pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3483 ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
3484 aItr = aDefaultItr;
3485 aItr++;
3486 while (aItr != aSet.end())
3488 // for entries with equal count, use the one with the lowest start row,
3489 // don't use the random order of pointer comparisons
3490 if ( aItr->nCount > aDefaultItr->nCount ||
3491 ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
3492 aDefaultItr = aItr;
3493 aItr++;
3495 nDefault = aDefaultItr->nFirst;
3496 bRet = TRUE;
3498 else
3499 bRet = TRUE;
3500 return bRet;
3503 BOOL ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
3505 BOOL bRet(FALSE);
3506 return bRet;
3509 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3511 if ( ValidTab(nTab) && pTab[nTab] )
3512 pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
3516 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3518 if ( ValidTab(nTab) && pTab[nTab] )
3519 pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
3523 // Attribute ----------------------------------------------------------
3526 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, USHORT nWhich ) const
3528 if ( ValidTab(nTab) && pTab[nTab] )
3530 const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
3531 if (pTemp)
3532 return pTemp;
3533 else
3535 DBG_ERROR( "Attribut Null" );
3538 return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
3542 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3544 if ( ValidTab(nTab) && pTab[nTab] )
3545 return pTab[nTab]->GetPattern( nCol, nRow );
3546 return NULL;
3550 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3552 if ( ValidTab(nTab) && pTab[nTab] )
3553 return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
3554 return NULL;
3558 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
3560 if ( ValidTab(nTab) && pTab[nTab] )
3561 pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
3565 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
3567 if ( ValidTab(nTab) && pTab[nTab] )
3568 pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
3572 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
3573 SCCOL nEndCol, SCROW nEndRow,
3574 const ScMarkData& rMark,
3575 const ScPatternAttr& rAttr,
3576 ScEditDataArray* pDataArray )
3578 for (SCTAB i=0; i <= MAXTAB; i++)
3579 if (pTab[i])
3580 if (rMark.GetTableSelect(i))
3581 pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray );
3585 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3586 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
3588 if (VALIDTAB(nTab))
3589 if (pTab[nTab])
3590 pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3593 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
3594 const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
3596 for (SCTAB i=0; i <= MAXTAB; i++)
3597 if (pTab[i])
3598 if (rMark.GetTableSelect(i))
3599 pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
3603 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
3605 if (VALIDTAB(nTab))
3606 if (pTab[nTab])
3607 pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
3611 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
3612 SCCOL nEndCol, SCROW nEndRow,
3613 const ScMarkData& rMark,
3614 const ScStyleSheet& rStyle)
3616 for (SCTAB i=0; i <= MAXTAB; i++)
3617 if (pTab[i])
3618 if (rMark.GetTableSelect(i))
3619 pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3623 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
3624 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
3626 if (VALIDTAB(nTab))
3627 if (pTab[nTab])
3628 pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3632 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
3634 // ApplySelectionStyle needs multi mark
3635 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
3637 ScRange aRange;
3638 rMark.GetMarkArea( aRange );
3639 ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
3640 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
3642 else
3644 for (SCTAB i=0; i<=MAXTAB; i++)
3645 if ( pTab[i] && rMark.GetTableSelect(i) )
3646 pTab[i]->ApplySelectionStyle( rStyle, rMark );
3651 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
3652 const SvxBorderLine* pLine, BOOL bColorOnly )
3654 if ( bColorOnly && !pLine )
3655 return;
3657 for (SCTAB i=0; i<=MAXTAB; i++)
3658 if (pTab[i])
3659 if (rMark.GetTableSelect(i))
3660 pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
3664 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3666 if ( VALIDTAB(nTab) && pTab[nTab] )
3667 return pTab[nTab]->GetStyle(nCol, nRow);
3668 else
3669 return NULL;
3673 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
3675 BOOL bEqual = TRUE;
3676 BOOL bFound;
3678 const ScStyleSheet* pStyle = NULL;
3679 const ScStyleSheet* pNewStyle;
3681 if ( rMark.IsMultiMarked() )
3682 for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
3683 if (pTab[i] && rMark.GetTableSelect(i))
3685 pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
3686 if (bFound)
3688 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
3689 bEqual = FALSE; // unterschiedliche
3690 pStyle = pNewStyle;
3693 if ( rMark.IsMarked() )
3695 ScRange aRange;
3696 rMark.GetMarkArea( aRange );
3697 for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
3698 if (pTab[i] && rMark.GetTableSelect(i))
3700 pNewStyle = pTab[i]->GetAreaStyle( bFound,
3701 aRange.aStart.Col(), aRange.aStart.Row(),
3702 aRange.aEnd.Col(), aRange.aEnd.Row() );
3703 if (bFound)
3705 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
3706 bEqual = FALSE; // unterschiedliche
3707 pStyle = pNewStyle;
3712 return bEqual ? pStyle : NULL;
3716 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, BOOL bRemoved,
3717 OutputDevice* pDev,
3718 double nPPTX, double nPPTY,
3719 const Fraction& rZoomX, const Fraction& rZoomY )
3721 for (SCTAB i=0; i <= MAXTAB; i++)
3722 if (pTab[i])
3723 pTab[i]->StyleSheetChanged
3724 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
3726 if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
3728 // update attributes for all note objects
3729 ScDetectiveFunc::UpdateAllComments( *this );
3734 BOOL ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
3736 if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
3738 if ( bGatherAllStyles )
3740 SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
3741 SFX_STYLE_FAMILY_PARA );
3742 for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
3743 pStyle = aIter.Next() )
3745 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
3746 if ( pScStyle )
3747 pScStyle->SetUsage( ScStyleSheet::NOTUSED );
3751 BOOL bIsUsed = FALSE;
3753 for ( SCTAB i=0; i<=MAXTAB; i++ )
3755 if ( pTab[i] )
3757 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
3759 if ( !bGatherAllStyles )
3760 return TRUE;
3761 bIsUsed = TRUE;
3766 if ( bGatherAllStyles )
3767 bStyleSheetUsageInvalid = FALSE;
3769 return bIsUsed;
3772 return rStyle.GetUsage() == ScStyleSheet::USED;
3776 BOOL ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
3777 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
3779 if (VALIDTAB(nTab))
3780 if (pTab[nTab])
3781 return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
3783 DBG_ERROR("ApplyFlags: falsche Tabelle");
3784 return FALSE;
3788 BOOL ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
3789 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
3791 if (VALIDTAB(nTab))
3792 if (pTab[nTab])
3793 return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
3795 DBG_ERROR("RemoveFlags: falsche Tabelle");
3796 return FALSE;
3800 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
3801 BOOL bPutToPool )
3803 if (VALIDTAB(nTab))
3804 if (pTab[nTab])
3805 pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
3809 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
3810 BOOL bPutToPool )
3812 SCTAB nTab = rPos.Tab();
3813 if (pTab[nTab])
3814 pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
3818 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
3820 ScMergePatternState aState;
3822 if ( rMark.IsMultiMarked() ) // multi selection
3824 for (SCTAB i=0; i<=MAXTAB; i++)
3825 if (pTab[i] && rMark.GetTableSelect(i))
3826 pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
3828 if ( rMark.IsMarked() ) // simle selection
3830 ScRange aRange;
3831 rMark.GetMarkArea(aRange);
3832 for (SCTAB i=0; i<=MAXTAB; i++)
3833 if (pTab[i] && rMark.GetTableSelect(i))
3834 pTab[i]->MergePatternArea( aState,
3835 aRange.aStart.Col(), aRange.aStart.Row(),
3836 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
3839 DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
3840 if (aState.pItemSet)
3841 return new ScPatternAttr( aState.pItemSet );
3842 else
3843 return new ScPatternAttr( GetPool() ); // empty
3847 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
3849 delete pSelectionAttr;
3850 pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
3851 return pSelectionAttr;
3855 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
3856 SvxBoxItem& rLineOuter,
3857 SvxBoxInfoItem& rLineInner )
3859 rLineOuter.SetLine(NULL, BOX_LINE_TOP);
3860 rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
3861 rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
3862 rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
3863 rLineOuter.SetDistance(0);
3865 rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
3866 rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
3867 rLineInner.SetTable(TRUE);
3868 rLineInner.SetDist(TRUE);
3869 rLineInner.SetMinDist(FALSE);
3871 ScLineFlags aFlags;
3873 if (rMark.IsMarked())
3875 ScRange aRange;
3876 rMark.GetMarkArea(aRange);
3877 rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
3878 rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
3879 for (SCTAB i=0; i<=MAXTAB; i++)
3880 if (pTab[i] && rMark.GetTableSelect(i))
3881 pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
3882 aRange.aStart.Col(), aRange.aStart.Row(),
3883 aRange.aEnd.Col(), aRange.aEnd.Row() );
3886 // Don't care Status auswerten
3888 rLineInner.SetValid( VALID_LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
3889 rLineInner.SetValid( VALID_RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
3890 rLineInner.SetValid( VALID_TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
3891 rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
3892 rLineInner.SetValid( VALID_HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
3893 rLineInner.SetValid( VALID_VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
3897 BOOL ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
3898 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, USHORT nMask )
3900 if ( nMask & HASATTR_ROTATE )
3902 // Attribut im Dokument ueberhaupt verwendet?
3903 // (wie in fillinfo)
3905 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
3907 BOOL bAnyItem = FALSE;
3908 USHORT nRotCount = pPool->GetItemCount( ATTR_ROTATE_VALUE );
3909 for (USHORT nItem=0; nItem<nRotCount; nItem++)
3911 const SfxPoolItem* pItem = pPool->GetItem( ATTR_ROTATE_VALUE, nItem );
3912 if ( pItem )
3914 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
3915 // (see ScPatternAttr::GetCellOrientation)
3916 INT32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
3917 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
3919 bAnyItem = TRUE;
3920 break;
3924 if (!bAnyItem)
3925 nMask &= ~HASATTR_ROTATE;
3928 if ( nMask & HASATTR_RTL )
3930 // first check if right-to left is in the pool at all
3931 // (the same item is used in cell and page format)
3933 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
3935 BOOL bHasRtl = FALSE;
3936 USHORT nDirCount = pPool->GetItemCount( ATTR_WRITINGDIR );
3937 for (USHORT nItem=0; nItem<nDirCount; nItem++)
3939 const SfxPoolItem* pItem = pPool->GetItem( ATTR_WRITINGDIR, nItem );
3940 if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
3942 bHasRtl = TRUE;
3943 break;
3946 if (!bHasRtl)
3947 nMask &= ~HASATTR_RTL;
3950 if (!nMask)
3951 return FALSE;
3953 BOOL bFound = FALSE;
3954 for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
3955 if (pTab[i])
3957 if ( nMask & HASATTR_RTL )
3959 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
3960 bFound = TRUE;
3962 if ( nMask & HASATTR_RIGHTORCENTER )
3964 // On a RTL sheet, don't start to look for the default left value
3965 // (which is then logically right), instead always assume TRUE.
3966 // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
3968 if ( IsLayoutRTL(i) )
3969 bFound = TRUE;
3972 if ( !bFound )
3973 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
3976 return bFound;
3979 BOOL ScDocument::HasAttrib( const ScRange& rRange, USHORT nMask )
3981 return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
3982 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
3983 nMask );
3986 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
3987 SCCOL nX1, SCCOL nX2 ) const
3989 if ( ValidTab(nTab) && pTab[nTab] )
3990 pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
3991 else
3993 DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
3997 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
3998 const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
3999 const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4001 //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
4003 const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4004 DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4006 const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
4007 const SvxBorderLine* pTopLine = pThisAttr->GetTop();
4008 const SvxBorderLine* pRightLine = pThisAttr->GetRight();
4009 const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4011 if ( nCol > 0 )
4013 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4014 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4015 if ( ScHasPriority( pOther, pLeftLine ) )
4016 pLeftLine = pOther;
4018 if ( nRow > 0 )
4020 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4021 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4022 if ( ScHasPriority( pOther, pTopLine ) )
4023 pTopLine = pOther;
4025 if ( nCol < MAXCOL )
4027 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4028 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4029 if ( ScHasPriority( pOther, pRightLine ) )
4030 pRightLine = pOther;
4032 if ( nRow < MAXROW )
4034 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4035 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4036 if ( ScHasPriority( pOther, pBottomLine ) )
4037 pBottomLine = pOther;
4040 if (ppLeft)
4041 *ppLeft = pLeftLine;
4042 if (ppTop)
4043 *ppTop = pTopLine;
4044 if (ppRight)
4045 *ppRight = pRightLine;
4046 if (ppBottom)
4047 *ppBottom = pBottomLine;
4050 BOOL ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4051 SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4053 if (VALIDTAB(nTab))
4054 if (pTab[nTab])
4055 return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4057 DBG_ERROR("Falsche Tabellennummer");
4058 return FALSE;
4062 void ScDocument::LockTable(SCTAB nTab)
4064 if ( ValidTab(nTab) && pTab[nTab] )
4065 pTab[nTab]->LockTable();
4066 else
4068 DBG_ERROR("Falsche Tabellennummer");
4073 void ScDocument::UnlockTable(SCTAB nTab)
4075 if ( ValidTab(nTab) && pTab[nTab] )
4076 pTab[nTab]->UnlockTable();
4077 else
4079 DBG_ERROR("Falsche Tabellennummer");
4084 BOOL ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4085 SCCOL nEndCol, SCROW nEndRow,
4086 BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4088 // import into read-only document is possible
4089 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4091 if ( pOnlyNotBecauseOfMatrix )
4092 *pOnlyNotBecauseOfMatrix = FALSE;
4093 return FALSE;
4096 if (VALIDTAB(nTab))
4097 if (pTab[nTab])
4098 return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4099 nEndRow, pOnlyNotBecauseOfMatrix );
4101 DBG_ERROR("Falsche Tabellennummer");
4102 if ( pOnlyNotBecauseOfMatrix )
4103 *pOnlyNotBecauseOfMatrix = FALSE;
4104 return FALSE;
4108 BOOL ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4109 BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4111 // import into read-only document is possible
4112 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4114 if ( pOnlyNotBecauseOfMatrix )
4115 *pOnlyNotBecauseOfMatrix = FALSE;
4116 return FALSE;
4119 ScRange aRange;
4120 rMark.GetMarkArea(aRange);
4122 BOOL bOk = TRUE;
4123 BOOL bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4124 for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4126 if ( pTab[i] && rMark.GetTableSelect(i) )
4128 if (rMark.IsMarked())
4130 if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4131 aRange.aStart.Row(), aRange.aEnd.Col(),
4132 aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4134 bOk = FALSE;
4135 if ( pOnlyNotBecauseOfMatrix )
4136 bMatrix = *pOnlyNotBecauseOfMatrix;
4139 if (rMark.IsMultiMarked())
4141 if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4143 bOk = FALSE;
4144 if ( pOnlyNotBecauseOfMatrix )
4145 bMatrix = *pOnlyNotBecauseOfMatrix;
4151 if ( pOnlyNotBecauseOfMatrix )
4152 *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4154 return bOk;
4158 BOOL ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4159 SCCOL nEndCol, SCROW nEndRow,
4160 const ScMarkData& rMark ) const
4162 BOOL bOk = TRUE;
4163 for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4164 if (pTab[i])
4165 if (rMark.GetTableSelect(i))
4166 if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4167 bOk = FALSE;
4169 return !bOk;
4173 BOOL ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4175 // if rCell is part of a matrix formula, return its complete range
4177 BOOL bRet = FALSE;
4178 ScBaseCell* pCell = GetCell( rCellPos );
4179 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4181 ScAddress aOrigin = rCellPos;
4182 if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4184 if ( aOrigin != rCellPos )
4185 pCell = GetCell( aOrigin );
4186 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4188 SCCOL nSizeX;
4189 SCROW nSizeY;
4190 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4191 if ( !(nSizeX > 0 && nSizeY > 0) )
4193 // GetMatrixEdge computes also dimensions of the matrix
4194 // if not already done (may occur if document is loaded
4195 // from old file format).
4196 // Needs an "invalid" initialized address.
4197 aOrigin.SetInvalid();
4198 ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4199 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4201 if ( nSizeX > 0 && nSizeY > 0 )
4203 ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4204 aOrigin.Row() + nSizeY - 1,
4205 aOrigin.Tab() );
4207 rMatrix.aStart = aOrigin;
4208 rMatrix.aEnd = aEnd;
4209 bRet = TRUE;
4214 return bRet;
4218 BOOL ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4219 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4221 BOOL bFound = FALSE;
4222 if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4224 if (pTab[nTab])
4226 SCCOL nCol;
4227 SCCOL nOldCol = rStartCol;
4228 SCROW nOldRow = rStartRow;
4229 for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4230 while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4231 IsVerOverlapped())
4232 --rStartRow;
4234 //! weiterreichen ?
4236 ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4237 SCSIZE nIndex;
4238 pAttrArray->Search( nOldRow, nIndex );
4239 SCROW nAttrPos = nOldRow;
4240 while (nAttrPos<=nEndRow)
4242 DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4244 if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4245 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4247 SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4248 for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4250 SCCOL nTempCol = nOldCol;
4252 --nTempCol;
4253 while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4254 ->IsHorOverlapped());
4255 if (nTempCol < rStartCol)
4256 rStartCol = nTempCol;
4259 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4260 ++nIndex;
4264 else
4266 DBG_ERROR("ExtendOverlapped: falscher Bereich");
4269 return bFound;
4273 BOOL ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4274 SCCOL& rEndCol, SCROW& rEndRow,
4275 const ScMarkData& rMark, BOOL bRefresh, BOOL bAttrs )
4277 // use all selected sheets from rMark
4279 BOOL bFound = FALSE;
4280 SCCOL nOldEndCol = rEndCol;
4281 SCROW nOldEndRow = rEndRow;
4283 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4284 if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4286 SCCOL nThisEndCol = nOldEndCol;
4287 SCROW nThisEndRow = nOldEndRow;
4288 if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4289 bFound = TRUE;
4290 if ( nThisEndCol > rEndCol )
4291 rEndCol = nThisEndCol;
4292 if ( nThisEndRow > rEndRow )
4293 rEndRow = nThisEndRow;
4296 return bFound;
4300 BOOL ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4301 SCCOL& rEndCol, SCROW& rEndRow,
4302 SCTAB nTab, BOOL bRefresh, BOOL bAttrs )
4304 BOOL bFound = FALSE;
4305 if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4307 if (pTab[nTab])
4308 bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4310 if (bRefresh)
4311 RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4313 else
4315 DBG_ERROR("ExtendMerge: falscher Bereich");
4318 return bFound;
4322 BOOL ScDocument::ExtendMerge( ScRange& rRange, BOOL bRefresh, BOOL bAttrs )
4324 BOOL bFound = FALSE;
4325 SCTAB nStartTab = rRange.aStart.Tab();
4326 SCTAB nEndTab = rRange.aEnd.Tab();
4327 SCCOL nEndCol = rRange.aEnd.Col();
4328 SCROW nEndRow = rRange.aEnd.Row();
4330 PutInOrder( nStartTab, nEndTab );
4331 for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4333 SCCOL nExtendCol = rRange.aEnd.Col();
4334 SCROW nExtendRow = rRange.aEnd.Row();
4335 if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4336 nExtendCol, nExtendRow,
4337 nTab, bRefresh, bAttrs ) )
4339 bFound = TRUE;
4340 if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4341 if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4345 rRange.aEnd.SetCol(nEndCol);
4346 rRange.aEnd.SetRow(nEndRow);
4348 return bFound;
4351 BOOL ScDocument::ExtendTotalMerge( ScRange& rRange )
4353 // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4354 // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4356 BOOL bRet = FALSE;
4357 ScRange aExt = rRange;
4358 if (ExtendMerge(aExt))
4360 if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4362 ScRange aTest = aExt;
4363 aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4364 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4365 aExt.aEnd.SetRow(rRange.aEnd.Row());
4367 if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4369 ScRange aTest = aExt;
4370 aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4371 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4372 aExt.aEnd.SetCol(rRange.aEnd.Col());
4375 bRet = ( aExt.aEnd != rRange.aEnd );
4376 rRange = aExt;
4378 return bRet;
4381 BOOL ScDocument::ExtendOverlapped( ScRange& rRange )
4383 BOOL bFound = FALSE;
4384 SCTAB nStartTab = rRange.aStart.Tab();
4385 SCTAB nEndTab = rRange.aEnd.Tab();
4386 SCCOL nStartCol = rRange.aStart.Col();
4387 SCROW nStartRow = rRange.aStart.Row();
4389 PutInOrder( nStartTab, nEndTab );
4390 for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4392 SCCOL nExtendCol = rRange.aStart.Col();
4393 SCROW nExtendRow = rRange.aStart.Row();
4394 ExtendOverlapped( nExtendCol, nExtendRow,
4395 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4396 if (nExtendCol < nStartCol)
4398 nStartCol = nExtendCol;
4399 bFound = TRUE;
4401 if (nExtendRow < nStartRow)
4403 nStartRow = nExtendRow;
4404 bFound = TRUE;
4408 rRange.aStart.SetCol(nStartCol);
4409 rRange.aStart.SetRow(nStartRow);
4411 return bFound;
4414 BOOL ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4415 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4417 USHORT nCount = pDBCollection->GetCount();
4418 USHORT i;
4419 ScDBData* pData;
4420 SCTAB nDBTab;
4421 SCCOL nDBStartCol;
4422 SCROW nDBStartRow;
4423 SCCOL nDBEndCol;
4424 SCROW nDBEndRow;
4426 // Autofilter loeschen
4428 BOOL bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4430 // Autofilter setzen
4432 for (i=0; i<nCount; i++)
4434 pData = (*pDBCollection)[i];
4435 if (pData->HasAutoFilter())
4437 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4438 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4439 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4441 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4442 nDBTab, SC_MF_AUTO ))
4443 bChange = TRUE;
4447 return bChange;
4450 void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
4452 while (IsHorOverlapped(rCol, rRow, nTab))
4453 --rCol;
4454 while (IsVerOverlapped(rCol, rRow, nTab))
4455 --rRow;
4458 BOOL ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4460 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4461 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4462 if (pAttr)
4463 return pAttr->IsHorOverlapped();
4464 else
4466 DBG_ERROR("Overlapped: Attr==0");
4467 return FALSE;
4472 BOOL ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4474 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4475 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4476 if (pAttr)
4477 return pAttr->IsVerOverlapped();
4478 else
4480 DBG_ERROR("Overlapped: Attr==0");
4481 return FALSE;
4486 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4487 const SvxBoxItem* pLineOuter,
4488 const SvxBoxInfoItem* pLineInner )
4490 ScRangeList aRangeList;
4491 rMark.FillRangeListWithMarks( &aRangeList, FALSE );
4492 ULONG nRangeCount = aRangeList.Count();
4493 for (SCTAB i=0; i<=MAXTAB; i++)
4495 if (pTab[i] && rMark.GetTableSelect(i))
4497 for (ULONG j=0; j<nRangeCount; j++)
4499 ScRange aRange = *aRangeList.GetObject(j);
4500 pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4501 aRange.aStart.Col(), aRange.aStart.Row(),
4502 aRange.aEnd.Col(), aRange.aEnd.Row() );
4509 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4510 const SvxBoxItem* pLineOuter,
4511 const SvxBoxInfoItem* pLineInner )
4513 SCTAB nStartTab = rRange.aStart.Tab();
4514 SCTAB nEndTab = rRange.aStart.Tab();
4515 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4516 if (pTab[nTab])
4517 pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4518 rRange.aStart.Col(), rRange.aStart.Row(),
4519 rRange.aEnd.Col(), rRange.aEnd.Row() );
4523 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark, ScEditDataArray* pDataArray )
4525 const SfxItemSet* pSet = &rAttr.GetItemSet();
4526 BOOL bSet = FALSE;
4527 USHORT i;
4528 for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4529 if (pSet->GetItemState(i) == SFX_ITEM_SET)
4530 bSet = TRUE;
4532 if (bSet)
4534 // ApplySelectionCache needs multi mark
4535 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4537 ScRange aRange;
4538 rMark.GetMarkArea( aRange );
4539 ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4540 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray );
4542 else
4544 SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4545 for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4546 if (pTab[nTab])
4547 if (rMark.GetTableSelect(nTab))
4548 pTab[nTab]->ApplySelectionCache( &aCache, rMark, pDataArray );
4554 void ScDocument::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
4556 for (SCTAB i=0; i<=MAXTAB; i++)
4557 if (pTab[i] && rMark.GetTableSelect(i))
4558 pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4562 void ScDocument::ClearSelectionItems( const USHORT* pWhich, const ScMarkData& rMark )
4564 for (SCTAB i=0; i<=MAXTAB; i++)
4565 if (pTab[i] && rMark.GetTableSelect(i))
4566 pTab[i]->ClearSelectionItems( pWhich, rMark );
4570 void ScDocument::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
4572 for (SCTAB i=0; i<=MAXTAB; i++)
4573 if (pTab[i] && rMark.GetTableSelect(i))
4574 pTab[i]->DeleteSelection( nDelFlag, rMark );
4578 void ScDocument::DeleteSelectionTab( SCTAB nTab, USHORT nDelFlag, const ScMarkData& rMark )
4580 if (ValidTab(nTab) && pTab[nTab])
4581 pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4582 else
4584 DBG_ERROR("Falsche Tabelle");
4589 ScPatternAttr* ScDocument::GetDefPattern() const
4591 return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4595 ScDocumentPool* ScDocument::GetPool()
4597 return xPoolHelper->GetDocPool();
4602 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
4604 return xPoolHelper->GetStylePool();
4608 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
4609 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
4611 PutInOrder(nStartCol, nEndCol);
4612 PutInOrder(nStartRow, nEndRow);
4613 PutInOrder(nStartTab, nEndTab);
4614 if (VALIDTAB(nStartTab))
4616 if (pTab[nStartTab])
4617 return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
4618 else
4619 return 0;
4621 else
4622 return 0;
4626 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
4628 if (ValidTab(nTab) && pTab[nTab])
4629 pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
4633 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
4634 BOOL bMarked, BOOL bUnprotected, const ScMarkData& rMark )
4636 DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
4638 ScMarkData aCopyMark = rMark;
4639 aCopyMark.SetMarking(FALSE);
4640 aCopyMark.MarkToMulti();
4642 if (ValidTab(nTab) && pTab[nTab])
4643 pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
4647 // Datei-Operationen
4651 void ScDocument::UpdStlShtPtrsFrmNms()
4653 ScPatternAttr::pDoc = this;
4655 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4657 USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
4658 ScPatternAttr* pPattern;
4659 for (USHORT i=0; i<nCount; i++)
4661 pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
4662 if (pPattern)
4663 pPattern->UpdateStyleSheet();
4665 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
4669 void ScDocument::StylesToNames()
4671 ScPatternAttr::pDoc = this;
4673 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4675 USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
4676 ScPatternAttr* pPattern;
4677 for (USHORT i=0; i<nCount; i++)
4679 pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
4680 if (pPattern)
4681 pPattern->StyleToName();
4683 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
4687 ULONG ScDocument::GetCellCount() const
4689 ULONG nCellCount = 0L;
4691 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
4692 if ( pTab[nTab] )
4693 nCellCount += pTab[nTab]->GetCellCount();
4695 return nCellCount;
4699 ULONG ScDocument::GetCodeCount() const
4701 ULONG nCodeCount = 0;
4703 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
4704 if ( pTab[nTab] )
4705 nCodeCount += pTab[nTab]->GetCodeCount();
4707 return nCodeCount;
4711 ULONG ScDocument::GetWeightedCount() const
4713 ULONG nCellCount = 0L;
4715 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
4716 if ( pTab[nTab] )
4717 nCellCount += pTab[nTab]->GetWeightedCount();
4719 return nCellCount;
4723 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
4725 if ( ValidTab(nTab) && pTab[nTab] )
4726 pTab[nTab]->PageStyleModified( rNewName );
4730 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
4732 if ( ValidTab(nTab) && pTab[nTab] )
4733 pTab[nTab]->SetPageStyle( rName );
4737 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
4739 if ( ValidTab(nTab) && pTab[nTab] )
4740 return pTab[nTab]->GetPageStyle();
4742 return EMPTY_STRING;
4746 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
4748 if ( ValidTab(nTab) && pTab[nTab] )
4749 pTab[nTab]->SetPageSize( rSize );
4752 Size ScDocument::GetPageSize( SCTAB nTab ) const
4754 if ( ValidTab(nTab) && pTab[nTab] )
4755 return pTab[nTab]->GetPageSize();
4757 DBG_ERROR("falsche Tab");
4758 return Size();
4762 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
4764 if ( ValidTab(nTab) && pTab[nTab] )
4765 pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
4769 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
4771 if ( ValidTab(nTab) && pTab[nTab] )
4772 pTab[nTab]->UpdatePageBreaks( pUserArea );
4775 void ScDocument::RemoveManualBreaks( SCTAB nTab )
4777 if ( ValidTab(nTab) && pTab[nTab] )
4778 pTab[nTab]->RemoveManualBreaks();
4781 BOOL ScDocument::HasManualBreaks( SCTAB nTab ) const
4783 if ( ValidTab(nTab) && pTab[nTab] )
4784 return pTab[nTab]->HasManualBreaks();
4786 DBG_ERROR("falsche Tab");
4787 return FALSE;
4791 void ScDocument::GetDocStat( ScDocStat& rDocStat )
4793 rDocStat.nTableCount = GetTableCount();
4794 rDocStat.aDocName = aDocName;
4795 rDocStat.nCellCount = GetCellCount();
4799 BOOL ScDocument::HasPrintRange()
4801 BOOL bResult = FALSE;
4803 for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
4804 if ( pTab[i] )
4805 bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
4807 return bResult;
4811 BOOL ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
4813 return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
4817 USHORT ScDocument::GetPrintRangeCount( SCTAB nTab )
4819 if (ValidTab(nTab) && pTab[nTab])
4820 return pTab[nTab]->GetPrintRangeCount();
4822 return 0;
4826 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, USHORT nPos )
4828 if (ValidTab(nTab) && pTab[nTab])
4829 return pTab[nTab]->GetPrintRange(nPos);
4831 return NULL;
4835 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
4837 if (ValidTab(nTab) && pTab[nTab])
4838 return pTab[nTab]->GetRepeatColRange();
4840 return NULL;
4844 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
4846 if (ValidTab(nTab) && pTab[nTab])
4847 return pTab[nTab]->GetRepeatRowRange();
4849 return NULL;
4853 void ScDocument::ClearPrintRanges( SCTAB nTab )
4855 if (ValidTab(nTab) && pTab[nTab])
4856 pTab[nTab]->ClearPrintRanges();
4860 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
4862 if (ValidTab(nTab) && pTab[nTab])
4863 pTab[nTab]->AddPrintRange( rNew );
4867 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
4868 //UNUSED2009-05 {
4869 //UNUSED2009-05 if (ValidTab(nTab) && pTab[nTab])
4870 //UNUSED2009-05 pTab[nTab]->SetPrintRange( rNew );
4871 //UNUSED2009-05 }
4874 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
4876 if (ValidTab(nTab) && pTab[nTab])
4877 pTab[nTab]->SetPrintEntireSheet();
4881 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
4883 if (ValidTab(nTab) && pTab[nTab])
4884 pTab[nTab]->SetRepeatColRange( pNew );
4888 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
4890 if (ValidTab(nTab) && pTab[nTab])
4891 pTab[nTab]->SetRepeatRowRange( pNew );
4895 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
4897 SCTAB nCount = GetTableCount();
4898 ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
4899 for (SCTAB i=0; i<nCount; i++)
4900 if (pTab[i])
4901 pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
4902 return pNew;
4906 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
4908 SCTAB nCount = rSaver.GetTabCount();
4909 for (SCTAB i=0; i<nCount; i++)
4910 if (pTab[i])
4911 pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
4915 BOOL ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
4917 // Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
4918 // andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
4919 // und eine Seitennummer angegeben ist (nicht 0)
4921 if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
4923 String aNew = pTab[nTab+1]->GetPageStyle();
4924 if ( aNew != pTab[nTab]->GetPageStyle() )
4926 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
4927 if ( pStyle )
4929 const SfxItemSet& rSet = pStyle->GetItemSet();
4930 USHORT nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
4931 if ( nFirst != 0 )
4932 return TRUE; // Seitennummer in neuer Vorlage angegeben
4937 return FALSE; // sonst nicht
4940 SfxUndoManager* ScDocument::GetUndoManager()
4942 if (!mpUndoManager)
4943 mpUndoManager = new SfxUndoManager;
4944 return mpUndoManager;
4948 void ScDocument::EnableUndo( bool bVal )
4950 GetUndoManager()->EnableUndo(bVal);
4951 mbUndoEnabled = bVal;