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