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