xref: /AOO41X/main/sc/source/core/data/table2.cxx (revision e1d5bd03a6ea7ac2b26b792c9e2a94e9f347a43b)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 // INCLUDE ---------------------------------------------------------------
28 
29 #include "scitems.hxx"
30 #include <editeng/boxitem.hxx>
31 #include <tools/urlobj.hxx>
32 #include <svl/poolcach.hxx>
33 #include <unotools/charclass.hxx>
34 #include <math.h>
35 #include <svl/PasswordHelper.hxx>
36 #include <unotools/transliterationwrapper.hxx>
37 
38 #include "patattr.hxx"
39 #include "docpool.hxx"
40 #include "cell.hxx"
41 #include "document.hxx"
42 #include "drwlayer.hxx"
43 #include "olinetab.hxx"
44 #include "rechead.hxx"
45 #include "stlpool.hxx"
46 #include "attarray.hxx"		// Iterator
47 #include "markdata.hxx"
48 #include "progress.hxx"
49 #include "dociter.hxx"
50 #include "conditio.hxx"
51 #include "chartlis.hxx"
52 #include "fillinfo.hxx"
53 #include "bcaslot.hxx"
54 #include "postit.hxx"
55 #include "sheetevents.hxx"
56 #include "globstr.hrc"
57 #include "segmenttree.hxx"
58 #include "dbcolect.hxx"
59 
60 #include <math.h>
61 
62 // STATIC DATA -----------------------------------------------------------
63 
64 
65 sal_Bool ScTable::SetOutlineTable( const ScOutlineTable* pNewOutline )
66 {
67 	sal_uInt16 nOldSizeX = 0;
68 	sal_uInt16 nOldSizeY = 0;
69 	sal_uInt16 nNewSizeX = 0;
70 	sal_uInt16 nNewSizeY = 0;
71 
72 	if (pOutlineTable)
73 	{
74 		nOldSizeX = pOutlineTable->GetColArray()->GetDepth();
75 		nOldSizeY = pOutlineTable->GetRowArray()->GetDepth();
76 		delete pOutlineTable;
77 	}
78 
79 	if (pNewOutline)
80 	{
81 		pOutlineTable = new ScOutlineTable( *pNewOutline );
82 		nNewSizeX = pOutlineTable->GetColArray()->GetDepth();
83 		nNewSizeY = pOutlineTable->GetRowArray()->GetDepth();
84 	}
85 	else
86 		pOutlineTable = NULL;
87 
88 	return ( nNewSizeX != nOldSizeX || nNewSizeY != nOldSizeY );		// Groesse geaendert ?
89 }
90 
91 
92 void ScTable::StartOutlineTable()
93 {
94 	if (!pOutlineTable)
95 		pOutlineTable = new ScOutlineTable;
96 }
97 
98 
99 void ScTable::SetSheetEvents( const ScSheetEvents* pNew )
100 {
101     delete pSheetEvents;
102     if (pNew)
103         pSheetEvents = new ScSheetEvents(*pNew);
104     else
105         pSheetEvents = NULL;
106 
107     SetCalcNotification( sal_False );       // discard notifications before the events were set
108 
109     if (IsStreamValid())
110         SetStreamValid(sal_False);
111 }
112 
113 
114 void ScTable::SetCalcNotification( sal_Bool bSet )
115 {
116     bCalcNotification = bSet;
117 }
118 
119 
120 sal_Bool ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize )
121 {
122 	sal_Bool bTest = sal_True;
123 
124 	if ( nStartCol==0 && nEndCol==MAXCOL && pOutlineTable )
125 		bTest = pOutlineTable->TestInsertRow(nSize);
126 
127 	for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
128 		bTest = aCol[i].TestInsertRow( nSize );
129 
130 	return bTest;
131 }
132 
133 
134 void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize )
135 {
136 	IncRecalcLevel();
137     InitializeNoteCaptions();
138 	if (nStartCol==0 && nEndCol==MAXCOL)
139 	{
140         if (mpRowHeights && pRowFlags)
141 		{
142             mpRowHeights->insertSegment(nStartRow, nSize, false);
143             sal_uInt8 nNewFlags = pRowFlags->Insert( nStartRow, nSize);
144             // only copy manual size flag, clear all others
145             if (nNewFlags && (nNewFlags != CR_MANUALSIZE))
146                 pRowFlags->SetValue( nStartRow, nStartRow + nSize - 1,
147                         nNewFlags & CR_MANUALSIZE);
148 		}
149 
150 		if (pOutlineTable)
151 			pOutlineTable->InsertRow( nStartRow, nSize );
152 
153         mpFilteredRows->insertSegment(nStartRow, nSize, true);
154         mpHiddenRows->insertSegment(nStartRow, nSize, true);
155 
156         if (!maRowManualBreaks.empty())
157         {
158             std::set<SCROW>::reverse_iterator rit = maRowManualBreaks.rbegin();
159             while (rit != maRowManualBreaks.rend())
160             {
161                 SCROW nRow = *rit;
162                 if (nRow < nStartRow)
163                     break;  // while
164                 else
165                 {
166                     maRowManualBreaks.erase( (++rit).base());
167                     maRowManualBreaks.insert( static_cast<SCROW>( nRow + nSize));
168                 }
169             }
170         }
171 	}
172 
173 	for (SCCOL j=nStartCol; j<=nEndCol; j++)
174 		aCol[j].InsertRow( nStartRow, nSize );
175 	DecRecalcLevel( false );
176 
177     InvalidatePageBreaks();
178 }
179 
180 
181 void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
182 							sal_Bool* pUndoOutline )
183 {
184 	IncRecalcLevel();
185     InitializeNoteCaptions();
186 	if (nStartCol==0 && nEndCol==MAXCOL)
187 	{
188         if (pRowFlags)
189             pRowFlags->Remove( nStartRow, nSize);
190 
191         if (mpRowHeights)
192             mpRowHeights->removeSegment(nStartRow, nStartRow+nSize);
193 
194 		if (pOutlineTable)
195 			if (pOutlineTable->DeleteRow( nStartRow, nSize ))
196 				if (pUndoOutline)
197 					*pUndoOutline = sal_True;
198 
199         mpFilteredRows->removeSegment(nStartRow, nStartRow+nSize);
200         mpHiddenRows->removeSegment(nStartRow, nStartRow+nSize);
201 
202         if (!maRowManualBreaks.empty())
203         {
204             std::set<SCROW>::iterator it = maRowManualBreaks.upper_bound( static_cast<SCROW>( nStartRow + nSize - 1));
205             maRowManualBreaks.erase( maRowManualBreaks.lower_bound( nStartRow), it);
206             while (it != maRowManualBreaks.end())
207             {
208                 SCROW nRow = *it;
209                 maRowManualBreaks.erase( it++);
210                 maRowManualBreaks.insert( static_cast<SCROW>( nRow - nSize));
211             }
212         }
213 	}
214 
215     {   // scope for bulk broadcast
216         ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
217         for (SCCOL j=nStartCol; j<=nEndCol; j++)
218             aCol[j].DeleteRow( nStartRow, nSize );
219     }
220 	DecRecalcLevel();
221 
222     InvalidatePageBreaks();
223 }
224 
225 
226 sal_Bool ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
227 {
228 	sal_Bool bTest = sal_True;
229 
230 	if ( nStartRow==0 && nEndRow==MAXROW && pOutlineTable )
231 		bTest = pOutlineTable->TestInsertCol(nSize);
232 
233 	if ( nSize > static_cast<SCSIZE>(MAXCOL) )
234 		bTest = sal_False;
235 
236 	for (SCCOL i=MAXCOL; (i+static_cast<SCCOL>(nSize)>MAXCOL) && bTest; i--)
237 		bTest = aCol[i].TestInsertCol(nStartRow, nEndRow);
238 
239 	return bTest;
240 }
241 
242 
243 void ScTable::InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
244 {
245 	IncRecalcLevel();
246     InitializeNoteCaptions();
247 	if (nStartRow==0 && nEndRow==MAXROW)
248 	{
249 		if (pColWidth && pColFlags)
250         {
251             memmove( &pColWidth[nStartCol+nSize], &pColWidth[nStartCol],
252                     (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColWidth[0]) );
253             memmove( &pColFlags[nStartCol+nSize], &pColFlags[nStartCol],
254                     (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColFlags[0]) );
255         }
256 		if (pOutlineTable)
257 			pOutlineTable->InsertCol( nStartCol, nSize );
258 
259         mpHiddenCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize), true);
260         mpFilteredCols->insertSegment(nStartCol, static_cast<SCCOL>(nSize), true);
261 
262         if (!maColManualBreaks.empty())
263         {
264             std::set<SCCOL>::reverse_iterator rit = maColManualBreaks.rbegin();
265             while (rit != maColManualBreaks.rend())
266             {
267                 SCCOL nCol = *rit;
268                 if (nCol < nStartCol)
269                     break;  // while
270                 else
271                 {
272                     maColManualBreaks.erase( (++rit).base());
273                     maColManualBreaks.insert( static_cast<SCCOL>( nCol + nSize));
274                 }
275             }
276         }
277 	}
278 
279 
280 	if ((nStartRow == 0) && (nEndRow == MAXROW))
281 	{
282 		for (SCSIZE i=0; i < nSize; i++)
283 			for (SCCOL nCol = MAXCOL; nCol > nStartCol; nCol--)
284 				aCol[nCol].SwapCol(aCol[nCol-1]);
285 	}
286 	else
287 	{
288 		for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol <= MAXCOL; i++)
289 			aCol[MAXCOL - nSize - i].MoveTo(nStartRow, nEndRow, aCol[MAXCOL - i]);
290 	}
291 
292 	if (nStartCol>0)						// copy old attributes
293 	{
294 		sal_uInt16 nWhichArray[2];
295 		nWhichArray[0] = ATTR_MERGE;
296 		nWhichArray[1] = 0;
297 
298 		for (SCSIZE i=0; i<nSize; i++)
299 		{
300 			aCol[nStartCol-1].CopyToColumn( nStartRow, nEndRow, IDF_ATTRIB,
301 												sal_False, aCol[nStartCol+i] );
302 			aCol[nStartCol+i].RemoveFlags( nStartRow, nEndRow,
303 												SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
304 			aCol[nStartCol+i].ClearItems( nStartRow, nEndRow, nWhichArray );
305 		}
306 	}
307 	DecRecalcLevel();
308 
309     InvalidatePageBreaks();
310 }
311 
312 
313 void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize,
314 							sal_Bool* pUndoOutline )
315 {
316 	IncRecalcLevel();
317     InitializeNoteCaptions();
318 	if (nStartRow==0 && nEndRow==MAXROW)
319 	{
320 		if (pColWidth && pColFlags)
321         {
322             memmove( &pColWidth[nStartCol], &pColWidth[nStartCol+nSize],
323                     (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColWidth[0]) );
324             memmove( &pColFlags[nStartCol], &pColFlags[nStartCol+nSize],
325                     (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColFlags[0]) );
326         }
327 		if (pOutlineTable)
328 			if (pOutlineTable->DeleteCol( nStartCol, nSize ))
329 				if (pUndoOutline)
330 					*pUndoOutline = sal_True;
331 
332         SCCOL nRmSize = nStartCol + static_cast<SCCOL>(nSize);
333         mpHiddenCols->removeSegment(nStartCol, nRmSize);
334         mpFilteredCols->removeSegment(nStartCol, nRmSize);
335 
336         if (!maColManualBreaks.empty())
337         {
338             std::set<SCCOL>::iterator it = maColManualBreaks.upper_bound( static_cast<SCCOL>( nStartCol + nSize - 1));
339             maColManualBreaks.erase( maColManualBreaks.lower_bound( nStartCol), it);
340             while (it != maColManualBreaks.end())
341             {
342                 SCCOL nCol = *it;
343                 maColManualBreaks.erase( it++);
344                 maColManualBreaks.insert( static_cast<SCCOL>( nCol - nSize));
345             }
346         }
347 	}
348 
349 
350     {   // scope for bulk broadcast
351         ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
352         for (SCSIZE i = 0; i < nSize; i++)
353             aCol[nStartCol + i].DeleteArea(nStartRow, nEndRow, IDF_ALL);
354     }
355 
356 	if ((nStartRow == 0) && (nEndRow == MAXROW))
357 	{
358 		for (SCSIZE i=0; i < nSize; i++)
359 			for (SCCOL nCol = nStartCol; nCol < MAXCOL; nCol++)
360 				aCol[nCol].SwapCol(aCol[nCol+1]);
361 	}
362 	else
363 	{
364 		for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol <= MAXCOL; i++)
365 			aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]);
366 	}
367 	DecRecalcLevel();
368 
369     InvalidatePageBreaks();
370 }
371 
372 
373 void ScTable::DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nDelFlag)
374 {
375 	if (nCol2 > MAXCOL) nCol2 = MAXCOL;
376 	if (nRow2 > MAXROW) nRow2 = MAXROW;
377 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
378 	{
379 //		IncRecalcLevel();
380 
381         {   // scope for bulk broadcast
382             ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
383             for (SCCOL i = nCol1; i <= nCol2; i++)
384                 aCol[i].DeleteArea(nRow1, nRow2, nDelFlag);
385         }
386 
387 			//
388 			// Zellschutz auf geschuetzter Tabelle nicht setzen
389 			//
390 
391 		if ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
392 		{
393 			ScPatternAttr aPattern(pDocument->GetPool());
394 			aPattern.GetItemSet().Put( ScProtectionAttr( sal_False ) );
395 			ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
396 		}
397 
398 //		DecRecalcLevel();
399 	}
400 }
401 
402 
403 void ScTable::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
404 {
405     {   // scope for bulk broadcast
406         ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
407         for (SCCOL i=0; i<=MAXCOL; i++)
408             aCol[i].DeleteSelection( nDelFlag, rMark );
409     }
410 
411 		//
412 		// Zellschutz auf geschuetzter Tabelle nicht setzen
413 		//
414 
415 	if ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
416 	{
417 		ScDocumentPool* pPool = pDocument->GetPool();
418 		SfxItemSet aSet( *pPool, ATTR_PATTERN_START, ATTR_PATTERN_END );
419 		aSet.Put( ScProtectionAttr( sal_False ) );
420 		SfxItemPoolCache aCache( pPool, &aSet );
421 		ApplySelectionCache( &aCache, rMark );
422 	}
423 }
424 
425 
426 //	pTable = Clipboard
427 void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
428                         ScTable* pTable, sal_Bool bKeepScenarioFlags, sal_Bool bCloneNoteCaptions)
429 {
430 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
431 	{
432 		//	Inhalte kopieren
433 		SCCOL i;
434 
435 		for ( i = nCol1; i <= nCol2; i++)
436             aCol[i].CopyToClip(nRow1, nRow2, pTable->aCol[i], bKeepScenarioFlags, bCloneNoteCaptions);
437 
438 		//	copy widths/heights, and only "hidden", "filtered" and "manual" flags
439 		//	also for all preceding columns/rows, to have valid positions for drawing objects
440 
441 		if (pColWidth && pTable->pColWidth)
442 			for (i=0; i<=nCol2; i++)
443 				pTable->pColWidth[i] = pColWidth[i];
444 
445         pTable->CopyColHidden(*this, 0, nCol2);
446         pTable->CopyColFiltered(*this, 0, nCol2);
447 
448         if (pRowFlags && pTable->pRowFlags && mpRowHeights && pTable->mpRowHeights)
449         {
450             pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2, CR_MANUALSIZE);
451             pTable->CopyRowHeight(*this, 0, nRow2, 0);
452         }
453 
454         pTable->CopyRowHidden(*this, 0, nRow2);
455         pTable->CopyRowFiltered(*this, 0, nRow2);
456 
457 		//	ggf. Formeln durch Werte ersetzen
458 
459 		if ( IsProtected() )
460 			for (i = nCol1; i <= nCol2; i++)
461 				pTable->aCol[i].RemoveProtected(nRow1, nRow2);
462 	}
463 }
464 
465 void ScTable::CopyToClip(const ScRangeList& rRanges, ScTable* pTable,
466                          bool bKeepScenarioFlags, bool bCloneNoteCaptions)
467 {
468     ScRangeList aRanges(rRanges);
469     for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
470     {
471         CopyToClip(p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(),
472                    pTable, bKeepScenarioFlags, bCloneNoteCaptions);
473     }
474 }
475 
476 void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
477 							SCsCOL nDx, SCsROW nDy, sal_uInt16 nInsFlag,
478 							sal_Bool bAsLink, sal_Bool bSkipAttrForEmpty, ScTable* pTable)
479 {
480 	SCCOL i;
481 
482 	if (nCol2 > MAXCOL) nCol2 = MAXCOL;
483 	if (nRow2 > MAXROW) nRow2 = MAXROW;
484 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
485 	{
486 		IncRecalcLevel();
487 		for ( i = nCol1; i <= nCol2; i++)
488 			aCol[i].CopyFromClip(nRow1, nRow2, nDy, nInsFlag, bAsLink, bSkipAttrForEmpty, pTable->aCol[i - nDx]);
489 
490 		if ((nInsFlag & IDF_ATTRIB) != 0)
491 		{
492 			if (nRow1==0 && nRow2==MAXROW && pColWidth && pTable->pColWidth)
493 				for (i=nCol1; i<=nCol2; i++)
494 					pColWidth[i] = pTable->pColWidth[i-nDx];
495 
496             if (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pTable->mpRowHeights &&
497 											 pRowFlags && pTable->pRowFlags)
498             {
499                 CopyRowHeight(*pTable, nRow1, nRow2, -nDy);
500                 // Must copy CR_MANUALSIZE bit too, otherwise pRowHeight doesn't make sense
501 				for (SCROW j=nRow1; j<=nRow2; j++)
502 				{
503 					if ( pTable->pRowFlags->GetValue(j-nDy) & CR_MANUALSIZE )
504 						pRowFlags->OrValue( j, CR_MANUALSIZE);
505 					else
506                         pRowFlags->AndValue( j, sal::static_int_cast<sal_uInt8>(~CR_MANUALSIZE));
507 				}
508             }
509 
510 				//
511 				// Zellschutz auf geschuetzter Tabelle nicht setzen
512 				//
513 
514 			if ( IsProtected() && (nInsFlag & IDF_ATTRIB) )
515 			{
516 				ScPatternAttr aPattern(pDocument->GetPool());
517 				aPattern.GetItemSet().Put( ScProtectionAttr( sal_False ) );
518 				ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
519 			}
520 		}
521 		DecRecalcLevel();
522 	}
523 }
524 
525 
526 void ScTable::MixData( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
527 							sal_uInt16 nFunction, sal_Bool bSkipEmpty, ScTable* pSrcTab )
528 {
529 	for (SCCOL i=nCol1; i<=nCol2; i++)
530 		aCol[i].MixData( nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[i] );
531 }
532 
533 
534 //	Markierung von diesem Dokument
535 void ScTable::MixMarked( const ScMarkData& rMark, sal_uInt16 nFunction,
536 						sal_Bool bSkipEmpty, ScTable* pSrcTab )
537 {
538 	for (SCCOL i=0; i<=MAXCOL; i++)
539 		aCol[i].MixMarked( rMark, nFunction, bSkipEmpty, pSrcTab->aCol[i] );
540 }
541 
542 
543 void ScTable::TransposeClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
544 								ScTable* pTransClip, sal_uInt16 nFlags, sal_Bool bAsLink )
545 {
546 	sal_Bool bWasCut = pDocument->IsCutMode();
547 
548 	ScDocument* pDestDoc = pTransClip->pDocument;
549 
550 	for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
551 	{
552 		SCROW nRow;
553 		ScBaseCell* pCell;
554 
555 		if ( bAsLink && nFlags == IDF_ALL )
556 		{
557 			//	#68989# with IDF_ALL, also create links (formulas) for empty cells
558 
559 			for ( nRow=nRow1; nRow<=nRow2; nRow++ )
560 			{
561 				//	create simple formula, as in ScColumn::CreateRefCell
562 
563 				ScAddress aDestPos( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pTransClip->nTab );
564 				ScSingleRefData aRef;
565 				aRef.nCol = nCol;
566 				aRef.nRow = nRow;
567 				aRef.nTab = nTab;
568 				aRef.InitFlags();							// -> all absolute
569 				aRef.SetFlag3D(sal_True);
570 				aRef.CalcRelFromAbs( aDestPos );
571 				ScTokenArray aArr;
572 				aArr.AddSingleReference( aRef );
573 
574 				ScBaseCell* pNew = new ScFormulaCell( pDestDoc, aDestPos, &aArr );
575 				pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
576 			}
577 		}
578 		else
579 		{
580 			ScColumnIterator aIter( &aCol[nCol], nRow1, nRow2 );
581 			while (aIter.Next( nRow, pCell ))
582 			{
583                 ScAddress aDestPos( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pTransClip->nTab );
584 				ScBaseCell* pNew;
585 				if ( bAsLink )					// Referenz erzeugen ?
586 				{
587 					pNew = aCol[nCol].CreateRefCell( pDestDoc, aDestPos, aIter.GetIndex(), nFlags );
588 				}
589 				else							// kopieren
590 				{
591                     ScAddress aOwnPos( nCol, nRow, nTab );
592 					if (pCell->GetCellType() == CELLTYPE_FORMULA)
593 					{
594                         pNew = pCell->CloneWithNote( aOwnPos, *pDestDoc, aDestPos, SC_CLONECELL_STARTLISTENING );
595 
596 						//	Referenzen drehen
597 						//	bei Cut werden Referenzen spaeter per UpdateTranspose angepasst
598 
599 						if (!bWasCut)
600 							((ScFormulaCell*)pNew)->TransposeReference();
601 					}
602 					else
603                     {
604                         pNew = pCell->CloneWithNote( aOwnPos, *pDestDoc, aDestPos );
605                     }
606 				}
607 				pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
608 			}
609 		}
610 
611 		//	Attribute
612 
613 		SCROW nAttrRow1;
614 		SCROW nAttrRow2;
615 		const ScPatternAttr* pPattern;
616 		ScAttrIterator* pAttrIter = aCol[nCol].CreateAttrIterator( nRow1, nRow2 );
617 		while ( (pPattern = pAttrIter->Next( nAttrRow1, nAttrRow2 )) != 0 )
618 		{
619 			if ( !IsDefaultItem( pPattern ) )
620 			{
621 				const SfxItemSet& rSet = pPattern->GetItemSet();
622 				if ( rSet.GetItemState( ATTR_MERGE, sal_False ) == SFX_ITEM_DEFAULT &&
623 					 rSet.GetItemState( ATTR_MERGE_FLAG, sal_False ) == SFX_ITEM_DEFAULT &&
624 					 rSet.GetItemState( ATTR_BORDER, sal_False ) == SFX_ITEM_DEFAULT )
625 				{
626 					// no borders or merge items involved - use pattern as-is
627 					for (nRow = nAttrRow1; nRow<=nAttrRow2; nRow++)
628 						pTransClip->SetPattern( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), *pPattern, sal_True );
629 				}
630 				else
631 				{
632 					// transpose borders and merge values, remove merge flags (refreshed after pasting)
633 					ScPatternAttr aNewPattern( *pPattern );
634 					SfxItemSet& rNewSet = aNewPattern.GetItemSet();
635 
636 					const SvxBoxItem& rOldBox = (const SvxBoxItem&)rSet.Get(ATTR_BORDER);
637 					if ( rOldBox.GetTop() || rOldBox.GetBottom() || rOldBox.GetLeft() || rOldBox.GetRight() )
638 					{
639 						SvxBoxItem aNew( ATTR_BORDER );
640 						aNew.SetLine( rOldBox.GetLine( BOX_LINE_TOP ), BOX_LINE_LEFT );
641 						aNew.SetLine( rOldBox.GetLine( BOX_LINE_LEFT ), BOX_LINE_TOP );
642 						aNew.SetLine( rOldBox.GetLine( BOX_LINE_BOTTOM ), BOX_LINE_RIGHT );
643 						aNew.SetLine( rOldBox.GetLine( BOX_LINE_RIGHT ), BOX_LINE_BOTTOM );
644 						aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_TOP ), BOX_LINE_LEFT );
645 						aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_LEFT ), BOX_LINE_TOP );
646 						aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_BOTTOM ), BOX_LINE_RIGHT );
647 						aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_RIGHT ), BOX_LINE_BOTTOM );
648 						rNewSet.Put( aNew );
649 					}
650 
651 					const ScMergeAttr& rOldMerge = (const ScMergeAttr&)rSet.Get(ATTR_MERGE);
652 					if (rOldMerge.IsMerged())
653                         rNewSet.Put( ScMergeAttr( Min(
654                                         static_cast<SCsCOL>(rOldMerge.GetRowMerge()),
655                                         static_cast<SCsCOL>(MAXCOL+1 - (nAttrRow2-nRow1))),
656                                     Min(
657                                         static_cast<SCsROW>(rOldMerge.GetColMerge()),
658                                         static_cast<SCsROW>(MAXROW+1 - (nCol-nCol1)))));
659 					const ScMergeFlagAttr& rOldFlag = (const ScMergeFlagAttr&)rSet.Get(ATTR_MERGE_FLAG);
660 					if (rOldFlag.IsOverlapped())
661 					{
662 						sal_Int16 nNewFlags = rOldFlag.GetValue() & ~( SC_MF_HOR | SC_MF_VER );
663 						if ( nNewFlags )
664 							rNewSet.Put( ScMergeFlagAttr( nNewFlags ) );
665 						else
666 							rNewSet.ClearItem( ATTR_MERGE_FLAG );
667 					}
668 
669 					for (nRow = nAttrRow1; nRow<=nAttrRow2; nRow++)
670                         pTransClip->SetPattern( static_cast<SCCOL>(nRow-nRow1),
671                                 static_cast<SCROW>(nCol-nCol1), aNewPattern, sal_True);
672 				}
673 			}
674 		}
675 
676 		delete pAttrIter;
677 	}
678 }
679 
680 
681 void ScTable::StartAllListeners()
682 {
683 	for (SCCOL i=0; i<=MAXCOL; i++)
684 		aCol[i].StartAllListeners();
685 }
686 
687 
688 void ScTable::StartNeededListeners()
689 {
690 	for (SCCOL i=0; i<=MAXCOL; i++)
691         aCol[i].StartNeededListeners();
692 }
693 
694 
695 void ScTable::BroadcastInArea( SCCOL nCol1, SCROW nRow1,
696 		SCCOL nCol2, SCROW nRow2 )
697 {
698 	if (nCol2 > MAXCOL) nCol2 = MAXCOL;
699 	if (nRow2 > MAXROW) nRow2 = MAXROW;
700 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
701 		for (SCCOL i = nCol1; i <= nCol2; i++)
702 			aCol[i].BroadcastInArea( nRow1, nRow2 );
703 }
704 
705 
706 void ScTable::StartListeningInArea( SCCOL nCol1, SCROW nRow1,
707 		SCCOL nCol2, SCROW nRow2 )
708 {
709 	if (nCol2 > MAXCOL) nCol2 = MAXCOL;
710 	if (nRow2 > MAXROW) nRow2 = MAXROW;
711 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
712 		for (SCCOL i = nCol1; i <= nCol2; i++)
713 			aCol[i].StartListeningInArea( nRow1, nRow2 );
714 }
715 
716 
717 void ScTable::CopyToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
718 							sal_uInt16 nFlags, sal_Bool bMarked, ScTable* pDestTab,
719 							const ScMarkData* pMarkData,
720 							sal_Bool bAsLink, sal_Bool bColRowFlags)
721 {
722 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
723 	{
724 		if (nFlags)
725 			for (SCCOL i = nCol1; i <= nCol2; i++)
726 				aCol[i].CopyToColumn(nRow1, nRow2, nFlags, bMarked,
727 								pDestTab->aCol[i], pMarkData, bAsLink);
728 
729 		if (bColRowFlags)		// Spaltenbreiten/Zeilenhoehen/Flags
730 		{
731 			//	Charts muessen beim Ein-/Ausblenden angepasst werden
732 			ScChartListenerCollection* pCharts = pDestTab->pDocument->GetChartListenerCollection();
733 
734             bool bFlagChange = false;
735 
736 			sal_Bool bWidth  = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
737             sal_Bool bHeight = (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights);
738 
739 			if (bWidth||bHeight)
740 			{
741 				pDestTab->IncRecalcLevel();
742 
743 				if (bWidth)
744                 {
745 					for (SCCOL i=nCol1; i<=nCol2; i++)
746 					{
747                         bool bThisHidden = ColHidden(i);
748                         bool bHiddenChange = (pDestTab->ColHidden(i) != bThisHidden);
749                         bool bChange = bHiddenChange || (pDestTab->pColWidth[i] != pColWidth[i]);
750 						pDestTab->pColWidth[i] = pColWidth[i];
751 						pDestTab->pColFlags[i] = pColFlags[i];
752                         pDestTab->SetColHidden(i, i, bThisHidden);
753 						//!	Aenderungen zusammenfassen?
754                         if (bHiddenChange && pCharts)
755                             pCharts->SetRangeDirty(ScRange( i, 0, nTab, i, MAXROW, nTab ));
756 
757                         if (bChange)
758                             bFlagChange = true;
759 					}
760                     pDestTab->SetColManualBreaks( maColManualBreaks);
761                 }
762 
763 				if (bHeight)
764 				{
765                     bool bChange = pDestTab->GetRowHeight(nRow1, nRow2) != GetRowHeight(nRow1, nRow2);
766 
767                     if (bChange)
768                         bFlagChange = true;
769 
770                     pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
771                     pDestTab->pRowFlags->CopyFrom(*pRowFlags, nRow1, nRow2);
772 
773                     // Hidden flags.
774                     // #i116164# Collect information first, then apply the changes,
775                     // so RowHidden doesn't rebuild the tree for each row range.
776                     std::vector<ScShowRowsEntry> aEntries;
777                     for (SCROW i = nRow1; i <= nRow2; ++i)
778                     {
779                         SCROW nThisLastRow, nDestLastRow;
780                         bool bThisHidden = RowHidden(i, NULL, &nThisLastRow);
781                         bool bDestHidden = pDestTab->RowHidden(i, NULL, &nDestLastRow);
782 
783                         // If the segment sizes differ, we take the shorter segment of the two.
784                         SCROW nLastRow = ::std::min(nThisLastRow, nDestLastRow);
785                         if (nLastRow >= nRow2)
786                             // the last row shouldn't exceed the upper bound the caller specified.
787                             nLastRow = nRow2;
788 
789                         //pDestTab->SetRowHidden(i, nLastRow, bThisHidden);
790                         aEntries.push_back(ScShowRowsEntry(i, nLastRow, !bThisHidden));
791 
792                         bool bThisHiddenChange = (bThisHidden != bDestHidden);
793                         if (bThisHiddenChange && pCharts)
794                         {
795                             // Hidden flags differ.
796                             pCharts->SetRangeDirty(ScRange(0, i, nTab, MAXCOL, nLastRow, nTab));
797                         }
798 
799                         if (bThisHiddenChange)
800                             bFlagChange = true;
801 
802                         // Jump to the last row of the identical flag segment.
803                         i = nLastRow;
804 					}
805 
806                     std::vector<ScShowRowsEntry>::const_iterator aEnd = aEntries.end();
807                     std::vector<ScShowRowsEntry>::const_iterator aIter = aEntries.begin();
808                     if ( aIter != aEnd )
809                     {
810                         pDestTab->mpHiddenRows->setInsertFromBack(true);    // important for undo document
811                         while (aIter != aEnd)
812                         {
813                             pDestTab->SetRowHidden(aIter->mnRow1, aIter->mnRow2, !aIter->mbShow);
814                             ++aIter;
815                         }
816                         pDestTab->mpHiddenRows->setInsertFromBack(false);
817                     }
818 
819                     // Filtered flags.
820                     for (SCROW i = nRow1; i <= nRow2; ++i)
821                     {
822                         SCROW nLastRow;
823                         bool bFiltered = RowFiltered(i, NULL, &nLastRow);
824                         if (nLastRow >= nRow2)
825                             // the last row shouldn't exceed the upper bound the caller specified.
826                             nLastRow = nRow2;
827                         pDestTab->SetRowFiltered(i, nLastRow, bFiltered);
828                         i = nLastRow;
829                     }
830                     pDestTab->SetRowManualBreaks( maRowManualBreaks);
831 				}
832 				pDestTab->DecRecalcLevel();
833 			}
834 
835             if (bFlagChange)
836                 pDestTab->InvalidatePageBreaks();
837 
838 			pDestTab->SetOutlineTable( pOutlineTable );		// auch nur wenn bColRowFlags
839 		}
840 	}
841 }
842 
843 
844 void ScTable::UndoToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
845 							sal_uInt16 nFlags, sal_Bool bMarked, ScTable* pDestTab,
846 							const ScMarkData* pMarkData)
847 {
848 	if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
849 	{
850 		sal_Bool bWidth  = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
851         sal_Bool bHeight = (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights);
852 
853 		if (bWidth||bHeight)
854 			IncRecalcLevel();
855 
856 		for ( SCCOL i = 0; i <= MAXCOL; i++)
857 		{
858 			if ( i >= nCol1 && i <= nCol2 )
859 				aCol[i].UndoToColumn(nRow1, nRow2, nFlags, bMarked, pDestTab->aCol[i],
860 										pMarkData);
861 			else
862 				aCol[i].CopyToColumn(0, MAXROW, IDF_FORMULA, sal_False, pDestTab->aCol[i]);
863 		}
864 
865 		if (bWidth||bHeight)
866 		{
867             if (bWidth)
868             {
869                 for (SCCOL i=nCol1; i<=nCol2; i++)
870                     pDestTab->pColWidth[i] = pColWidth[i];
871                 pDestTab->SetColManualBreaks( maColManualBreaks);
872             }
873             if (bHeight)
874             {
875                 pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
876                 pDestTab->SetRowManualBreaks( maRowManualBreaks);
877             }
878             DecRecalcLevel();
879 		}
880 	}
881 }
882 
883 
884 void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
885 {
886 	for (SCCOL i=0; i<=MAXCOL; i++)
887 		aCol[i].CopyUpdated( pPosTab->aCol[i], pDestTab->aCol[i] );
888 }
889 
890 void ScTable::InvalidateTableArea()
891 {
892     bTableAreaValid = sal_False;
893 }
894 
895 void ScTable::InvalidatePageBreaks()
896 {
897     mbPageBreaksValid = false;
898 }
899 
900 void ScTable::CopyScenarioTo( ScTable* pDestTab ) const
901 {
902 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
903 
904 	for (SCCOL i=0; i<=MAXCOL; i++)
905 		aCol[i].CopyScenarioTo( pDestTab->aCol[i] );
906 }
907 
908 void ScTable::CopyScenarioFrom( const ScTable* pSrcTab )
909 {
910 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
911 
912 	for (SCCOL i=0; i<=MAXCOL; i++)
913 		aCol[i].CopyScenarioFrom( pSrcTab->aCol[i] );
914 }
915 
916 void ScTable::MarkScenarioIn( ScMarkData& rDestMark, sal_uInt16 nNeededBits ) const
917 {
918 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
919 
920 	if ( ( nScenarioFlags & nNeededBits ) != nNeededBits )	// alle Bits gesetzt?
921 		return;
922 
923 	for (SCCOL i=0; i<=MAXCOL; i++)
924 		aCol[i].MarkScenarioIn( rDestMark );
925 }
926 
927 sal_Bool ScTable::HasScenarioRange( const ScRange& rRange ) const
928 {
929 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
930 
931 //	ScMarkData aMark;
932 //	MarkScenarioIn( aMark, 0 );				//! Bits als Parameter von HasScenarioRange?
933 //	return aMark.IsAllMarked( rRange );
934 
935 	ScRange aTabRange = rRange;
936 	aTabRange.aStart.SetTab( nTab );
937 	aTabRange.aEnd.SetTab( nTab );
938 
939 	const ScRangeList* pList = GetScenarioRanges();
940 //	return ( pList && pList->Find( aTabRange ) );
941 
942 	if (pList)
943 	{
944 		sal_uLong nCount = pList->Count();
945 		for ( sal_uLong j = 0; j < nCount; j++ )
946 		{
947 			ScRange* pR = pList->GetObject( j );
948 			if ( pR->Intersects( aTabRange ) )
949 				return sal_True;
950 		}
951 	}
952 
953 	return sal_False;
954 }
955 
956 void ScTable::InvalidateScenarioRanges()
957 {
958 	delete pScenarioRanges;
959 	pScenarioRanges = NULL;
960 }
961 
962 const ScRangeList* ScTable::GetScenarioRanges() const
963 {
964 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
965 
966 	if (!pScenarioRanges)
967 	{
968 		((ScTable*)this)->pScenarioRanges = new ScRangeList;
969 		ScMarkData aMark;
970 		MarkScenarioIn( aMark, 0 );		// immer
971 		aMark.FillRangeListWithMarks( pScenarioRanges, sal_False );
972 	}
973 	return pScenarioRanges;
974 }
975 
976 sal_Bool ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
977 {
978 	DBG_ASSERT( bScenario, "bScenario == FALSE" );
979 
980 	if (!pDestTab->IsProtected())
981 		return sal_True;
982 
983 	sal_Bool bOk = sal_True;
984 	for (SCCOL i=0; i<=MAXCOL && bOk; i++)
985 		bOk = aCol[i].TestCopyScenarioTo( pDestTab->aCol[i] );
986 	return bOk;
987 }
988 
989 void ScTable::PutCell( SCCOL nCol, SCROW nRow, ScBaseCell* pCell )
990 {
991 	if (ValidColRow(nCol,nRow))
992 	{
993 		if (pCell)
994 			aCol[nCol].Insert( nRow, pCell );
995 		else
996 			aCol[nCol].Delete( nRow );
997 	}
998 }
999 
1000 
1001 void ScTable::PutCell( SCCOL nCol, SCROW nRow, sal_uLong nFormatIndex, ScBaseCell* pCell )
1002 {
1003 	if (ValidColRow(nCol,nRow))
1004 	{
1005 		if (pCell)
1006 			aCol[nCol].Insert( nRow, nFormatIndex, pCell );
1007 		else
1008 			aCol[nCol].Delete( nRow );
1009 	}
1010 }
1011 
1012 
1013 void ScTable::PutCell( const ScAddress& rPos, ScBaseCell* pCell )
1014 {
1015 	if (pCell)
1016 		aCol[rPos.Col()].Insert( rPos.Row(), pCell );
1017 	else
1018 		aCol[rPos.Col()].Delete( rPos.Row() );
1019 }
1020 
1021 
1022 //UNUSED2009-05 void ScTable::PutCell( const ScAddress& rPos, sal_uLong nFormatIndex, ScBaseCell* pCell )
1023 //UNUSED2009-05 {
1024 //UNUSED2009-05     if (pCell)
1025 //UNUSED2009-05         aCol[rPos.Col()].Insert( rPos.Row(), nFormatIndex, pCell );
1026 //UNUSED2009-05     else
1027 //UNUSED2009-05         aCol[rPos.Col()].Delete( rPos.Row() );
1028 //UNUSED2009-05 }
1029 
1030 
1031 sal_Bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const String& rString,
1032                          SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
1033 {
1034 	if (ValidColRow(nCol,nRow))
1035         return aCol[nCol].SetString(
1036             nRow, nTabP, rString, pDocument->GetAddressConvention(), pFormatter, bDetectNumberFormat );
1037 	else
1038 		return sal_False;
1039 }
1040 
1041 
1042 void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
1043 {
1044 	if (ValidColRow(nCol, nRow))
1045 		aCol[nCol].SetValue( nRow, rVal );
1046 }
1047 
1048 
1049 void ScTable::GetString( SCCOL nCol, SCROW nRow, String& rString )
1050 {
1051 	if (ValidColRow(nCol,nRow))
1052 		aCol[nCol].GetString( nRow, rString );
1053 	else
1054 		rString.Erase();
1055 }
1056 
1057 
1058 void ScTable::GetInputString( SCCOL nCol, SCROW nRow, String& rString )
1059 {
1060 	if (ValidColRow(nCol,nRow))
1061 		aCol[nCol].GetInputString( nRow, rString );
1062 	else
1063 		rString.Erase();
1064 }
1065 
1066 
1067 double ScTable::GetValue( SCCOL nCol, SCROW nRow )
1068 {
1069 	if (ValidColRow( nCol, nRow ))
1070 		return aCol[nCol].GetValue( nRow );
1071 	return 0.0;
1072 }
1073 
1074 
1075 void ScTable::GetFormula( SCCOL nCol, SCROW nRow, String& rFormula,
1076 						  sal_Bool bAsciiExport )
1077 {
1078 	if (ValidColRow(nCol,nRow))
1079 		aCol[nCol].GetFormula( nRow, rFormula, bAsciiExport );
1080 	else
1081 		rFormula.Erase();
1082 }
1083 
1084 
1085 ScPostIt* ScTable::GetNote( SCCOL nCol, SCROW nRow )
1086 {
1087 	return ValidColRow( nCol, nRow ) ? aCol[ nCol ].GetNote( nRow ) : 0;
1088 }
1089 
1090 
1091 void ScTable::TakeNote( SCCOL nCol, SCROW nRow, ScPostIt*& rpNote )
1092 {
1093 	if( ValidColRow( nCol, nRow ) )
1094     {
1095         aCol[ nCol ].TakeNote( nRow, rpNote );
1096         if( rpNote && rpNote->GetNoteData().mxInitData.get() )
1097         {
1098             if( !mxUninitNotes.get() )
1099                 mxUninitNotes.reset( new ScAddress2DVec );
1100             mxUninitNotes->push_back( ScAddress2D( nCol, nRow ) );
1101         }
1102     }
1103     else
1104         DELETEZ( rpNote );
1105 }
1106 
1107 
1108 ScPostIt* ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
1109 {
1110 	return ValidColRow( nCol, nRow ) ? aCol[ nCol ].ReleaseNote( nRow ) : 0;
1111 }
1112 
1113 
1114 void ScTable::DeleteNote( SCCOL nCol, SCROW nRow )
1115 {
1116 	if( ValidColRow( nCol, nRow ) )
1117         aCol[ nCol ].DeleteNote( nRow );
1118 }
1119 
1120 
1121 void ScTable::InitializeNoteCaptions( bool bForced )
1122 {
1123     if( mxUninitNotes.get() && (bForced || pDocument->IsUndoEnabled()) )
1124     {
1125         for( ScAddress2DVec::iterator aIt = mxUninitNotes->begin(), aEnd = mxUninitNotes->end(); aIt != aEnd; ++aIt )
1126             if( ScPostIt* pNote = GetNote( aIt->first, aIt->second ) )
1127                 pNote->GetOrCreateCaption( ScAddress( aIt->first, aIt->second, nTab ) );
1128         mxUninitNotes.reset();
1129     }
1130 }
1131 
1132 CellType ScTable::GetCellType( SCCOL nCol, SCROW nRow ) const
1133 {
1134 	if (ValidColRow( nCol, nRow ))
1135 		return aCol[nCol].GetCellType( nRow );
1136 	return CELLTYPE_NONE;
1137 }
1138 
1139 
1140 ScBaseCell* ScTable::GetCell( SCCOL nCol, SCROW nRow ) const
1141 {
1142 	if (ValidColRow( nCol, nRow ))
1143 		return aCol[nCol].GetCell( nRow );
1144 
1145 	DBG_ERROR("GetCell ausserhalb");
1146 	return NULL;
1147 }
1148 
1149 void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
1150 {
1151     rCol = 0;
1152     rRow = MAXROW+1;
1153     while (aCol[rCol].IsEmptyData() && rCol < MAXCOL)
1154         ++rCol;
1155     SCCOL nCol = rCol;
1156     while (nCol <= MAXCOL && rRow > 0)
1157     {
1158         if (!aCol[nCol].IsEmptyData())
1159             rRow = ::std::min( rRow, aCol[nCol].GetFirstDataPos());
1160         ++nCol;
1161     }
1162 }
1163 
1164 void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
1165 {
1166     rCol = MAXCOL;
1167     rRow = 0;
1168     while (aCol[rCol].IsEmptyData() && (rCol > 0))
1169         rCol--;
1170     SCCOL nCol = rCol;
1171     while (nCol >= 0 && rRow < MAXROW)
1172         rRow = ::std::max( rRow, aCol[nCol--].GetLastDataPos());
1173 }
1174 
1175 
1176 sal_Bool ScTable::HasData( SCCOL nCol, SCROW nRow )
1177 {
1178 	if (ValidColRow(nCol,nRow))
1179 		return aCol[nCol].HasDataAt( nRow );
1180 	else
1181 		return sal_False;
1182 }
1183 
1184 
1185 sal_Bool ScTable::HasStringData( SCCOL nCol, SCROW nRow )
1186 {
1187 	if (ValidColRow(nCol,nRow))
1188 		return aCol[nCol].HasStringData( nRow );
1189 	else
1190 		return sal_False;
1191 }
1192 
1193 
1194 sal_Bool ScTable::HasValueData( SCCOL nCol, SCROW nRow )
1195 {
1196 	if (ValidColRow(nCol,nRow))
1197 		return aCol[nCol].HasValueData( nRow );
1198 	else
1199 		return sal_False;
1200 }
1201 
1202 
1203 sal_Bool ScTable::HasStringCells( SCCOL nStartCol, SCROW nStartRow,
1204 								SCCOL nEndCol, SCROW nEndRow ) const
1205 {
1206 	if ( ValidCol(nEndCol) )
1207 		for ( SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++ )
1208 			if (aCol[nCol].HasStringCells(nStartRow, nEndRow))
1209 				return sal_True;
1210 
1211 	return sal_False;
1212 }
1213 
1214 
1215 //UNUSED2008-05  sal_uInt16 ScTable::GetErrCode( SCCOL nCol, SCROW nRow ) const
1216 //UNUSED2008-05  {
1217 //UNUSED2008-05      if (ValidColRow( nCol, nRow ))
1218 //UNUSED2008-05          return aCol[nCol].GetErrCode( nRow );
1219 //UNUSED2008-05      return 0;
1220 //UNUSED2008-05  }
1221 
1222 
1223 void ScTable::SetDirtyVar()
1224 {
1225 	for (SCCOL i=0; i<=MAXCOL; i++)
1226 		aCol[i].SetDirtyVar();
1227 }
1228 
1229 
1230 void ScTable::SetDirty()
1231 {
1232 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1233 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1234 	for (SCCOL i=0; i<=MAXCOL; i++)
1235 		aCol[i].SetDirty();
1236 	pDocument->SetAutoCalc( bOldAutoCalc );
1237 }
1238 
1239 
1240 void ScTable::SetDirty( const ScRange& rRange )
1241 {
1242 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1243 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1244 	SCCOL nCol2 = rRange.aEnd.Col();
1245 	for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
1246 		aCol[i].SetDirty( rRange );
1247 	pDocument->SetAutoCalc( bOldAutoCalc );
1248 }
1249 
1250 
1251 void ScTable::SetTableOpDirty( const ScRange& rRange )
1252 {
1253 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1254 	pDocument->SetAutoCalc( sal_False );	// no multiple recalculation
1255 	SCCOL nCol2 = rRange.aEnd.Col();
1256 	for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
1257 		aCol[i].SetTableOpDirty( rRange );
1258 	pDocument->SetAutoCalc( bOldAutoCalc );
1259 }
1260 
1261 
1262 void ScTable::SetDirtyAfterLoad()
1263 {
1264 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1265 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1266 	for (SCCOL i=0; i<=MAXCOL; i++)
1267 		aCol[i].SetDirtyAfterLoad();
1268 	pDocument->SetAutoCalc( bOldAutoCalc );
1269 }
1270 
1271 
1272 void ScTable::SetRelNameDirty()
1273 {
1274 	sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1275 	pDocument->SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1276 	for (SCCOL i=0; i<=MAXCOL; i++)
1277 		aCol[i].SetRelNameDirty();
1278 	pDocument->SetAutoCalc( bOldAutoCalc );
1279 }
1280 
1281 
1282 void ScTable::SetLoadingMedium(bool bLoading)
1283 {
1284     mpRowHeights->enableTreeSearch(!bLoading);
1285 
1286     // When loading a medium, prefer inserting row heights from the back
1287     // position since the row heights are stored and read in ascending order
1288     // during import.
1289     mpRowHeights->setInsertFromBack(bLoading);
1290 }
1291 
1292 
1293 void ScTable::CalcAll()
1294 {
1295 	for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CalcAll();
1296 }
1297 
1298 
1299 void ScTable::CompileAll()
1300 {
1301 	for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].CompileAll();
1302 }
1303 
1304 
1305 void ScTable::CompileXML( ScProgress& rProgress )
1306 {
1307 	for (SCCOL i=0; i <= MAXCOL; i++)
1308 	{
1309 		aCol[i].CompileXML( rProgress );
1310 	}
1311 }
1312 
1313 void ScTable::CalcAfterLoad()
1314 {
1315 	for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].CalcAfterLoad();
1316 }
1317 
1318 
1319 void ScTable::ResetChanged( const ScRange& rRange )
1320 {
1321 	SCCOL nStartCol = rRange.aStart.Col();
1322 	SCROW nStartRow = rRange.aStart.Row();
1323 	SCCOL nEndCol = rRange.aEnd.Col();
1324 	SCROW nEndRow = rRange.aEnd.Row();
1325 
1326 	for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
1327 		aCol[nCol].ResetChanged(nStartRow, nEndRow);
1328 }
1329 
1330 //	Attribute
1331 
1332 const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich ) const
1333 {
1334 	if (ValidColRow(nCol,nRow))
1335 		return aCol[nCol].GetAttr( nRow, nWhich );
1336 	else
1337 		return NULL;
1338 }
1339 
1340 
1341 sal_uLong ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
1342 {
1343 	if (ValidColRow(nCol,nRow))
1344 		return aCol[nCol].GetNumberFormat( nRow );
1345 	else
1346 		return 0;
1347 }
1348 
1349 
1350 const ScPatternAttr* ScTable::GetPattern( SCCOL nCol, SCROW nRow ) const
1351 {
1352 	if (ValidColRow(nCol,nRow))
1353 		return aCol[nCol].GetPattern( nRow );
1354 	else
1355     {
1356         DBG_ERROR("wrong column or row");
1357         return pDocument->GetDefPattern();      // for safety
1358     }
1359 }
1360 
1361 
1362 const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
1363 {
1364     if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow) )
1365         return aCol[nCol].GetMostUsedPattern( nStartRow, nEndRow );
1366     else
1367         return NULL;
1368 }
1369 
1370 
1371 bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nMask ) const
1372 {
1373 	bool bFound = false;
1374 	for (SCCOL i=nCol1; i<=nCol2 && !bFound; i++)
1375 		bFound |= aCol[i].HasAttrib( nRow1, nRow2, nMask );
1376 	return bFound;
1377 }
1378 
1379 
1380 //UNUSED2009-05 sal_Bool ScTable::HasLines( const ScRange& rRange, Rectangle& rSizes ) const
1381 //UNUSED2009-05 {
1382 //UNUSED2009-05     SCCOL nCol1 = rRange.aStart.Col();
1383 //UNUSED2009-05     SCROW nRow1 = rRange.aStart.Row();
1384 //UNUSED2009-05     SCCOL nCol2 = rRange.aEnd.Col();
1385 //UNUSED2009-05     SCROW nRow2 = rRange.aEnd.Row();
1386 //UNUSED2009-05     PutInOrder( nCol1, nCol2 );
1387 //UNUSED2009-05     PutInOrder( nRow1, nRow2 );
1388 //UNUSED2009-05
1389 //UNUSED2009-05     sal_Bool bFound = sal_False;
1390 //UNUSED2009-05     for (SCCOL i=nCol1; i<=nCol2; i++)
1391 //UNUSED2009-05         if (aCol[i].HasLines( nRow1, nRow2, rSizes, (i==nCol1), (i==nCol2) ))
1392 //UNUSED2009-05             bFound = sal_True;
1393 //UNUSED2009-05
1394 //UNUSED2009-05     return bFound;
1395 //UNUSED2009-05 }
1396 
1397 
1398 sal_Bool ScTable::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
1399 {
1400 	sal_Bool bFound=sal_False;
1401 	for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
1402 		bFound |= aCol[i].HasAttribSelection( rMark, nMask );
1403 	return bFound;
1404 }
1405 
1406 
1407 sal_Bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
1408 						   SCCOL& rEndCol, SCROW& rEndRow,
1409 						   sal_Bool bRefresh, sal_Bool bAttrs )
1410 {
1411     if (!(ValidCol(nStartCol) && ValidCol(rEndCol)))
1412     {
1413         DBG_ERRORFILE("ScTable::ExtendMerge: invalid column number");
1414         return sal_False;
1415     }
1416 	sal_Bool bFound=sal_False;
1417 	SCCOL nOldEndX = rEndCol;
1418 	SCROW nOldEndY = rEndRow;
1419 	for (SCCOL i=nStartCol; i<=nOldEndX; i++)
1420 		bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh, bAttrs );
1421 	return bFound;
1422 }
1423 
1424 
1425 sal_Bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bIgnoreNotes ) const
1426 {
1427     if (!(ValidCol(nCol1) && ValidCol(nCol2)))
1428     {
1429         DBG_ERRORFILE("ScTable::IsBlockEmpty: invalid column number");
1430         return sal_False;
1431     }
1432 	sal_Bool bEmpty = sal_True;
1433 	for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
1434 		bEmpty = aCol[i].IsEmptyBlock( nRow1, nRow2, bIgnoreNotes );
1435 	return bEmpty;
1436 }
1437 
1438 SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2,
1439 							SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY,
1440 							const ScPatternAttr* pPattern, const SfxItemSet* pCondSet )
1441 {
1442 	//	Rueckgabe = neues nArrY
1443 
1444 	sal_uInt8 nRotDir = pPattern->GetRotateDir( pCondSet );
1445 	if ( nRotDir != SC_ROTDIR_NONE )
1446 	{
1447 		sal_Bool bHit = sal_True;
1448 		if ( nCol+1 < nX1 )								// column to the left
1449 			bHit = ( nRotDir != SC_ROTDIR_LEFT );
1450 		else if ( nCol > nX2+1 )						// column to the right
1451 			bHit = ( nRotDir != SC_ROTDIR_RIGHT );		// SC_ROTDIR_STANDARD may now also be extended to the left
1452 
1453 		if ( bHit )
1454 		{
1455 			double nFactor = 0.0;
1456 			if ( nCol > nX2+1 )
1457 			{
1458 				long nRotVal = ((const SfxInt32Item&) pPattern->
1459 						GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue();
1460 				double nRealOrient = nRotVal * F_PI18000;	// 1/100 Grad
1461 				double nCos = cos( nRealOrient );
1462 				double nSin = sin( nRealOrient );
1463 				//!	begrenzen !!!
1464 				//!	zusaetzlich Faktor fuer unterschiedliche PPT X/Y !!!
1465 
1466 				//	bei SC_ROTDIR_LEFT kommt immer ein negativer Wert heraus,
1467 				//	wenn der Modus beruecksichtigt wird
1468 				nFactor = -fabs( nCos / nSin );
1469 			}
1470 
1471 			for ( SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++ )
1472 			{
1473                 if (!RowHidden(nRow))
1474 				{
1475 					sal_Bool bHitOne = sal_True;
1476 					if ( nCol > nX2+1 )
1477 					{
1478 						// reicht die gedrehte Zelle bis in den sichtbaren Bereich?
1479 
1480 						SCCOL nTouchedCol = nCol;
1481                         long nWidth = static_cast<long>(mpRowHeights->getValue(nRow) * nFactor);
1482 						DBG_ASSERT(nWidth <= 0, "Richtung falsch");
1483 						while ( nWidth < 0 && nTouchedCol > 0 )
1484 						{
1485 							--nTouchedCol;
1486 							nWidth += GetColWidth( nTouchedCol );
1487 						}
1488 						if ( nTouchedCol > nX2 )
1489 							bHitOne = sal_False;
1490 					}
1491 
1492 					if (bHitOne)
1493 					{
1494 						while ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo < nRow )
1495 							++nArrY;
1496 						if ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo == nRow )
1497 							pRowInfo[nArrY].nRotMaxCol = nCol;
1498 					}
1499 				}
1500 			}
1501 		}
1502 	}
1503 
1504 	return nArrY;
1505 }
1506 
1507 void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2 )
1508 {
1509     if ( !pColWidth || !mpRowHeights || !pColFlags || !pRowFlags )
1510 	{
1511 		DBG_ERROR( "Spalten-/Zeileninfo fehlt" );
1512 		return;
1513 	}
1514 
1515 	//	nRotMaxCol ist auf SC_ROTMAX_NONE initialisiert, nRowNo ist schon gesetzt
1516 
1517 	SCROW nY1 = pRowInfo[0].nRowNo;
1518 	SCROW nY2 = pRowInfo[nArrCount-1].nRowNo;
1519 
1520 	for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
1521 	{
1522         if (!ColHidden(nCol))
1523 		{
1524 			SCSIZE nArrY = 0;
1525 			ScDocAttrIterator aIter( pDocument, nTab, nCol, nY1, nCol, nY2 );
1526 			SCCOL nAttrCol;
1527             SCROW nAttrRow1, nAttrRow2;
1528 			const ScPatternAttr* pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
1529 			while ( pPattern )
1530 			{
1531 				const SfxPoolItem* pCondItem;
1532 				if ( pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, sal_True, &pCondItem )
1533 						== SFX_ITEM_SET )
1534 				{
1535 					//	alle Formate durchgehen, damit die Zellen nicht einzeln
1536 					//	angeschaut werden muessen
1537 
1538 					sal_uLong nIndex = ((const SfxUInt32Item*)pCondItem)->GetValue();
1539 					ScConditionalFormatList* pList = pDocument->GetCondFormList();
1540 					ScStyleSheetPool* pStylePool = pDocument->GetStyleSheetPool();
1541 					if (pList && pStylePool && nIndex)
1542 					{
1543 						const ScConditionalFormat* pFormat = pList->GetFormat(nIndex);
1544 						if ( pFormat )
1545 						{
1546 							sal_uInt16 nEntryCount = pFormat->Count();
1547 							for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
1548 							{
1549                                 String aStyleName = pFormat->GetEntry(nEntry)->GetStyle();
1550                                 if (aStyleName.Len())
1551 								{
1552 									SfxStyleSheetBase* pStyleSheet =
1553                                             pStylePool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
1554 									if ( pStyleSheet )
1555 									{
1556 										FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
1557 													nCol, nAttrRow1, nAttrRow2,
1558 													nArrY, pPattern, &pStyleSheet->GetItemSet() );
1559 										//	nArrY nicht veraendern
1560 									}
1561 								}
1562 							}
1563 						}
1564 					}
1565 				}
1566 
1567 				nArrY = FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
1568 									nCol, nAttrRow1, nAttrRow2,
1569 									nArrY, pPattern, NULL );
1570 
1571 				pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
1572 			}
1573 		}
1574 	}
1575 }
1576 
1577 sal_Bool ScTable::HasBlockMatrixFragment( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
1578 {
1579 	// nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
1580 	sal_uInt16 nEdges;
1581 
1582 	if ( nCol1 == nCol2 )
1583 	{	// linke und rechte Spalte
1584 		const sal_uInt16 n = 4 | 16;
1585 		nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, n );
1586 		// nicht (4 und 16) oder 1 oder 32
1587 		if ( nEdges && (((nEdges & n) != n) || (nEdges & 33)) )
1588 			return sal_True;		// linke oder rechte Kante fehlt oder offen
1589 	}
1590 	else
1591 	{	// linke Spalte
1592 		nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, 4 );
1593 		// nicht 4 oder 1 oder 32
1594 		if ( nEdges && (((nEdges & 4) != 4) || (nEdges & 33)) )
1595 			return sal_True;		// linke Kante fehlt oder offen
1596 		// rechte Spalte
1597 		nEdges = aCol[nCol2].GetBlockMatrixEdges( nRow1, nRow2, 16 );
1598 		// nicht 16 oder 1 oder 32
1599 		if ( nEdges && (((nEdges & 16) != 16) || (nEdges & 33)) )
1600 			return sal_True;		// rechte Kante fehlt oder offen
1601 	}
1602 
1603 	if ( nRow1 == nRow2 )
1604 	{	// obere und untere Zeile
1605 		sal_Bool bOpen = sal_False;
1606 		const sal_uInt16 n = 2 | 8;
1607 		for ( SCCOL i=nCol1; i<=nCol2; i++)
1608 		{
1609 			nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n );
1610 			if ( nEdges )
1611 			{
1612 				if ( (nEdges & n) != n )
1613 					return sal_True;		// obere oder untere Kante fehlt
1614 				if ( nEdges & 4 )
1615 					bOpen = sal_True;		// linke Kante oeffnet, weitersehen
1616 				else if ( !bOpen )
1617 					return sal_True;		// es gibt was, was nicht geoeffnet wurde
1618 				if ( nEdges & 16 )
1619 					bOpen = sal_False;		// rechte Kante schliesst
1620 			}
1621 		}
1622 		if ( bOpen )
1623 			return sal_True;				// es geht noch weiter
1624 	}
1625 	else
1626 	{
1627 		sal_uInt16 j, n;
1628         SCROW nR;
1629 		// erst obere Zeile, dann untere Zeile
1630 		for ( j=0, nR=nRow1, n=8; j<2; j++, nR=nRow2, n=2 )
1631 		{
1632 			sal_Bool bOpen = sal_False;
1633 			for ( SCCOL i=nCol1; i<=nCol2; i++)
1634 			{
1635 				nEdges = aCol[i].GetBlockMatrixEdges( nR, nR, n );
1636 				if ( nEdges )
1637 				{
1638 					// in oberere Zeile keine obere Kante bzw.
1639 					// in unterer Zeile keine untere Kante
1640 					if ( (nEdges & n) != n )
1641 						return sal_True;
1642 					if ( nEdges & 4 )
1643 						bOpen = sal_True;		// linke Kante oeffnet, weitersehen
1644 					else if ( !bOpen )
1645 						return sal_True;		// es gibt was, was nicht geoeffnet wurde
1646 					if ( nEdges & 16 )
1647 						bOpen = sal_False;		// rechte Kante schliesst
1648 				}
1649 			}
1650 			if ( bOpen )
1651 				return sal_True;				// es geht noch weiter
1652 		}
1653 	}
1654 	return sal_False;
1655 }
1656 
1657 
1658 sal_Bool ScTable::HasSelectionMatrixFragment( const ScMarkData& rMark ) const
1659 {
1660 	sal_Bool bFound=sal_False;
1661 	for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
1662 		bFound |= aCol[i].HasSelectionMatrixFragment(rMark);
1663 	return bFound;
1664 }
1665 
1666 
1667 sal_Bool ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
1668 			SCROW nRow2, sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
1669 {
1670     if ( !ValidColRow( nCol2, nRow2 ) )
1671     {
1672         DBG_ERRORFILE("IsBlockEditable: invalid column or row");
1673         if (pOnlyNotBecauseOfMatrix)
1674             *pOnlyNotBecauseOfMatrix = sal_False;
1675         return sal_False;
1676     }
1677 
1678 	sal_Bool bIsEditable = sal_True;
1679 	if ( nLockCount )
1680 		bIsEditable = sal_False;
1681     else if ( IsProtected() && !pDocument->IsScenario(nTab) )
1682     {
1683         if((bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HASATTR_PROTECTED )) != sal_False)
1684         {
1685             // If Sheet is protected and cells are not protected then
1686             // check the active scenario protect flag if this range is
1687             // on the active scenario range. Note the 'copy back' must also
1688             // be set to apply protection.
1689             sal_uInt16 nScenTab = nTab+1;
1690             while(pDocument->IsScenario(nScenTab))
1691             {
1692                 ScRange aEditRange(nCol1, nRow1, nScenTab, nCol2, nRow2, nScenTab);
1693                 if(pDocument->IsActiveScenario(nScenTab) && pDocument->HasScenarioRange(nScenTab, aEditRange))
1694                 {
1695                     sal_uInt16 nFlags;
1696                     pDocument->GetScenarioFlags(nScenTab,nFlags);
1697                     bIsEditable = !((nFlags & SC_SCENARIO_PROTECT) && (nFlags & SC_SCENARIO_TWOWAY));
1698                     break;
1699                 }
1700                 nScenTab++;
1701             }
1702         }
1703     }
1704     else if (pDocument->IsScenario(nTab))
1705     {
1706         // Determine if the preceding sheet is protected
1707         SCTAB nActualTab = nTab;
1708         do
1709         {
1710             nActualTab--;
1711         }
1712         while(pDocument->IsScenario(nActualTab));
1713 
1714         if(pDocument->IsTabProtected(nActualTab))
1715         {
1716             ScRange aEditRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1717             if(pDocument->HasScenarioRange(nTab, aEditRange))
1718             {
1719                 sal_uInt16 nFlags;
1720                 pDocument->GetScenarioFlags(nTab,nFlags);
1721                 bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
1722             }
1723         }
1724     }
1725 	if ( bIsEditable )
1726 	{
1727 		if ( HasBlockMatrixFragment( nCol1, nRow1, nCol2, nRow2 ) )
1728 		{
1729 			bIsEditable = sal_False;
1730 			if ( pOnlyNotBecauseOfMatrix )
1731 				*pOnlyNotBecauseOfMatrix = sal_True;
1732 		}
1733 		else if ( pOnlyNotBecauseOfMatrix )
1734 			*pOnlyNotBecauseOfMatrix = sal_False;
1735 	}
1736 	else if ( pOnlyNotBecauseOfMatrix )
1737 		*pOnlyNotBecauseOfMatrix = sal_False;
1738 	return bIsEditable;
1739 }
1740 
1741 
1742 sal_Bool ScTable::IsSelectionEditable( const ScMarkData& rMark,
1743 			sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
1744 {
1745 	sal_Bool bIsEditable = sal_True;
1746 	if ( nLockCount )
1747 		bIsEditable = sal_False;
1748     else if ( IsProtected() && !pDocument->IsScenario(nTab) )
1749     {
1750         if((bIsEditable = !HasAttribSelection( rMark, HASATTR_PROTECTED )) != sal_False)
1751         {
1752             // If Sheet is protected and cells are not protected then
1753             // check the active scenario protect flag if this area is
1754             // in the active scenario range.
1755             ScRangeList aRanges;
1756             rMark.FillRangeListWithMarks( &aRanges, sal_False );
1757             sal_uLong nRangeCount = aRanges.Count();
1758             SCTAB nScenTab = nTab+1;
1759             while(pDocument->IsScenario(nScenTab) && bIsEditable)
1760             {
1761                 if(pDocument->IsActiveScenario(nScenTab))
1762                 {
1763                     for (sal_uLong i=0; i<nRangeCount && bIsEditable; i++)
1764                     {
1765                         ScRange aRange = *aRanges.GetObject(i);
1766                         if(pDocument->HasScenarioRange(nScenTab, aRange))
1767                         {
1768                             sal_uInt16 nFlags;
1769                             pDocument->GetScenarioFlags(nScenTab,nFlags);
1770                             bIsEditable = !((nFlags & SC_SCENARIO_PROTECT) && (nFlags & SC_SCENARIO_TWOWAY));
1771                         }
1772                     }
1773                 }
1774                 nScenTab++;
1775             }
1776         }
1777     }
1778     else if (pDocument->IsScenario(nTab))
1779     {
1780         // Determine if the preceding sheet is protected
1781         SCTAB nActualTab = nTab;
1782         do
1783         {
1784             nActualTab--;
1785         }
1786         while(pDocument->IsScenario(nActualTab));
1787 
1788         if(pDocument->IsTabProtected(nActualTab))
1789         {
1790             ScRangeList aRanges;
1791             rMark.FillRangeListWithMarks( &aRanges, sal_False );
1792             sal_uLong nRangeCount = aRanges.Count();
1793             for (sal_uLong i=0; i<nRangeCount && bIsEditable; i++)
1794             {
1795                 ScRange aRange = *aRanges.GetObject(i);
1796                 if(pDocument->HasScenarioRange(nTab, aRange))
1797                 {
1798                     sal_uInt16 nFlags;
1799                     pDocument->GetScenarioFlags(nTab,nFlags);
1800                     bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
1801                 }
1802             }
1803         }
1804     }
1805 	if ( bIsEditable )
1806 	{
1807 		if ( HasSelectionMatrixFragment( rMark ) )
1808 		{
1809 			bIsEditable = sal_False;
1810 			if ( pOnlyNotBecauseOfMatrix )
1811 				*pOnlyNotBecauseOfMatrix = sal_True;
1812 		}
1813 		else if ( pOnlyNotBecauseOfMatrix )
1814 			*pOnlyNotBecauseOfMatrix = sal_False;
1815 	}
1816 	else if ( pOnlyNotBecauseOfMatrix )
1817 		*pOnlyNotBecauseOfMatrix = sal_False;
1818 	return bIsEditable;
1819 }
1820 
1821 
1822 
1823 void ScTable::LockTable()
1824 {
1825 	++nLockCount;
1826 }
1827 
1828 
1829 void ScTable::UnlockTable()
1830 {
1831 	if (nLockCount)
1832 		--nLockCount;
1833 	else
1834 	{
1835 		DBG_ERROR("UnlockTable ohne LockTable");
1836 	}
1837 }
1838 
1839 
1840 void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_Bool bDeep ) const
1841 {
1842 	for (SCCOL i=0; i<=MAXCOL; i++)
1843 		aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
1844 }
1845 
1846 
1847 void ScTable::MergePatternArea( ScMergePatternState& rState, SCCOL nCol1, SCROW nRow1,
1848 													SCCOL nCol2, SCROW nRow2, sal_Bool bDeep ) const
1849 {
1850 	for (SCCOL i=nCol1; i<=nCol2; i++)
1851 		aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
1852 }
1853 
1854 
1855 void ScTable::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
1856 					SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
1857 {
1858 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1859 	{
1860 		PutInOrder(nStartCol, nEndCol);
1861 		PutInOrder(nStartRow, nEndRow);
1862 		for (SCCOL i=nStartCol; i<=nEndCol; i++)
1863 			aCol[i].MergeBlockFrame( pLineOuter, pLineInner, rFlags,
1864 									nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
1865 	}
1866 }
1867 
1868 
1869 void ScTable::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1870 					SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
1871 {
1872 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1873 	{
1874 		PutInOrder(nStartCol, nEndCol);
1875 		PutInOrder(nStartRow, nEndRow);
1876 		for (SCCOL i=nStartCol; i<=nEndCol; i++)
1877 			aCol[i].ApplyBlockFrame( pLineOuter, pLineInner,
1878 									nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
1879 	}
1880 }
1881 
1882 
1883 void ScTable::ApplyPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
1884 {
1885 	if (ValidColRow(nCol,nRow))
1886 		aCol[nCol].ApplyPattern( nRow, rAttr );
1887 }
1888 
1889 
1890 void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1891 									 const ScPatternAttr& rAttr )
1892 {
1893 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1894 	{
1895 		PutInOrder(nStartCol, nEndCol);
1896 		PutInOrder(nStartRow, nEndRow);
1897 		for (SCCOL i = nStartCol; i <= nEndCol; i++)
1898 			aCol[i].ApplyPatternArea(nStartRow, nEndRow, rAttr);
1899 	}
1900 }
1901 
1902 void ScTable::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
1903 		const ScPatternAttr& rPattern, short nNewType )
1904 {
1905 	SCCOL nEndCol = rRange.aEnd.Col();
1906 	for ( SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; nCol++ )
1907 	{
1908 		aCol[nCol].ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
1909 	}
1910 }
1911 
1912 
1913 
1914 void ScTable::ApplyStyle( SCCOL nCol, SCROW nRow, const ScStyleSheet& rStyle )
1915 {
1916 	if (ValidColRow(nCol,nRow))
1917 		aCol[nCol].ApplyStyle( nRow, rStyle );
1918 }
1919 
1920 
1921 void ScTable::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScStyleSheet& rStyle )
1922 {
1923 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1924 	{
1925 		PutInOrder(nStartCol, nEndCol);
1926 		PutInOrder(nStartRow, nEndRow);
1927 		for (SCCOL i = nStartCol; i <= nEndCol; i++)
1928 			aCol[i].ApplyStyleArea(nStartRow, nEndRow, rStyle);
1929 	}
1930 }
1931 
1932 
1933 void ScTable::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
1934 {
1935 	for (SCCOL i=0; i<=MAXCOL; i++)
1936 		aCol[i].ApplySelectionStyle( rStyle, rMark );
1937 }
1938 
1939 
1940 void ScTable::ApplySelectionLineStyle( const ScMarkData& rMark,
1941 							const SvxBorderLine* pLine, sal_Bool bColorOnly )
1942 {
1943 	if ( bColorOnly && !pLine )
1944 		return;
1945 
1946 	for (SCCOL i=0; i<=MAXCOL; i++)
1947 		aCol[i].ApplySelectionLineStyle( rMark, pLine, bColorOnly );
1948 }
1949 
1950 
1951 const ScStyleSheet* ScTable::GetStyle( SCCOL nCol, SCROW nRow ) const
1952 {
1953 	if (ValidColRow(nCol, nRow))
1954 		return aCol[nCol].GetStyle(nRow);
1955 	else
1956 		return NULL;
1957 }
1958 
1959 
1960 const ScStyleSheet* ScTable::GetSelectionStyle( const ScMarkData& rMark, sal_Bool& rFound ) const
1961 {
1962 	rFound = sal_False;
1963 
1964 	sal_Bool	bEqual = sal_True;
1965 	sal_Bool	bColFound;
1966 
1967 	const ScStyleSheet* pStyle = NULL;
1968 	const ScStyleSheet* pNewStyle;
1969 
1970 	for (SCCOL i=0; i<=MAXCOL && bEqual; i++)
1971 		if (rMark.HasMultiMarks(i))
1972 		{
1973 			pNewStyle = aCol[i].GetSelectionStyle( rMark, bColFound );
1974 			if (bColFound)
1975 			{
1976 				rFound = sal_True;
1977 				if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
1978 					bEqual = sal_False;												// unterschiedliche
1979 				pStyle = pNewStyle;
1980 			}
1981 		}
1982 
1983 	return bEqual ? pStyle : NULL;
1984 }
1985 
1986 
1987 const ScStyleSheet*	ScTable::GetAreaStyle( sal_Bool& rFound, SCCOL nCol1, SCROW nRow1,
1988 													SCCOL nCol2, SCROW nRow2 ) const
1989 {
1990 	rFound = sal_False;
1991 
1992 	sal_Bool	bEqual = sal_True;
1993 	sal_Bool	bColFound;
1994 
1995 	const ScStyleSheet* pStyle = NULL;
1996 	const ScStyleSheet* pNewStyle;
1997 
1998 	for (SCCOL i=nCol1; i<=nCol2 && bEqual; i++)
1999 	{
2000 		pNewStyle = aCol[i].GetAreaStyle(bColFound, nRow1, nRow2);
2001 		if (bColFound)
2002 		{
2003 			rFound = sal_True;
2004 			if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
2005 				bEqual = sal_False;												// unterschiedliche
2006 			pStyle = pNewStyle;
2007 		}
2008 	}
2009 
2010 	return bEqual ? pStyle : NULL;
2011 }
2012 
2013 
2014 sal_Bool ScTable::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
2015 {
2016 	sal_Bool bIsUsed = sal_False;
2017 
2018 	for ( SCCOL i=0; i<=MAXCOL; i++ )
2019     {
2020 		if ( aCol[i].IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
2021         {
2022             if ( !bGatherAllStyles )
2023                 return sal_True;
2024             bIsUsed = sal_True;
2025         }
2026     }
2027 
2028 	return bIsUsed;
2029 }
2030 
2031 
2032 void ScTable::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
2033 								OutputDevice* pDev,
2034 								double nPPTX, double nPPTY,
2035 								const Fraction& rZoomX, const Fraction& rZoomY )
2036 {
2037     ScFlatBoolRowSegments aUsedRows;
2038     for (SCCOL i = 0; i <= MAXCOL; ++i)
2039         aCol[i].FindStyleSheet(pStyleSheet, aUsedRows, bRemoved);
2040 
2041     SCROW nRow = 0;
2042     while (nRow <= MAXROW)
2043     {
2044         ScFlatBoolRowSegments::RangeData aData;
2045         if (!aUsedRows.getRangeData(nRow, aData))
2046             // search failed!
2047             return;
2048 
2049         SCROW nEndRow = aData.mnRow2;
2050         if (aData.mbValue)
2051             SetOptimalHeight(nRow, nEndRow, 0, pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False);
2052 
2053         nRow = nEndRow + 1;
2054     }
2055 }
2056 
2057 
2058 sal_Bool ScTable::ApplyFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2059 									sal_Int16 nFlags )
2060 {
2061 	sal_Bool bChanged = sal_False;
2062 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2063 		for (SCCOL i = nStartCol; i <= nEndCol; i++)
2064 			bChanged |= aCol[i].ApplyFlags(nStartRow, nEndRow, nFlags);
2065 	return bChanged;
2066 }
2067 
2068 
2069 sal_Bool ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2070 									sal_Int16 nFlags )
2071 {
2072 	sal_Bool bChanged = sal_False;
2073 	if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2074 		for (SCCOL i = nStartCol; i <= nEndCol; i++)
2075 			bChanged |= aCol[i].RemoveFlags(nStartRow, nEndRow, nFlags);
2076 	return bChanged;
2077 }
2078 
2079 
2080 void ScTable::SetPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr, sal_Bool bPutToPool )
2081 {
2082 	if (ValidColRow(nCol,nRow))
2083 		aCol[nCol].SetPattern( nRow, rAttr, bPutToPool );
2084 }
2085 
2086 
2087 void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
2088 {
2089 	if (ValidColRow(nCol,nRow))
2090 		aCol[nCol].ApplyAttr( nRow, rAttr );
2091 }
2092 
2093 
2094 void ScTable::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
2095 {
2096 	for (SCCOL i=0; i<=MAXCOL; i++)
2097 		aCol[i].ApplySelectionCache( pCache, rMark );
2098 }
2099 
2100 
2101 void ScTable::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
2102 {
2103 	for (SCCOL i=0; i<=MAXCOL; i++)
2104 		aCol[i].ChangeSelectionIndent( bIncrement, rMark );
2105 }
2106 
2107 
2108 void ScTable::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
2109 {
2110 	for (SCCOL i=0; i<=MAXCOL; i++)
2111 		aCol[i].ClearSelectionItems( pWhich, rMark );
2112 }
2113 
2114 
2115 //	Spaltenbreiten / Zeilenhoehen
2116 
2117 void ScTable::SetColWidth( SCCOL nCol, sal_uInt16 nNewWidth )
2118 {
2119 	if (VALIDCOL(nCol) && pColWidth)
2120 	{
2121 		if (!nNewWidth)
2122 		{
2123 //			DBG_ERROR("Spaltenbreite 0 in SetColWidth");
2124 			nNewWidth = STD_COL_WIDTH;
2125 		}
2126 
2127 		if ( nNewWidth != pColWidth[nCol] )
2128 		{
2129 			IncRecalcLevel();
2130             InitializeNoteCaptions();
2131 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2132 			if (pDrawLayer)
2133 				pDrawLayer->WidthChanged( nTab, nCol, ((long) nNewWidth) - (long) pColWidth[nCol] );
2134 			pColWidth[nCol] = nNewWidth;
2135 			DecRecalcLevel();
2136 
2137             InvalidatePageBreaks();
2138 		}
2139 	}
2140 	else
2141 	{
2142 		DBG_ERROR("Falsche Spaltennummer oder keine Breiten");
2143 	}
2144 }
2145 
2146 
2147 void ScTable::SetRowHeight( SCROW nRow, sal_uInt16 nNewHeight )
2148 {
2149     if (VALIDROW(nRow) && mpRowHeights)
2150 	{
2151 		if (!nNewHeight)
2152 		{
2153 			DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
2154 			nNewHeight = ScGlobal::nStdRowHeight;
2155 		}
2156 
2157         sal_uInt16 nOldHeight = mpRowHeights->getValue(nRow);
2158 		if ( nNewHeight != nOldHeight )
2159 		{
2160 			IncRecalcLevel();
2161             InitializeNoteCaptions();
2162 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2163 			if (pDrawLayer)
2164 				pDrawLayer->HeightChanged( nTab, nRow, ((long) nNewHeight) - (long) nOldHeight );
2165             mpRowHeights->setValue(nRow, nRow, nNewHeight);
2166 			DecRecalcLevel();
2167 
2168             InvalidatePageBreaks();
2169 		}
2170 	}
2171 	else
2172 	{
2173 		DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
2174 	}
2175 }
2176 
2177 namespace {
2178 
2179 /**
2180  * Check if the new pixel size is different from the old size between
2181  * specified ranges.
2182  */
2183 bool lcl_pixelSizeChanged(
2184     ScFlatUInt16RowSegments& rRowHeights, SCROW nStartRow, SCROW nEndRow,
2185     sal_uInt16 nNewHeight, double nPPTY)
2186 {
2187     long nNewPix = static_cast<long>(nNewHeight * nPPTY);
2188 
2189     ScFlatUInt16RowSegments::ForwardIterator aFwdIter(rRowHeights);
2190     for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
2191     {
2192         sal_uInt16 nHeight;
2193         if (!aFwdIter.getValue(nRow, nHeight))
2194             break;
2195 
2196         if (nHeight != nNewHeight)
2197         {
2198             bool bChanged = (nNewPix != static_cast<long>(nHeight * nPPTY));
2199             if (bChanged)
2200                 return true;
2201         }
2202 
2203         // Skip ahead to the last position of the current range.
2204         nRow = aFwdIter.getLastPos();
2205     }
2206     return false;
2207 }
2208 
2209 }
2210 
2211 sal_Bool ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight,
2212                                     double /* nPPTX */, double nPPTY )
2213 {
2214 	sal_Bool bChanged = sal_False;
2215     if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
2216 	{
2217 		IncRecalcLevel();
2218         InitializeNoteCaptions();
2219 		if (!nNewHeight)
2220 		{
2221 			DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
2222 			nNewHeight = ScGlobal::nStdRowHeight;
2223 		}
2224 
2225         sal_Bool bSingle = sal_False;   // sal_True = process every row for its own
2226 		ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2227 		if (pDrawLayer)
2228 			if (pDrawLayer->HasObjectsInRows( nTab, nStartRow, nEndRow ))
2229 				bSingle = sal_True;
2230 
2231 		if (bSingle)
2232 		{
2233             ScFlatUInt16RowSegments::RangeData aData;
2234             mpRowHeights->getRangeData(nStartRow, aData);
2235             if (nNewHeight == aData.mnValue && nEndRow <= aData.mnRow2)
2236                 bSingle = sal_False;    // no difference in this range
2237 		}
2238 		if (bSingle)
2239 		{
2240 			if (nEndRow-nStartRow < 20)
2241             {
2242                 if (!bChanged)
2243                     bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
2244 
2245                 /*  #i94028# #i94991# If drawing objects are involved, each row
2246                     has to be changed for its own, because each call to
2247                     ScDrawLayer::HeightChanged expects correct row heights
2248                     above passed row in the document. Cannot use array iterator
2249                     because array changes in every cycle. */
2250                 if( pDrawLayer )
2251                 {
2252                     for( SCROW nRow = nStartRow; nRow <= nEndRow ; ++nRow )
2253                     {
2254                         pDrawLayer->HeightChanged( nTab, nRow,
2255                              static_cast<long>(nNewHeight) - static_cast<long>(mpRowHeights->getValue(nRow)));
2256                         mpRowHeights->setValue(nRow, nRow, nNewHeight);
2257                     }
2258                 }
2259                 else
2260                     mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
2261             }
2262 			else
2263 			{
2264 				SCROW nMid = (nStartRow+nEndRow) / 2;
2265 				if (SetRowHeightRange( nStartRow, nMid, nNewHeight, 1.0, 1.0 ))
2266 					bChanged = sal_True;
2267 				if (SetRowHeightRange( nMid+1, nEndRow, nNewHeight, 1.0, 1.0 ))
2268 					bChanged = sal_True;
2269 			}
2270 		}
2271 		else
2272 		{
2273 			if (pDrawLayer)
2274 			{
2275                 // #i115025# When comparing to nNewHeight for the whole range, the height
2276                 // including hidden rows has to be used (same behavior as 3.2).
2277                 unsigned long nOldHeights = mpRowHeights->getSumValue(nStartRow, nEndRow);
2278                 // FIXME: should we test for overflows?
2279 				long nHeightDif = (long) (unsigned long) nNewHeight *
2280                     (nEndRow - nStartRow + 1) - nOldHeights;
2281 				pDrawLayer->HeightChanged( nTab, nEndRow, nHeightDif );
2282 			}
2283 
2284             if (!bChanged)
2285                 bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
2286 
2287             mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
2288 		}
2289 		DecRecalcLevel();
2290 
2291         if (bChanged)
2292             InvalidatePageBreaks();
2293 	}
2294 	else
2295 	{
2296 		DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
2297 	}
2298 
2299 	return bChanged;
2300 }
2301 
2302 void ScTable::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nNewHeight )
2303 {
2304     if (!ValidRow(nStartRow) || !ValidRow(nEndRow) || !mpRowHeights)
2305         return;
2306 
2307     if (!nNewHeight)
2308         nNewHeight = ScGlobal::nStdRowHeight;
2309 
2310     mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
2311 }
2312 
2313 void ScTable::SetManualHeight( SCROW nStartRow, SCROW nEndRow, sal_Bool bManual )
2314 {
2315 	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags)
2316 	{
2317 		if (bManual)
2318             pRowFlags->OrValue( nStartRow, nEndRow, CR_MANUALSIZE);
2319 		else
2320             pRowFlags->AndValue( nStartRow, nEndRow, sal::static_int_cast<sal_uInt8>(~CR_MANUALSIZE));
2321 	}
2322 	else
2323 	{
2324 		DBG_ERROR("Falsche Zeilennummer oder keine Zeilenflags");
2325 	}
2326 }
2327 
2328 
2329 sal_uInt16 ScTable::GetColWidth( SCCOL nCol ) const
2330 {
2331 	DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
2332 
2333 	if (VALIDCOL(nCol) && pColFlags && pColWidth)
2334 	{
2335         if (ColHidden(nCol))
2336 			return 0;
2337 		else
2338 			return pColWidth[nCol];
2339 	}
2340 	else
2341 		return (sal_uInt16) STD_COL_WIDTH;
2342 }
2343 
2344 
2345 sal_uInt16 ScTable::GetOriginalWidth( SCCOL nCol ) const		// immer die eingestellte
2346 {
2347 	DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
2348 
2349 	if (VALIDCOL(nCol) && pColWidth)
2350 		return pColWidth[nCol];
2351 	else
2352 		return (sal_uInt16) STD_COL_WIDTH;
2353 }
2354 
2355 
2356 sal_uInt16 ScTable::GetCommonWidth( SCCOL nEndCol )
2357 {
2358 	//	get the width that is used in the largest continuous column range (up to nEndCol)
2359 
2360 	if ( !ValidCol(nEndCol) )
2361 	{
2362 		DBG_ERROR("wrong column");
2363 		nEndCol = MAXCOL;
2364 	}
2365 
2366 	sal_uInt16 nMaxWidth = 0;
2367 	sal_uInt16 nMaxCount = 0;
2368 	SCCOL nRangeStart = 0;
2369 	while ( nRangeStart <= nEndCol )
2370 	{
2371 		//	skip hidden columns
2372 		while ( nRangeStart <= nEndCol && ColHidden(nRangeStart) )
2373 			++nRangeStart;
2374 		if ( nRangeStart <= nEndCol )
2375 		{
2376 			sal_uInt16 nThisCount = 0;
2377 			sal_uInt16 nThisWidth = pColWidth[nRangeStart];
2378 			SCCOL nRangeEnd = nRangeStart;
2379 			while ( nRangeEnd <= nEndCol && pColWidth[nRangeEnd] == nThisWidth )
2380 			{
2381 				++nThisCount;
2382 				++nRangeEnd;
2383 
2384 				//	skip hidden columns
2385 				while ( nRangeEnd <= nEndCol && ColHidden(nRangeEnd) )
2386 					++nRangeEnd;
2387 			}
2388 
2389 			if ( nThisCount > nMaxCount )
2390 			{
2391 				nMaxCount = nThisCount;
2392 				nMaxWidth = nThisWidth;
2393 			}
2394 
2395 			nRangeStart = nRangeEnd;		// next range
2396 		}
2397 	}
2398 
2399 	return nMaxWidth;
2400 }
2401 
2402 
2403 sal_uInt16 ScTable::GetRowHeight( SCROW nRow, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
2404 {
2405     DBG_ASSERT(VALIDROW(nRow),"Invalid row number");
2406 
2407     if (VALIDROW(nRow) && mpRowHeights)
2408     {
2409         if (bHiddenAsZero && RowHidden( nRow, pStartRow, pEndRow))
2410             return 0;
2411         else
2412         {
2413             ScFlatUInt16RowSegments::RangeData aData;
2414             if (!mpRowHeights->getRangeData(nRow, aData))
2415             {
2416                 if (pStartRow)
2417                     *pStartRow = nRow;
2418                 if (pEndRow)
2419                     *pEndRow = nRow;
2420                 // TODO: What should we return in case the search fails?
2421                 return 0;
2422             }
2423 
2424             // If bHiddenAsZero, pStartRow and pEndRow were initialized to
2425             // boundaries of a non-hidden segment. Assume that the previous and
2426             // next segment are hidden then and limit the current height
2427             // segment.
2428             if (pStartRow)
2429                 *pStartRow = (bHiddenAsZero ? std::max( *pStartRow, aData.mnRow1) : aData.mnRow1);
2430             if (pEndRow)
2431                 *pEndRow = (bHiddenAsZero ? std::min( *pEndRow, aData.mnRow2) : aData.mnRow2);
2432             return aData.mnValue;
2433         }
2434     }
2435     else
2436     {
2437         if (pStartRow)
2438             *pStartRow = nRow;
2439         if (pEndRow)
2440             *pEndRow = nRow;
2441         return (sal_uInt16) ScGlobal::nStdRowHeight;
2442     }
2443 }
2444 
2445 
2446 sal_uLong ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow ) const
2447 {
2448 	DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
2449 
2450 	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
2451 	{
2452         sal_uLong nHeight = 0;
2453         SCROW nRow = nStartRow;
2454         while (nRow <= nEndRow)
2455         {
2456             SCROW nLastRow = -1;
2457             if (!RowHidden(nRow, nLastRow))
2458             {
2459                 if (nLastRow > nEndRow)
2460                     nLastRow = nEndRow;
2461                 nHeight += mpRowHeights->getSumValue(nRow, nLastRow);
2462             }
2463             nRow = nLastRow + 1;
2464         }
2465         return nHeight;
2466 	}
2467 	else
2468 		return (sal_uLong) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight);
2469 }
2470 
2471 
2472 sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale ) const
2473 {
2474 	DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
2475 
2476 	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
2477 	{
2478         sal_uLong nHeight = 0;
2479         SCROW nRow = nStartRow;
2480         while (nRow <= nEndRow)
2481         {
2482             SCROW nLastRow = -1;
2483             if (!RowHidden(nRow, nLastRow))
2484             {
2485                 if (nLastRow > nEndRow)
2486                     nLastRow = nEndRow;
2487 
2488                 // #i117315# can't use getSumValue, because individual values must be rounded
2489                 while (nRow <= nLastRow)
2490                 {
2491                     ScFlatUInt16RowSegments::RangeData aData;
2492                     if (!mpRowHeights->getRangeData(nRow, aData))
2493                         return nHeight;   // shouldn't happen
2494 
2495                     SCROW nSegmentEnd = std::min( nLastRow, aData.mnRow2 );
2496 
2497                     // round-down a single height value, multiply resulting (pixel) values
2498                     sal_uLong nOneHeight = static_cast<sal_uLong>( aData.mnValue * fScale );
2499                     nHeight += nOneHeight * ( nSegmentEnd + 1 - nRow );
2500 
2501                     nRow = nSegmentEnd + 1;
2502                 }
2503             }
2504             nRow = nLastRow + 1;
2505         }
2506         return nHeight;
2507 	}
2508 	else
2509 		return (sal_uLong) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight * fScale);
2510 }
2511 
2512 
2513 sal_uInt16 ScTable::GetOriginalHeight( SCROW nRow ) const		// non-0 even if hidden
2514 {
2515 	DBG_ASSERT(VALIDROW(nRow),"wrong row number");
2516 
2517     if (VALIDROW(nRow) && mpRowHeights)
2518         return mpRowHeights->getValue(nRow);
2519 	else
2520 		return (sal_uInt16) ScGlobal::nStdRowHeight;
2521 }
2522 
2523 
2524 //	Spalten-/Zeilen-Flags
2525 
2526 
2527 SCROW ScTable::GetHiddenRowCount( SCROW nRow )
2528 {
2529     if (!ValidRow(nRow))
2530         return 0;
2531 
2532     SCROW nLastRow = -1;
2533     if (!RowHidden(nRow, nLastRow) || !ValidRow(nLastRow))
2534         return 0;
2535 
2536     return nLastRow - nRow + 1;
2537 }
2538 
2539 
2540 //!		ShowRows / DBShowRows zusammenfassen
2541 
2542 void ScTable::ShowCol(SCCOL nCol, bool bShow)
2543 {
2544 	if (VALIDCOL(nCol))
2545 	{
2546         bool bWasVis = !ColHidden(nCol);
2547 		if (bWasVis != bShow)
2548 		{
2549 			IncRecalcLevel();
2550             InitializeNoteCaptions();
2551 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2552 			if (pDrawLayer)
2553 			{
2554 				if (bShow)
2555 					pDrawLayer->WidthChanged( nTab, nCol, (long) pColWidth[nCol] );
2556 				else
2557 					pDrawLayer->WidthChanged( nTab, nCol, -(long) pColWidth[nCol] );
2558 			}
2559 
2560             SetColHidden(nCol, nCol, !bShow);
2561 	    DecRecalcLevel();
2562 
2563 			ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
2564 			if ( pCharts )
2565 				pCharts->SetRangeDirty(ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ));
2566 		}
2567 	}
2568 	else
2569 	{
2570 		DBG_ERROR("Falsche Spaltennummer oder keine Flags");
2571 	}
2572 }
2573 
2574 
2575 void ScTable::ShowRow(SCROW nRow, bool bShow)
2576 {
2577 	if (VALIDROW(nRow) && pRowFlags)
2578 	{
2579         bool bWasVis = !RowHidden(nRow);
2580 		if (bWasVis != bShow)
2581 		{
2582 			IncRecalcLevel();
2583             InitializeNoteCaptions();
2584 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2585 			if (pDrawLayer)
2586 			{
2587 				if (bShow)
2588                     pDrawLayer->HeightChanged(
2589                         nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
2590 				else
2591                     pDrawLayer->HeightChanged(
2592                         nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
2593 			}
2594 
2595             SetRowHidden(nRow, nRow, !bShow);
2596 			if (bShow)
2597                 SetRowFiltered(nRow, nRow, false);
2598 		DecRecalcLevel();
2599 
2600 			ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
2601 			if ( pCharts )
2602 				pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
2603 
2604             InvalidatePageBreaks();
2605 		}
2606 	}
2607 	else
2608 	{
2609 		DBG_ERROR("Falsche Zeilennummer oder keine Flags");
2610 	}
2611 }
2612 
2613 
2614 void ScTable::DBShowRow(SCROW nRow, bool bShow)
2615 {
2616 	if (VALIDROW(nRow) && pRowFlags)
2617 	{
2618         bool bWasVis = !RowHidden(nRow);
2619 		IncRecalcLevel();
2620         InitializeNoteCaptions();
2621 		if (bWasVis != bShow)
2622 		{
2623 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2624 			if (pDrawLayer)
2625 			{
2626 				if (bShow)
2627                     pDrawLayer->HeightChanged(
2628                         nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
2629 				else
2630                     pDrawLayer->HeightChanged(
2631                         nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
2632 			}
2633 		}
2634 
2635 		//	Filter-Flag immer setzen, auch wenn Hidden unveraendert
2636         SetRowHidden(nRow, nRow, !bShow);
2637         SetRowFiltered(nRow, nRow, !bShow);
2638 	DecRecalcLevel();
2639 
2640 		if (bWasVis != bShow)
2641 		{
2642 			ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
2643 			if ( pCharts )
2644 				pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
2645 
2646 			if (pOutlineTable)
2647 				UpdateOutlineRow( nRow, nRow, bShow );
2648 
2649             InvalidatePageBreaks();
2650 		}
2651 	}
2652 	else
2653 	{
2654 		DBG_ERROR("Falsche Zeilennummer oder keine Flags");
2655 	}
2656 }
2657 
2658 
2659 void ScTable::DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow, bool bSetFlags)
2660 {
2661     // #i116164# IncRecalcLevel/DecRecalcLevel is in ScTable::Query
2662 	SCROW nStartRow = nRow1;
2663     InitializeNoteCaptions();
2664 	while (nStartRow <= nRow2)
2665 	{
2666         SCROW nEndRow = -1;
2667         bool bWasVis = !RowHidden(nStartRow, nEndRow);
2668         if (nEndRow > nRow2)
2669             nEndRow = nRow2;
2670 
2671 		sal_Bool bChanged = ( bWasVis != bShow );
2672 		if ( bChanged && bSetFlags )
2673 		{
2674 			ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2675 			if (pDrawLayer)
2676 			{
2677                 long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
2678 				if (bShow)
2679 					pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
2680 				else
2681 					pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
2682 			}
2683 		}
2684 
2685         // #i116164# Directly modify the flags only if there are drawing objects within the area.
2686         // Otherwise, all modifications are made together in ScTable::Query, so the tree isn't constantly rebuilt.
2687         if ( bSetFlags )
2688         {
2689             SetRowHidden(nStartRow, nEndRow, !bShow);
2690             SetRowFiltered(nStartRow, nEndRow, !bShow);
2691         }
2692 
2693 		if ( bChanged )
2694 		{
2695 			ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
2696 			if ( pCharts )
2697 				pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab ));
2698 		}
2699 
2700 		nStartRow = nEndRow + 1;
2701 	}
2702 
2703 	//	#i12341# For Show/Hide rows, the outlines are updated separately from the outside.
2704 	//	For filtering, the changes aren't visible to the caller, so UpdateOutlineRow has
2705 	//	to be done here.
2706 	if (pOutlineTable)
2707 		UpdateOutlineRow( nRow1, nRow2, bShow );
2708 }
2709 
2710 
2711 void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
2712 {
2713 	SCROW nStartRow = nRow1;
2714 	IncRecalcLevel();
2715     InitializeNoteCaptions();
2716 
2717     // #i116164# if there are no drawing objects within the row range, a single HeightChanged call is enough
2718     ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
2719     bool bHasObjects = pDrawLayer && pDrawLayer->HasObjectsInRows( nTab, nRow1, nRow2, false );
2720     long nOldHeight = 0;
2721     if ( pDrawLayer && !bHasObjects )
2722         nOldHeight = static_cast<long>(GetRowHeight(nRow1, nRow2));
2723 
2724 	while (nStartRow <= nRow2)
2725 	{
2726         SCROW nEndRow = -1;
2727         bool bWasVis = !RowHidden(nStartRow, nEndRow);
2728         if (nEndRow > nRow2)
2729             nEndRow = nRow2;
2730 
2731 		sal_Bool bChanged = ( bWasVis != bShow );
2732         if ( bChanged && bHasObjects )
2733 		{
2734 			if (pDrawLayer)
2735 			{
2736                 long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
2737 				if (bShow)
2738 					pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
2739 				else
2740 					pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
2741 			}
2742 		}
2743 
2744         // #i116164# Directly modify the flags only if there are drawing objects within the area.
2745         // Otherwise, all rows are modified together after the loop, so the tree isn't constantly rebuilt.
2746         if ( bHasObjects )
2747         {
2748             SetRowHidden(nStartRow, nEndRow, !bShow);
2749             if (bShow)
2750                 SetRowFiltered(nStartRow, nEndRow, false);
2751         }
2752 
2753 		if ( bChanged )
2754 		{
2755 			ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
2756 			if ( pCharts )
2757 				pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab ));
2758 
2759             InvalidatePageBreaks();
2760 		}
2761 
2762 		nStartRow = nEndRow + 1;
2763 	}
2764 
2765     if ( !bHasObjects )
2766     {
2767         // #i116164# set the flags for the whole range at once
2768         SetRowHidden(nRow1, nRow2, !bShow);
2769         if (bShow)
2770             SetRowFiltered(nRow1, nRow2, false);
2771 
2772         if ( pDrawLayer )
2773         {
2774             // if there are no objects in the range, a single HeightChanged call is enough
2775             long nNewHeight = 0;
2776             if ( bShow )
2777                 nNewHeight = static_cast<long>(GetRowHeight(nRow1, nRow2));
2778             if ( nNewHeight != nOldHeight )
2779                 pDrawLayer->HeightChanged( nTab, nRow1, nNewHeight - nOldHeight );
2780         }
2781     }
2782 
2783 	DecRecalcLevel();
2784 }
2785 
2786 sal_Bool ScTable::IsDataFiltered() const
2787 {
2788 	sal_Bool bAnyQuery = sal_False;
2789 	ScDBData* pDBData = pDocument->GetFilterDBAtTable(nTab);
2790 	if ( pDBData )
2791 	{
2792 		ScQueryParam aParam;
2793 		pDBData->GetQueryParam( aParam );
2794 		if ( aParam.GetEntry(0).bDoQuery )
2795 			bAnyQuery = sal_True;
2796 	}
2797 	return bAnyQuery;
2798 }
2799 
2800 void ScTable::SetColFlags( SCCOL nCol, sal_uInt8 nNewFlags )
2801 {
2802 	if (VALIDCOL(nCol) && pColFlags)
2803 		pColFlags[nCol] = nNewFlags;
2804 	else
2805 	{
2806 		DBG_ERROR("Falsche Spaltennummer oder keine Flags");
2807 	}
2808 }
2809 
2810 
2811 void ScTable::SetRowFlags( SCROW nRow, sal_uInt8 nNewFlags )
2812 {
2813 	if (VALIDROW(nRow) && pRowFlags)
2814 		pRowFlags->SetValue( nRow, nNewFlags);
2815 	else
2816 	{
2817 		DBG_ERROR("Falsche Zeilennummer oder keine Flags");
2818 	}
2819 }
2820 
2821 
2822 void ScTable::SetRowFlags( SCROW nStartRow, SCROW nEndRow, sal_uInt8 nNewFlags )
2823 {
2824 	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags)
2825 		pRowFlags->SetValue( nStartRow, nEndRow, nNewFlags);
2826 	else
2827 	{
2828 		DBG_ERROR("Falsche Zeilennummer(n) oder keine Flags");
2829 	}
2830 }
2831 
2832 
2833 sal_uInt8 ScTable::GetColFlags( SCCOL nCol ) const
2834 {
2835 	if (VALIDCOL(nCol) && pColFlags)
2836 		return pColFlags[nCol];
2837 	else
2838 		return 0;
2839 }
2840 
2841 
2842 sal_uInt8 ScTable::GetRowFlags( SCROW nRow ) const
2843 {
2844 	if (VALIDROW(nRow) && pRowFlags)
2845 		return pRowFlags->GetValue(nRow);
2846 	else
2847 		return 0;
2848 }
2849 
2850 
2851 SCROW ScTable::GetLastFlaggedRow() const
2852 {
2853     SCROW nLastFound = 0;
2854     if (pRowFlags)
2855     {
2856         SCROW nRow = pRowFlags->GetLastAnyBitAccess( 0, sal::static_int_cast<sal_uInt8>(CR_ALL) );
2857         if (ValidRow(nRow))
2858             nLastFound = nRow;
2859     }
2860 
2861     if (!maRowManualBreaks.empty())
2862         nLastFound = ::std::max(nLastFound, *maRowManualBreaks.rbegin());
2863 
2864     if (mpHiddenRows)
2865     {
2866         SCROW nRow = mpHiddenRows->findLastNotOf(false);
2867         if (ValidRow(nRow))
2868             nLastFound = ::std::max(nLastFound, nRow);
2869     }
2870 
2871     if (mpFilteredRows)
2872     {
2873         SCROW nRow = mpFilteredRows->findLastNotOf(false);
2874         if (ValidRow(nRow))
2875             nLastFound = ::std::max(nLastFound, nRow);
2876     }
2877 
2878     return nLastFound;
2879 }
2880 
2881 
2882 SCCOL ScTable::GetLastChangedCol() const
2883 {
2884 	if ( !pColFlags )
2885 		return 0;
2886 
2887 	SCCOL nLastFound = 0;
2888 	for (SCCOL nCol = 1; nCol <= MAXCOL; nCol++)
2889         if ((pColFlags[nCol] & CR_ALL) || (pColWidth[nCol] != STD_COL_WIDTH))
2890 			nLastFound = nCol;
2891 
2892 	return nLastFound;
2893 }
2894 
2895 
2896 SCROW ScTable::GetLastChangedRow() const
2897 {
2898 	if ( !pRowFlags )
2899 		return 0;
2900 
2901     SCROW nLastFlags = GetLastFlaggedRow();
2902 
2903     // Find the last row position where the height is NOT the standard row
2904     // height.
2905     // KOHEI: Test this to make sure it does what it's supposed to.
2906     SCROW nLastHeight = mpRowHeights->findLastNotOf(ScGlobal::nStdRowHeight);
2907     if (!ValidRow(nLastHeight))
2908         nLastHeight = 0;
2909 
2910 	return std::max( nLastFlags, nLastHeight);
2911 }
2912 
2913 
2914 sal_Bool ScTable::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, sal_Bool bShow )
2915 {
2916 	if (pOutlineTable && pColFlags)
2917     {
2918         ScBitMaskCompressedArray< SCCOLROW, sal_uInt8> aArray( MAXCOL, pColFlags, MAXCOLCOUNT);
2919 		return pOutlineTable->GetColArray()->ManualAction( nStartCol, nEndCol, bShow, *this, true );
2920     }
2921 	else
2922 		return sal_False;
2923 }
2924 
2925 
2926 sal_Bool ScTable::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, sal_Bool bShow )
2927 {
2928 	if (pOutlineTable && pRowFlags)
2929 		return pOutlineTable->GetRowArray()->ManualAction( nStartRow, nEndRow, bShow, *this, false );
2930 	else
2931 		return sal_False;
2932 }
2933 
2934 
2935 void ScTable::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
2936 {
2937     // Column-wise expansion
2938 
2939     while (rX1 > 0 && ColHidden(rX1-1))
2940         --rX1;
2941 
2942     while (rX2 < MAXCOL && ColHidden(rX2+1))
2943         ++rX2;
2944 
2945     // Row-wise expansion
2946 
2947     if (rY1 > 0)
2948 	{
2949         ScFlatBoolRowSegments::RangeData aData;
2950         if (mpHiddenRows->getRangeData(rY1-1, aData) && aData.mbValue)
2951         {
2952             SCROW nStartRow = aData.mnRow1;
2953             if (ValidRow(nStartRow))
2954                 rY1 = nStartRow;
2955         }
2956     }
2957     if (rY2 < MAXROW)
2958     {
2959         SCROW nEndRow = -1;
2960         if (RowHidden(rY2+1, nEndRow) && ValidRow(nEndRow))
2961             rY2 = nEndRow;
2962 	}
2963 }
2964 
2965 
2966 void ScTable::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
2967 {
2968     while ( rX2>rX1 && ColHidden(rX2) )
2969         --rX2;
2970     while ( rX2>rX1 && ColHidden(rX1) )
2971         ++rX1;
2972 
2973     if (rY1 < rY2)
2974 	{
2975         ScFlatBoolRowSegments::RangeData aData;
2976         if (mpHiddenRows->getRangeData(rY2, aData) && aData.mbValue)
2977         {
2978             SCROW nStartRow = aData.mnRow1;
2979             if (ValidRow(nStartRow) && nStartRow >= rY1)
2980                 rY2 = nStartRow;
2981         }
2982     }
2983 
2984     if (rY1 < rY2)
2985     {
2986         SCROW nEndRow = -1;
2987         if (RowHidden(rY1, nEndRow) && ValidRow(nEndRow) && nEndRow <= rY2)
2988             rY1 = nEndRow;
2989 	}
2990 }
2991 
2992 
2993 //	Auto-Outline
2994 
2995 template< typename T >
2996 short DiffSign( T a, T b )
2997 {
2998 	return (a<b) ? -1 :
2999 			(a>b) ? 1 : 0;
3000 }
3001 
3002 
3003 void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
3004 {
3005 	sal_Bool bSizeChanged = sal_False;
3006 	sal_Bool bMissed	  = sal_False;
3007 
3008 	SCCOL nCol;
3009 	SCROW nRow;
3010 	SCROW i;
3011 	sal_Bool bFound;
3012 	ScOutlineArray* pArray;
3013 	ScBaseCell* pCell;
3014 	ScRange aRef;
3015 /*	ScPatternAttr aBoldPattern( pDocument->GetPool() );				//!	spezielle Format-Vorlage
3016 	aBoldPattern.GetItemSet().Put( SvxWeightItem( WEIGHT_BOLD ) );
3017 */
3018 
3019 	StartOutlineTable();
3020 
3021 							// Zeilen
3022 
3023 	SCROW	nCount = nEndRow-nStartRow+1;
3024 	sal_Bool*	pUsed = new sal_Bool[nCount];
3025 	for (i=0; i<nCount; i++)
3026 		pUsed[i] = sal_False;
3027 	for (nCol=nStartCol; nCol<=nEndCol; nCol++)
3028 		if (!aCol[nCol].IsEmptyData())
3029 			aCol[nCol].FindUsed( nStartRow, nEndRow, pUsed );
3030 
3031 	pArray = pOutlineTable->GetRowArray();
3032 	for (nRow=nStartRow; nRow<=nEndRow; nRow++)
3033 		if (pUsed[nRow-nStartRow])
3034 		{
3035 			bFound = sal_False;
3036 			for (nCol=nStartCol; nCol<=nEndCol && !bFound; nCol++)
3037 				if (!aCol[nCol].IsEmptyData())
3038 				{
3039 					pCell = aCol[nCol].GetCell( nRow );
3040 					if (pCell)
3041 						if ( pCell->GetCellType() == CELLTYPE_FORMULA )
3042 							if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef ))
3043 								if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
3044 									 aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
3045 									 DiffSign( aRef.aStart.Row(), nRow ) ==
3046 										DiffSign( aRef.aEnd.Row(), nRow ) )
3047 								{
3048 									if (pArray->Insert( aRef.aStart.Row(), aRef.aEnd.Row(), bSizeChanged ))
3049 									{
3050 //										ApplyPatternArea( nStartCol, nRow, nEndCol, nRow, aBoldPattern );
3051 										bFound = sal_True;
3052 									}
3053 									else
3054 										bMissed = sal_True;
3055 								}
3056 				}
3057 		}
3058 
3059 	delete[] pUsed;
3060 
3061 							// Spalten
3062 
3063 	pArray = pOutlineTable->GetColArray();
3064 	for (nCol=nStartCol; nCol<=nEndCol; nCol++)
3065 	{
3066 		if (!aCol[nCol].IsEmptyData())
3067 		{
3068 			bFound = sal_False;
3069 			ScColumnIterator aIter( &aCol[nCol], nStartRow, nEndRow );
3070 			while ( aIter.Next( nRow, pCell ) && !bFound )
3071 			{
3072 				if ( pCell->GetCellType() == CELLTYPE_FORMULA )
3073 					if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef ))
3074 						if ( aRef.aStart.Row() == nRow && aRef.aEnd.Row() == nRow &&
3075 							 aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
3076 							 DiffSign( aRef.aStart.Col(), nCol ) ==
3077 								DiffSign( aRef.aEnd.Col(), nCol ) )
3078 						{
3079 							if (pArray->Insert( aRef.aStart.Col(), aRef.aEnd.Col(), bSizeChanged ))
3080 							{
3081 //								ApplyPatternArea( nCol, nStartRow, nCol, nEndRow, aBoldPattern );
3082 								bFound = sal_True;
3083 							}
3084 							else
3085 								bMissed = sal_True;
3086 						}
3087 			}
3088 		}
3089 	}
3090 }
3091 
3092 									//	CopyData - fuer Query in anderen Bereich
3093 
3094 void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
3095 							SCCOL nDestCol, SCROW nDestRow, SCTAB nDestTab )
3096 {
3097 	//!		wenn fuer mehrere Zeilen benutzt, nach Spalten optimieren!
3098 
3099 	ScAddress aSrc( nStartCol, nStartRow, nTab );
3100 	ScAddress aDest( nDestCol, nDestRow, nDestTab );
3101 	ScRange aRange( aSrc, aDest );
3102 	sal_Bool bThisTab = ( nDestTab == nTab );
3103 	SCROW nDestY = nDestRow;
3104 	for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
3105 	{
3106 		aSrc.SetRow( nRow );
3107 		aDest.SetRow( nDestY );
3108 		SCCOL nDestX = nDestCol;
3109 		for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
3110 		{
3111 			aSrc.SetCol( nCol );
3112 			aDest.SetCol( nDestX );
3113 			ScBaseCell* pCell = GetCell( nCol, nRow );
3114 			if (pCell)
3115 			{
3116                 pCell = pCell->CloneWithoutNote( *pDocument );
3117 				if (pCell->GetCellType() == CELLTYPE_FORMULA)
3118 				{
3119 					((ScFormulaCell*)pCell)->UpdateReference( URM_COPY, aRange,
3120 									((SCsCOL) nDestCol) - ((SCsCOL) nStartCol),
3121 									((SCsROW) nDestRow) - ((SCsROW) nStartRow),
3122 									((SCsTAB) nDestTab) - ((SCsTAB) nTab) );
3123 					((ScFormulaCell*)pCell)->aPos = aDest;
3124 				}
3125 			}
3126 			if (bThisTab)
3127 			{
3128 				PutCell( nDestX, nDestY, pCell );
3129 				SetPattern( nDestX, nDestY, *GetPattern( nCol, nRow ), sal_True );
3130 			}
3131 			else
3132 			{
3133 				pDocument->PutCell( aDest, pCell );
3134 				pDocument->SetPattern( aDest, *GetPattern( nCol, nRow ), sal_True );
3135 			}
3136 
3137 			++nDestX;
3138 		}
3139 		++nDestY;
3140 	}
3141 }
3142 
3143 
3144 sal_Bool ScTable::RefVisible(ScFormulaCell* pCell)
3145 {
3146 	ScRange aRef;
3147 
3148 	if (pCell->HasOneReference(aRef))
3149 	{
3150 		if (aRef.aStart.Col()==aRef.aEnd.Col() && aRef.aStart.Tab()==aRef.aEnd.Tab())
3151 		{
3152             SCROW nEndRow;
3153             if (!RowFiltered(aRef.aStart.Row(), NULL, &nEndRow))
3154                 // row not filtered.
3155                 nEndRow = ::std::numeric_limits<SCROW>::max();
3156 
3157             if (!ValidRow(nEndRow) || nEndRow < aRef.aEnd.Row())
3158                 return sal_True;    // at least partly visible
3159             return sal_False;       // completely invisible
3160 		}
3161 	}
3162 
3163 	return sal_True;						// irgendwie anders
3164 }
3165 
3166 
3167 void ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow, String& rStr)
3168 {
3169 	GetInputString(nCol, nRow, rStr);
3170 	rStr.EraseTrailingChars();
3171 	rStr.EraseLeadingChars();
3172 	ScGlobal::pCharClass->toUpper(rStr);
3173 }
3174 
3175 
3176 // Berechnen der Groesse der Tabelle und setzen der Groesse an der DrawPage
3177 
3178 void ScTable::SetDrawPageSize(bool bResetStreamValid, bool bUpdateNoteCaptionPos)
3179 {
3180 	ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
3181 	if( pDrawLayer )
3182 	{
3183         double fValX = GetColOffset( MAXCOL + 1 ) * HMM_PER_TWIPS;
3184         double fValY = GetRowOffset( MAXROW + 1 ) * HMM_PER_TWIPS;
3185         const long nMax = ::std::numeric_limits<long>::max();
3186         // #i113884# Avoid int32 overflow with possible negative results than can cause bad effects.
3187         // If the draw page size is smaller than all rows, only the bottom of the sheet is affected.
3188         long x = ( fValX > (double)nMax ) ? nMax : (long) fValX;
3189         long y = ( fValY > (double)nMax ) ? nMax : (long) fValY;
3190 
3191 		if ( IsLayoutRTL() )		// IsNegativePage
3192 			x = -x;
3193 
3194 		pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( x, y ), bUpdateNoteCaptionPos );
3195 	}
3196 
3197     // #i102616# actions that modify the draw page size count as sheet modification
3198     // (exception: InitDrawLayer)
3199     if (bResetStreamValid && IsStreamValid())
3200         SetStreamValid(sal_False);
3201 }
3202 
3203 
3204 sal_uLong ScTable::GetRowOffset( SCROW nRow ) const
3205 {
3206 	sal_uLong n = 0;
3207     if ( mpHiddenRows && mpRowHeights )
3208 	{
3209         if (nRow == 0)
3210             return 0;
3211         else if (nRow == 1)
3212             return GetRowHeight(0);
3213 
3214         n = GetTotalRowHeight(0, nRow-1);
3215 #ifdef DBG_UTIL
3216         if (n == ::std::numeric_limits<unsigned long>::max())
3217             DBG_ERRORFILE("ScTable::GetRowOffset: row heights overflow");
3218 #endif
3219 	}
3220 	else
3221 	{
3222 		DBG_ERROR("GetRowOffset: Daten fehlen");
3223 	}
3224 	return n;
3225 }
3226 
3227 SCROW ScTable::GetRowForHeight(sal_uLong nHeight) const
3228 {
3229     sal_uInt32 nSum = 0;
3230 
3231     ScFlatBoolRowSegments::RangeData aData;
3232     for (SCROW nRow = 0; nRow <= MAXROW; ++nRow)
3233     {
3234         if (!mpHiddenRows->getRangeData(nRow, aData))
3235             break;
3236 
3237         if (aData.mbValue)
3238         {
3239             nRow = aData.mnRow2;
3240             continue;
3241         }
3242 
3243         sal_uInt32 nNew = mpRowHeights->getValue(nRow);
3244         nSum += nNew;
3245         if (nSum > nHeight)
3246         {
3247             return nRow < MAXROW ? nRow + 1 : MAXROW;
3248         }
3249     }
3250     return -1;
3251 }
3252 
3253 
3254 sal_uLong ScTable::GetColOffset( SCCOL nCol ) const
3255 {
3256 	sal_uLong n = 0;
3257 	if ( pColWidth )
3258 	{
3259 		SCCOL i;
3260 		for( i = 0; i < nCol; i++ )
3261             if (!ColHidden(i))
3262 				n += pColWidth[i];
3263 	}
3264 	else
3265 	{
3266 		DBG_ERROR("GetColumnOffset: Daten fehlen");
3267 	}
3268 	return n;
3269 }
3270 
3271