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