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