xref: /trunk/main/sc/source/core/data/column2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include "scitems.hxx"
36 #include <editeng/eeitem.hxx>
37 
38 #include <svx/algitem.hxx>
39 #include <editeng/editobj.hxx>
40 #include <editeng/editstat.hxx>
41 #include <editeng/emphitem.hxx>
42 #include <editeng/fhgtitem.hxx>
43 #include <editeng/forbiddencharacterstable.hxx>
44 #include <svx/rotmodit.hxx>
45 #include <editeng/scripttypeitem.hxx>
46 #include <editeng/unolingu.hxx>
47 #include <svl/zforlist.hxx>
48 #include <svl/broadcast.hxx>
49 #include <svl/listeneriter.hxx>
50 #include <vcl/outdev.hxx>
51 
52 #include "column.hxx"
53 #include "cell.hxx"
54 #include "document.hxx"
55 #include "docpool.hxx"
56 #include "attarray.hxx"
57 #include "patattr.hxx"
58 #include "cellform.hxx"
59 #include "collect.hxx"
60 #include "stlsheet.hxx"
61 #include "rechead.hxx"
62 #include "brdcst.hxx"
63 #include "editutil.hxx"
64 #include "subtotal.hxx"
65 #include "markdata.hxx"
66 #include "compiler.hxx"         // ScTokenArray GetCodeLen
67 #include "dbcolect.hxx"
68 #include "fillinfo.hxx"
69 #include "segmenttree.hxx"
70 
71 #include <math.h>
72 
73 // -----------------------------------------------------------------------
74 
75 // factor from font size to optimal cell height (text width)
76 #define SC_ROT_BREAK_FACTOR     6
77 
78 // -----------------------------------------------------------------------
79 
80 inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript )
81 {
82     //! move to a header file
83     return ( nScript != SCRIPTTYPE_LATIN &&
84              nScript != SCRIPTTYPE_ASIAN &&
85              nScript != SCRIPTTYPE_COMPLEX );
86 }
87 
88 // -----------------------------------------------------------------------------------------
89 
90 //
91 //  Datei-Operationen
92 //
93 
94 // -----------------------------------------------------------------------------------------
95 
96 //UNUSED2008-05  SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
97 //UNUSED2008-05  {
98 //UNUSED2008-05      SCROW nNoteCount = 0;
99 //UNUSED2008-05      SCSIZE i;
100 //UNUSED2008-05
101 //UNUSED2008-05      for (i=0; i<nCount; i++)
102 //UNUSED2008-05          if ( pItems[i].pCell->GetNotePtr() && pItems[i].nRow<=nMaxRow )
103 //UNUSED2008-05              ++nNoteCount;
104 //UNUSED2008-05
105 //UNUSED2008-05      return nNoteCount;
106 //UNUSED2008-05  }
107 
108 // -----------------------------------------------------------------------------------------
109 
110 //UNUSED2008-05  void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
111 //UNUSED2008-05  {
112 //UNUSED2008-05      //  #99139# find and correct string cells that are formatted with a symbol font,
113 //UNUSED2008-05      //  but are not in the LoadedSymbolStringCellsList
114 //UNUSED2008-05      //  (because CELLTYPE_SYMBOLS wasn't written in the file)
115 //UNUSED2008-05
116 //UNUSED2008-05      ScFontToSubsFontConverter_AutoPtr xFontConverter;
117 //UNUSED2008-05      const sal_uLong nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
118 //UNUSED2008-05
119 //UNUSED2008-05      sal_Bool bListInitialized = sal_False;
120 //UNUSED2008-05      ScSymbolStringCellEntry* pCurrentEntry = NULL;
121 //UNUSED2008-05
122 //UNUSED2008-05      ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
123 //UNUSED2008-05      SCROW nStt, nEnd;
124 //UNUSED2008-05      const ScPatternAttr* pAttr = aAttrIter.Next( nStt, nEnd );
125 //UNUSED2008-05      while ( pAttr )
126 //UNUSED2008-05      {
127 //UNUSED2008-05          if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
128 //UNUSED2008-05                  pAttr->IsSymbolFont() )
129 //UNUSED2008-05          {
130 //UNUSED2008-05              ScColumnIterator aCellIter( this, nStt, nEnd );
131 //UNUSED2008-05              SCROW nRow;
132 //UNUSED2008-05              ScBaseCell* pCell;
133 //UNUSED2008-05              while ( aCellIter.Next( nRow, pCell ) )
134 //UNUSED2008-05              {
135 //UNUSED2008-05                  if ( pCell->GetCellType() == CELLTYPE_STRING )
136 //UNUSED2008-05                  {
137 //UNUSED2008-05                      List& rList = pDocument->GetLoadedSymbolStringCellsList();
138 //UNUSED2008-05                      if (!bListInitialized)
139 //UNUSED2008-05                      {
140 //UNUSED2008-05                          pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
141 //UNUSED2008-05                          bListInitialized = sal_True;
142 //UNUSED2008-05                      }
143 //UNUSED2008-05
144 //UNUSED2008-05                      while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
145 //UNUSED2008-05                          pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
146 //UNUSED2008-05
147 //UNUSED2008-05                      if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
148 //UNUSED2008-05                      {
149 //UNUSED2008-05                          //  found
150 //UNUSED2008-05                      }
151 //UNUSED2008-05                      else
152 //UNUSED2008-05                      {
153 //UNUSED2008-05                          //  not in list -> convert and put into list
154 //UNUSED2008-05
155 //UNUSED2008-05                          ScStringCell* pStrCell = (ScStringCell*)pCell;
156 //UNUSED2008-05                          String aOldStr;
157 //UNUSED2008-05                          pStrCell->GetString( aOldStr );
158 //UNUSED2008-05
159 //UNUSED2008-05                          //  convert back to stream character set (get original data)
160 //UNUSED2008-05                          ByteString aByteStr( aOldStr, eStreamCharSet );
161 //UNUSED2008-05
162 //UNUSED2008-05                          //  convert using symbol encoding, as for CELLTYPE_SYMBOLS cells
163 //UNUSED2008-05                          String aNewStr( aByteStr, RTL_TEXTENCODING_SYMBOL );
164 //UNUSED2008-05                          pStrCell->SetString( aNewStr );
165 //UNUSED2008-05
166 //UNUSED2008-05                          ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
167 //UNUSED2008-05                          pEntry->pCell = pStrCell;
168 //UNUSED2008-05                          pEntry->nRow = nRow;
169 //UNUSED2008-05
170 //UNUSED2008-05                          if ( pCurrentEntry )
171 //UNUSED2008-05                              rList.Insert( pEntry );     // before current entry - pCurrentEntry stays valid
172 //UNUSED2008-05                          else
173 //UNUSED2008-05                              rList.Insert( pEntry, LIST_APPEND );    // append if already behind last entry
174 //UNUSED2008-05                      }
175 //UNUSED2008-05                  }
176 //UNUSED2008-05              }
177 //UNUSED2008-05          }
178 //UNUSED2008-05
179 //UNUSED2008-05          pAttr = aAttrIter.Next( nStt, nEnd );
180 //UNUSED2008-05      }
181 //UNUSED2008-05  }
182 
183 // -----------------------------------------------------------------------------------------
184 
185                                     //  GetNeededSize: optimale Hoehe / Breite in Pixeln
186 
187 long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev,
188                               double nPPTX, double nPPTY,
189                               const Fraction& rZoomX, const Fraction& rZoomY,
190                               sal_Bool bWidth, const ScNeededSizeOptions& rOptions )
191 {
192     long nValue=0;
193     SCSIZE nIndex;
194     double nPPT = bWidth ? nPPTX : nPPTY;
195     if (Search(nRow,nIndex))
196     {
197         ScBaseCell* pCell = pItems[nIndex].pCell;
198         const ScPatternAttr* pPattern = rOptions.pPattern;
199         if (!pPattern)
200             pPattern = pAttrArray->GetPattern( nRow );
201 
202         //      zusammengefasst?
203         //      Merge nicht in bedingter Formatierung
204 
205         const ScMergeAttr*      pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
206         const ScMergeFlagAttr*  pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
207 
208         if ( bWidth )
209         {
210             if ( pFlag->IsHorOverlapped() )
211                 return 0;
212             if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
213                 return 0;
214         }
215         else
216         {
217             if ( pFlag->IsVerOverlapped() )
218                 return 0;
219             if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
220                 return 0;
221         }
222 
223         //      bedingte Formatierung
224         const SfxItemSet* pCondSet = NULL;
225         if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
226             pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
227 
228         //  Zeilenumbruch?
229 
230         const SfxPoolItem* pCondItem;
231         SvxCellHorJustify eHorJust;
232         if (pCondSet &&
233                 pCondSet->GetItemState(ATTR_HOR_JUSTIFY, sal_True, &pCondItem) == SFX_ITEM_SET)
234             eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
235         else
236             eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
237                                             pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
238         bool bBreak;
239         if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
240             bBreak = true;
241         else if ( pCondSet &&
242                     pCondSet->GetItemState(ATTR_LINEBREAK, sal_True, &pCondItem) == SFX_ITEM_SET)
243             bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
244         else
245             bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
246 
247         SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
248         sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
249         // #i111387# #o11817313# disable automatic line breaks only for "General" number format
250         if ( bBreak && pCell->HasValueData() && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
251         {
252             // also take formula result type into account for number format
253             if ( pCell->GetCellType() != CELLTYPE_FORMULA ||
254                  ( static_cast<ScFormulaCell*>(pCell)->GetStandardFormat(*pFormatter, nFormat) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
255                 bBreak = false;
256         }
257 
258         //  get other attributes from pattern and conditional formatting
259 
260         SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
261         sal_Bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
262                 ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
263         if ( bAsianVertical )
264             bBreak = false;
265 
266         if ( bWidth && bBreak )     // after determining bAsianVertical (bBreak may be reset)
267             return 0;
268 
269         long nRotate = 0;
270         SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
271         if ( eOrient == SVX_ORIENTATION_STANDARD )
272         {
273             if (pCondSet &&
274                     pCondSet->GetItemState(ATTR_ROTATE_VALUE, sal_True, &pCondItem) == SFX_ITEM_SET)
275                 nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
276             else
277                 nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
278             if ( nRotate )
279             {
280                 if (pCondSet &&
281                         pCondSet->GetItemState(ATTR_ROTATE_MODE, sal_True, &pCondItem) == SFX_ITEM_SET)
282                     eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
283                 else
284                     eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
285                                                 pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
286 
287                 if ( nRotate == 18000 )
288                     eRotMode = SVX_ROTATE_MODE_STANDARD;    // keinen Ueberlauf
289             }
290         }
291 
292         if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
293         {
294             // ignore orientation/rotation if "repeat" is active
295             eOrient = SVX_ORIENTATION_STANDARD;
296             nRotate = 0;
297             bAsianVertical = sal_False;
298         }
299 
300         const SvxMarginItem* pMargin;
301         if (pCondSet &&
302                 pCondSet->GetItemState(ATTR_MARGIN, sal_True, &pCondItem) == SFX_ITEM_SET)
303             pMargin = (const SvxMarginItem*) pCondItem;
304         else
305             pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
306         sal_uInt16 nIndent = 0;
307         if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
308         {
309             if (pCondSet &&
310                     pCondSet->GetItemState(ATTR_INDENT, sal_True, &pCondItem) == SFX_ITEM_SET)
311                 nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
312             else
313                 nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
314         }
315 
316         sal_uInt8 nScript = pDocument->GetScriptType( nCol, nRow, nTab, pCell );
317         if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
318 
319         //  also call SetFont for edit cells, because bGetFont may be set only once
320         //  bGetFont is set also if script type changes
321         if (rOptions.bGetFont)
322         {
323             Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
324             Font aFont;
325             // font color doesn't matter here
326             pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
327             pDev->SetFont(aFont);
328         }
329 
330         sal_Bool bAddMargin = sal_True;
331         CellType eCellType = pCell->GetCellType();
332 
333         sal_Bool bEditEngine = ( eCellType == CELLTYPE_EDIT ||
334                                 eOrient == SVX_ORIENTATION_STACKED ||
335                                 IsAmbiguousScript( nScript ) ||
336                                 ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) );
337 
338         if (!bEditEngine)                                   // direkte Ausgabe
339         {
340             String aValStr;
341             Color* pColor;
342             ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
343                                         *pFormatter,
344                                         sal_True, rOptions.bFormula, ftCheck );
345             if (aValStr.Len())
346             {
347                 //  SetFont ist nach oben verschoben
348 
349                 Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
350                 if ( eOrient != SVX_ORIENTATION_STANDARD )
351                 {
352                     long nTemp = aSize.Width();
353                     aSize.Width() = aSize.Height();
354                     aSize.Height() = nTemp;
355                 }
356                 else if ( nRotate )
357                 {
358                     //! unterschiedliche Skalierung X/Y beruecksichtigen
359 
360                     double nRealOrient = nRotate * F_PI18000;   // nRotate sind 1/100 Grad
361                     double nCosAbs = fabs( cos( nRealOrient ) );
362                     double nSinAbs = fabs( sin( nRealOrient ) );
363                     long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
364                     long nWidth;
365                     if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
366                         nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
367                     else if ( rOptions.bTotalSize )
368                     {
369                         nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
370                         bAddMargin = sal_False;
371                         //  nur nach rechts:
372                         //! unterscheiden nach Ausrichtung oben/unten (nur Text/ganze Hoehe)
373                         if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
374                             nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
375                                                 nPPT * nCosAbs / nSinAbs );
376                     }
377                     else
378                         nWidth  = (long)( aSize.Height() / nSinAbs );   //! begrenzen?
379 
380                     if ( bBreak && !rOptions.bTotalSize )
381                     {
382                         //  #47744# limit size for line break
383                         long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
384                         if ( nHeight > nCmp )
385                             nHeight = nCmp;
386                     }
387 
388                     aSize = Size( nWidth, nHeight );
389                 }
390                 nValue = bWidth ? aSize.Width() : aSize.Height();
391 
392                 if ( bAddMargin )
393                 {
394                     if (bWidth)
395                     {
396                         nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
397                                   (long) ( pMargin->GetRightMargin() * nPPT );
398                         if ( nIndent )
399                             nValue += (long) ( nIndent * nPPT );
400                     }
401                     else
402                         nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
403                                   (long) ( pMargin->GetBottomMargin() * nPPT );
404                 }
405 
406                                                 //  Zeilenumbruch ausgefuehrt ?
407 
408                 if ( bBreak && !bWidth )
409                 {
410                     //  Test mit EditEngine zur Sicherheit schon bei 90%
411                     //  (wegen Rundungsfehlern und weil EditEngine teilweise anders formatiert)
412 
413                     long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
414                                         pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
415                                         nIndent )
416                                         * nPPT );
417                     nDocPixel = (nDocPixel * 9) / 10;           // zur Sicherheit
418                     if ( aSize.Width() > nDocPixel )
419                         bEditEngine = sal_True;
420                 }
421             }
422         }
423 
424         if (bEditEngine)
425         {
426             //  der Font wird bei !bEditEngine nicht jedesmal neu gesetzt
427             Font aOldFont = pDev->GetFont();
428 
429             MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
430 
431             // am Dokument speichern ?
432             ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
433 
434             pEngine->SetUpdateMode( sal_False );
435             sal_Bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
436             sal_uInt32 nCtrl = pEngine->GetControlWord();
437             if ( bTextWysiwyg )
438                 nCtrl |= EE_CNTRL_FORMAT100;
439             else
440                 nCtrl &= ~EE_CNTRL_FORMAT100;
441             pEngine->SetControlWord( nCtrl );
442             MapMode aOld = pDev->GetMapMode();
443             pDev->SetMapMode( aHMMMode );
444             pEngine->SetRefDevice( pDev );
445             pDocument->ApplyAsianEditSettings( *pEngine );
446             SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
447             pPattern->FillEditItemSet( pSet, pCondSet );
448 
449 //          no longer needed, are setted with the text (is faster)
450 //          pEngine->SetDefaults( pSet );
451 
452             if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
453 
454                 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
455                 pEngine->SetHyphenator( xXHyphenator );
456             }
457 
458             Size aPaper = Size( 1000000, 1000000 );
459             if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
460                 aPaper.Width() = 1;
461             else if (bBreak)
462             {
463                 double fWidthFactor = nPPTX;
464                 if ( bTextWysiwyg )
465                 {
466                     //  #95593# if text is formatted for printer, don't use PixelToLogic,
467                     //  to ensure the exact same paper width (and same line breaks) as in
468                     //  ScEditUtil::GetEditArea, used for output.
469 
470                     fWidthFactor = HMM_PER_TWIPS;
471                 }
472 
473                 // use original width for hidden columns:
474                 long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
475                 SCCOL nColMerge = pMerge->GetColMerge();
476                 if (nColMerge > 1)
477                     for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
478                         nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
479                 nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
480                            + (long) ( pMargin->GetRightMargin() * fWidthFactor )
481                            + 1;     // Ausgabebereich ist Breite-1 Pixel (wegen Gitterlinien)
482                 if ( nIndent )
483                     nDocWidth -= (long) ( nIndent * fWidthFactor );
484 
485                 // space for AutoFilter button:  20 * nZoom/100
486                 if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
487                     nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
488 
489                 aPaper.Width() = nDocWidth;
490 
491                 if ( !bTextWysiwyg )
492                     aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
493             }
494             pEngine->SetPaperSize(aPaper);
495 
496             if ( pCell->GetCellType() == CELLTYPE_EDIT )
497             {
498                 const EditTextObject* pData;
499                 ((ScEditCell*)pCell)->GetData(pData);
500                 pEngine->SetTextNewDefaults(*pData, pSet);
501             }
502             else
503             {
504                 Color* pColor;
505                 String aString;
506                 ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
507                                             *pFormatter,
508                                             sal_True, rOptions.bFormula, ftCheck );
509                 if (aString.Len())
510                     pEngine->SetTextNewDefaults(aString, pSet);
511                 else
512                     pEngine->SetDefaults(pSet);
513             }
514 
515             sal_Bool bEngineVertical = pEngine->IsVertical();
516             pEngine->SetVertical( bAsianVertical );
517             pEngine->SetUpdateMode( sal_True );
518 
519             sal_Bool bEdWidth = bWidth;
520             if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
521                 bEdWidth = !bEdWidth;
522             if ( nRotate )
523             {
524                 //! unterschiedliche Skalierung X/Y beruecksichtigen
525 
526                 Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
527                 double nRealOrient = nRotate * F_PI18000;   // nRotate sind 1/100 Grad
528                 double nCosAbs = fabs( cos( nRealOrient ) );
529                 double nSinAbs = fabs( sin( nRealOrient ) );
530                 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
531                 long nWidth;
532                 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
533                     nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
534                 else if ( rOptions.bTotalSize )
535                 {
536                     nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
537                     bAddMargin = sal_False;
538                     if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
539                         nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
540                                             nPPT * nCosAbs / nSinAbs );
541                 }
542                 else
543                     nWidth  = (long)( aSize.Height() / nSinAbs );   //! begrenzen?
544                 aSize = Size( nWidth, nHeight );
545 
546                 Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
547                 if ( bEdWidth )
548                     nValue = aPixSize.Width();
549                 else
550                 {
551                     nValue = aPixSize.Height();
552 
553                     if ( bBreak && !rOptions.bTotalSize )
554                     {
555                         //  #47744# limit size for line break
556                         long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
557                         if ( nValue > nCmp )
558                             nValue = nCmp;
559                     }
560                 }
561             }
562             else if ( bEdWidth )
563             {
564                 if (bBreak)
565                     nValue = 0;
566                 else
567                     nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
568                                         aHMMMode).Width();
569             }
570             else            // Hoehe
571             {
572                 nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
573                                     aHMMMode).Height();
574 
575                 // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
576                 if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
577                      ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
578                 {
579                     pEngine->SetControlWord( nCtrl | EE_CNTRL_FORMAT100 );
580                     pEngine->QuickFormatDoc( sal_True );
581                     long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
582                     if ( nSecondValue > nValue )
583                         nValue = nSecondValue;
584                 }
585             }
586 
587             if ( nValue && bAddMargin )
588             {
589                 if (bWidth)
590                 {
591                     nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
592                               (long) ( pMargin->GetRightMargin() * nPPT );
593                     if (nIndent)
594                         nValue += (long) ( nIndent * nPPT );
595                 }
596                 else
597                 {
598                     nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
599                               (long) ( pMargin->GetBottomMargin() * nPPT );
600 
601                     if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
602                     {
603                         //  add 1pt extra (default margin value) for line breaks with SetVertical
604                         nValue += (long) ( 20 * nPPT );
605                     }
606                 }
607             }
608 
609             //  EditEngine is cached and re-used, so the old vertical flag must be restored
610             pEngine->SetVertical( bEngineVertical );
611 
612             pDocument->DisposeFieldEditEngine(pEngine);
613 
614             pDev->SetMapMode( aOld );
615             pDev->SetFont( aOldFont );
616         }
617 
618         if (bWidth)
619         {
620             //      Platz fuer Autofilter-Button
621             //      20 * nZoom/100
622             //      bedingte Formatierung hier nicht interessant
623 
624             sal_Int16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
625             if (nFlags & SC_MF_AUTO)
626                 nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
627         }
628     }
629     return nValue;
630 }
631 
632 long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex, OutputDevice* pDev,
633         sal_Bool bWidth )
634 {
635     long nValue=0;
636     if ( nIndex < nCount )
637     {
638         SCROW nRow = pItems[nIndex].nRow;
639         const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
640         ScBaseCell* pCell = pItems[nIndex].pCell;
641         String aValStr;
642         Color* pColor;
643         SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
644         sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter );
645         ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
646                                     *pFormatter, sal_True, sal_False, ftCheck );
647         if ( aValStr.Len() )
648         {
649             if ( bWidth )
650                 nValue = pDev->GetTextWidth( aValStr );
651             else
652                 nValue = pDev->GetTextHeight();
653         }
654     }
655     return nValue;
656 }
657 
658 sal_uInt16 ScColumn::GetOptimalColWidth( OutputDevice* pDev, double nPPTX, double nPPTY,
659                                         const Fraction& rZoomX, const Fraction& rZoomY,
660                                         sal_Bool bFormula, sal_uInt16 nOldWidth,
661                                         const ScMarkData* pMarkData,
662                                         sal_Bool bSimpleTextImport )
663 {
664     if (nCount == 0)
665         return nOldWidth;
666 
667     sal_uInt16  nWidth = (sal_uInt16) (nOldWidth * nPPTX);
668     sal_Bool    bFound = sal_False;
669 
670     SCSIZE nIndex;
671     ScMarkedDataIter aDataIter(this, pMarkData, sal_True);
672     if ( bSimpleTextImport )
673     {   // alles eins bis auf NumberFormate
674         const ScPatternAttr* pPattern = GetPattern( 0 );
675         Font aFont;
676         // font color doesn't matter here
677         pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
678         pDev->SetFont( aFont );
679         const SvxMarginItem* pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
680         long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
681                         (long) ( pMargin->GetRightMargin() * nPPTX );
682 
683         while (aDataIter.Next( nIndex ))
684         {
685             sal_uInt16 nThis = (sal_uInt16) (GetSimpleTextNeededSize( nIndex, pDev,
686                 sal_True ) + nMargin);
687             if (nThis)
688             {
689                 if (nThis>nWidth || !bFound)
690                 {
691                     nWidth = nThis;
692                     bFound = sal_True;
693                 }
694             }
695         }
696     }
697     else
698     {
699         ScNeededSizeOptions aOptions;
700         aOptions.bFormula = bFormula;
701         const ScPatternAttr* pOldPattern = NULL;
702         sal_uInt8 nOldScript = 0;
703 
704         while (aDataIter.Next( nIndex ))
705         {
706             SCROW nRow = pItems[nIndex].nRow;
707 
708             sal_uInt8 nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
709             if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
710 
711             const ScPatternAttr* pPattern = GetPattern( nRow );
712             aOptions.pPattern = pPattern;
713             aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
714             sal_uInt16 nThis = (sal_uInt16) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
715                 rZoomX, rZoomY, sal_True, aOptions );
716             pOldPattern = pPattern;
717             if (nThis)
718             {
719                 if (nThis>nWidth || !bFound)
720                 {
721                     nWidth = nThis;
722                     bFound = sal_True;
723                 }
724             }
725         }
726     }
727 
728     if (bFound)
729     {
730         nWidth += 2;
731         sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
732         return nTwips;
733     }
734     else
735         return nOldWidth;
736 }
737 
738 sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
739 {
740     sal_uInt16 nHeight = (sal_uInt16) ((const SvxFontHeightItem&) rPattern.GetItem(nFontHeightId)).GetHeight();
741     const SvxMarginItem* pMargin = (const SvxMarginItem*) &rPattern.GetItem(ATTR_MARGIN);
742     nHeight += nHeight / 5;
743     //  gibt bei 10pt 240
744 
745     if ( ((const SvxEmphasisMarkItem&)rPattern.
746             GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
747     {
748         //  add height for emphasis marks
749         //! font metrics should be used instead
750         nHeight += nHeight / 4;
751     }
752 
753     if ( nHeight + 240 > ScGlobal::nDefFontHeight )
754     {
755         nHeight = sal::static_int_cast<sal_uInt16>( nHeight + ScGlobal::nDefFontHeight );
756         nHeight -= 240;
757     }
758 
759     //  Standard-Hoehe: TextHeight + Raender - 23
760     //  -> 257 unter Windows
761 
762     if (nHeight > STD_ROWHEIGHT_DIFF)
763         nHeight -= STD_ROWHEIGHT_DIFF;
764 
765     nHeight += pMargin->GetTopMargin() + pMargin->GetBottomMargin();
766 
767     return nHeight;
768 }
769 
770 //  pHeight in Twips
771 //  nMinHeight, nMinStart zur Optimierung: ab nRow >= nMinStart ist mindestens nMinHeight
772 //  (wird nur bei bStdAllowed ausgewertet)
773 
774 void ScColumn::GetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16* pHeight,
775                                 OutputDevice* pDev,
776                                 double nPPTX, double nPPTY,
777                                 const Fraction& rZoomX, const Fraction& rZoomY,
778                                 sal_Bool bShrink, sal_uInt16 nMinHeight, SCROW nMinStart )
779 {
780     ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
781 
782     SCROW nStart = -1;
783     SCROW nEnd = -1;
784     SCROW nEditPos = 0;
785     SCROW nNextEnd = 0;
786 
787     //  bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
788 
789     const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
790     while ( pPattern )
791     {
792         const ScMergeAttr*      pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
793         const ScMergeFlagAttr*  pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
794         if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
795         {
796             //  nix - vertikal bei der zusammengefassten und den ueberdeckten,
797             //        horizontal nur bei den ueberdeckten (unsichtbaren) -
798             //        eine nur horizontal zusammengefasste wird aber beruecksichtigt
799         }
800         else
801         {
802             SCROW nRow = 0;
803             sal_Bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
804             sal_Bool bStdOnly = sal_False;
805             if (bStdAllowed)
806             {
807                 sal_Bool bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
808                                 ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
809                                     GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
810                                     SVX_HOR_JUSTIFY_BLOCK);
811                 bStdOnly = !bBreak;
812 
813                 // bedingte Formatierung: Zellen durchgehen
814                 if ( bStdOnly && ((const SfxUInt32Item&)pPattern->
815                                     GetItem(ATTR_CONDITIONAL)).GetValue() )
816                     bStdOnly = sal_False;
817 
818                 // gedrehter Text: Zellen durchgehen
819                 if ( bStdOnly && ((const SfxInt32Item&)pPattern->
820                                     GetItem(ATTR_ROTATE_VALUE)).GetValue() )
821                     bStdOnly = sal_False;
822             }
823 
824             if (bStdOnly)
825                 if (HasEditCells(nStart,nEnd,nEditPos))     // includes mixed script types
826                 {
827                     if (nEditPos == nStart)
828                     {
829                         bStdOnly = sal_False;
830                         if (nEnd > nEditPos)
831                             nNextEnd = nEnd;
832                         nEnd = nEditPos;                // einzeln ausrechnen
833                         bStdAllowed = sal_False;            // wird auf jeden Fall per Zelle berechnet
834                     }
835                     else
836                     {
837                         nNextEnd = nEnd;
838                         nEnd = nEditPos - 1;            // Standard - Teil
839                     }
840                 }
841 
842             if (bStdAllowed)
843             {
844                 sal_uInt16 nLatHeight = 0;
845                 sal_uInt16 nCjkHeight = 0;
846                 sal_uInt16 nCtlHeight = 0;
847                 sal_uInt16 nDefHeight;
848                 sal_uInt8 nDefScript = ScGlobal::GetDefaultScriptType();
849                 if ( nDefScript == SCRIPTTYPE_ASIAN )
850                     nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
851                 else if ( nDefScript == SCRIPTTYPE_COMPLEX )
852                     nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
853                 else
854                     nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
855 
856                 //  if everything below is already larger, the loop doesn't have to
857                 //  be run again
858                 SCROW nStdEnd = nEnd;
859                 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
860                     nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
861 
862                 for (nRow=nStart; nRow<=nStdEnd; nRow++)
863                     if (nDefHeight > pHeight[nRow-nStartRow])
864                         pHeight[nRow-nStartRow] = nDefHeight;
865 
866                 if ( bStdOnly )
867                 {
868                     //  if cells are not handled individually below,
869                     //  check for cells with different script type
870 
871                     SCSIZE nIndex;
872                     Search(nStart,nIndex);
873                     while ( nIndex < nCount && (nRow=pItems[nIndex].nRow) <= nEnd )
874                     {
875                         sal_uInt8 nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
876                         if ( nScript != nDefScript )
877                         {
878                             if ( nScript == SCRIPTTYPE_ASIAN )
879                             {
880                                 if ( nCjkHeight == 0 )
881                                     nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
882                                 if (nCjkHeight > pHeight[nRow-nStartRow])
883                                     pHeight[nRow-nStartRow] = nCjkHeight;
884                             }
885                             else if ( nScript == SCRIPTTYPE_COMPLEX )
886                             {
887                                 if ( nCtlHeight == 0 )
888                                     nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
889                                 if (nCtlHeight > pHeight[nRow-nStartRow])
890                                     pHeight[nRow-nStartRow] = nCtlHeight;
891                             }
892                             else
893                             {
894                                 if ( nLatHeight == 0 )
895                                     nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
896                                 if (nLatHeight > pHeight[nRow-nStartRow])
897                                     pHeight[nRow-nStartRow] = nLatHeight;
898                             }
899                         }
900                         ++nIndex;
901                     }
902                 }
903             }
904 
905             if (!bStdOnly)                      // belegte Zellen suchen
906             {
907                 ScNeededSizeOptions aOptions;
908 
909                 SCSIZE nIndex;
910                 Search(nStart,nIndex);
911                 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEnd) : sal_False )
912                 {
913                     //  Zellhoehe nur berechnen, wenn sie spaeter auch gebraucht wird (#37928#)
914 
915                     if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
916                     {
917                         aOptions.pPattern = pPattern;
918                         sal_uInt16 nHeight = (sal_uInt16)
919                                 ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
920                                                     rZoomX, rZoomY, sal_False, aOptions ) / nPPTY );
921                         if (nHeight > pHeight[nRow-nStartRow])
922                             pHeight[nRow-nStartRow] = nHeight;
923                     }
924                     ++nIndex;
925                 }
926             }
927         }
928 
929         if (nNextEnd > 0)
930         {
931             nStart = nEnd + 1;
932             nEnd = nNextEnd;
933             nNextEnd = 0;
934         }
935         else
936             pPattern = aIter.Next(nStart,nEnd);
937     }
938 }
939 
940 sal_Bool ScColumn::GetNextSpellingCell(SCROW& nRow, sal_Bool bInSel, const ScMarkData& rData) const
941 {
942     sal_Bool bStop = sal_False;
943     CellType eCellType;
944     SCSIZE nIndex;
945     if (!bInSel && Search(nRow, nIndex))
946     {
947         eCellType = GetCellType(nRow);
948         if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
949              !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
950                pDocument->IsTabProtected(nTab)) )
951                 return sal_True;
952     }
953     while (!bStop)
954     {
955         if (bInSel)
956         {
957             nRow = rData.GetNextMarked(nCol, nRow, sal_False);
958             if (!ValidRow(nRow))
959             {
960                 nRow = MAXROW+1;
961                 bStop = sal_True;
962             }
963             else
964             {
965                 eCellType = GetCellType(nRow);
966                 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
967                      !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
968                        pDocument->IsTabProtected(nTab)) )
969                         return sal_True;
970                 else
971                     nRow++;
972             }
973         }
974         else if (GetNextDataPos(nRow))
975         {
976             eCellType = GetCellType(nRow);
977             if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
978                  !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
979                    pDocument->IsTabProtected(nTab)) )
980                     return sal_True;
981             else
982                 nRow++;
983         }
984         else
985         {
986             nRow = MAXROW+1;
987             bStop = sal_True;
988         }
989     }
990     return sal_False;
991 }
992 
993 // =========================================================================================
994 
995 void ScColumn::RemoveAutoSpellObj()
996 {
997     ScTabEditEngine* pEngine = NULL;
998 
999     for (SCSIZE i=0; i<nCount; i++)
1000         if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
1001         {
1002             ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
1003             const EditTextObject* pData = pOldCell->GetData();
1004             //  keine Abfrage auf HasOnlineSpellErrors, damit es auch
1005             //  nach dem Laden funktioniert
1006 
1007             //  Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
1008             //  in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
1009             //  Attribute in Default und harter Formatierung erkennen und weglassen sollte,
1010             //  muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
1011             //  werden!
1012 
1013             //  auf Attribute testen
1014             if ( !pEngine )
1015                 pEngine = new ScTabEditEngine(pDocument);
1016             pEngine->SetText( *pData );
1017             ScEditAttrTester aTester( pEngine );
1018             if ( aTester.NeedsObject() )                    // nur Spell-Errors entfernen
1019             {
1020                 EditTextObject* pNewData = pEngine->CreateTextObject(); // ohne BIGOBJ
1021                 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1022                 delete pNewData;
1023             }
1024             else                                            // String erzeugen
1025             {
1026                 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1027                 ScBaseCell* pNewCell = new ScStringCell( aText );
1028                 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1029                 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1030                 pItems[i].pCell = pNewCell;
1031                 delete pOldCell;
1032             }
1033         }
1034 
1035     delete pEngine;
1036 }
1037 
1038 void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
1039 {
1040     ScFieldEditEngine* pEngine = NULL;
1041 
1042     SCSIZE i;
1043     Search( nStartRow, i );
1044     for (; i<nCount && pItems[i].nRow <= nEndRow; i++)
1045         if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
1046         {
1047             ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
1048             const EditTextObject* pData = pOldCell->GetData();
1049 
1050             //  Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
1051             //  in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
1052             //  Attribute in Default und harter Formatierung erkennen und weglassen sollte,
1053             //  muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
1054             //  werden!
1055 
1056             //  auf Attribute testen
1057             if ( !pEngine )
1058             {
1059                 //pEngine = new ScTabEditEngine(pDocument);
1060                 pEngine = new ScFieldEditEngine( pDocument->GetEditPool() );
1061                 //  EE_CNTRL_ONLINESPELLING falls schon Fehler drin sind
1062                 pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING );
1063                 pDocument->ApplyAsianEditSettings( *pEngine );
1064             }
1065             pEngine->SetText( *pData );
1066             sal_uInt16 nParCount = pEngine->GetParagraphCount();
1067             for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
1068             {
1069                 pEngine->QuickRemoveCharAttribs( nPar );
1070                 const SfxItemSet& rOld = pEngine->GetParaAttribs( nPar );
1071                 if ( rOld.Count() )
1072                 {
1073                     SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() );   // leer
1074                     pEngine->SetParaAttribs( nPar, aNew );
1075                 }
1076             }
1077             //  URL-Felder in Text wandeln (andere gibt's nicht, darum pType=0)
1078             pEngine->RemoveFields( sal_True );
1079 
1080             sal_Bool bSpellErrors = pEngine->HasOnlineSpellErrors();
1081             sal_Bool bNeedObject = bSpellErrors || nParCount>1;         // Errors/Absaetze behalten
1082             //  ScEditAttrTester nicht mehr noetig, Felder sind raus
1083 
1084             if ( bNeedObject )                                      // bleibt Edit-Zelle
1085             {
1086                 sal_uLong nCtrl = pEngine->GetControlWord();
1087                 sal_uLong nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
1088                 if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
1089                     pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
1090                 EditTextObject* pNewData = pEngine->CreateTextObject();
1091                 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1092                 delete pNewData;
1093             }
1094             else                                            // String erzeugen
1095             {
1096                 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1097                 ScBaseCell* pNewCell = new ScStringCell( aText );
1098                 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1099                 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1100                 pItems[i].pCell = pNewCell;
1101                 delete pOldCell;
1102             }
1103         }
1104 
1105     delete pEngine;
1106 }
1107 
1108 // =========================================================================================
1109 
1110 sal_Bool ScColumn::TestTabRefAbs(SCTAB nTable)
1111 {
1112     sal_Bool bRet = sal_False;
1113     if (pItems)
1114         for (SCSIZE i = 0; i < nCount; i++)
1115             if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1116                 if (((ScFormulaCell*)pItems[i].pCell)->TestTabRefAbs(nTable))
1117                     bRet = sal_True;
1118     return bRet;
1119 }
1120 
1121 // =========================================================================================
1122 
1123 ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
1124     pColumn( pCol ),
1125     nTop( nStart ),
1126     nBottom( nEnd )
1127 {
1128     pColumn->Search( nTop, nPos );
1129 }
1130 
1131 ScColumnIterator::~ScColumnIterator()
1132 {
1133 }
1134 
1135 sal_Bool ScColumnIterator::Next( SCROW& rRow, ScBaseCell*& rpCell )
1136 {
1137     if ( nPos < pColumn->nCount )
1138     {
1139         rRow = pColumn->pItems[nPos].nRow;
1140         if ( rRow <= nBottom )
1141         {
1142             rpCell = pColumn->pItems[nPos].pCell;
1143             ++nPos;
1144             return sal_True;
1145         }
1146     }
1147 
1148     rRow = 0;
1149     rpCell = NULL;
1150     return sal_False;
1151 }
1152 
1153 SCSIZE ScColumnIterator::GetIndex() const           // Index zur letzen abgefragten Zelle
1154 {
1155     return nPos - 1;        // bei Next ist Pos hochgezaehlt worden
1156 }
1157 
1158 // -----------------------------------------------------------------------------------------
1159 
1160 ScMarkedDataIter::ScMarkedDataIter( const ScColumn* pCol, const ScMarkData* pMarkData,
1161                                     sal_Bool bAllIfNone ) :
1162     pColumn( pCol ),
1163     pMarkIter( NULL ),
1164     bNext( sal_True ),
1165     bAll( bAllIfNone )
1166 {
1167     if (pMarkData && pMarkData->IsMultiMarked())
1168         pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
1169 }
1170 
1171 ScMarkedDataIter::~ScMarkedDataIter()
1172 {
1173     delete pMarkIter;
1174 }
1175 
1176 sal_Bool ScMarkedDataIter::Next( SCSIZE& rIndex )
1177 {
1178     sal_Bool bFound = sal_False;
1179     do
1180     {
1181         if (bNext)
1182         {
1183             if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
1184             {
1185                 if (bAll)                   // ganze Spalte
1186                 {
1187                     nTop    = 0;
1188                     nBottom = MAXROW;
1189                 }
1190                 else
1191                     return sal_False;
1192             }
1193             pColumn->Search( nTop, nPos );
1194             bNext = sal_False;
1195             bAll  = sal_False;                  // nur beim ersten Versuch
1196         }
1197 
1198         if ( nPos >= pColumn->nCount )
1199             return sal_False;
1200 
1201         if ( pColumn->pItems[nPos].nRow <= nBottom )
1202             bFound = sal_True;
1203         else
1204             bNext = sal_True;
1205     }
1206     while (!bFound);
1207 
1208     rIndex = nPos++;
1209     return sal_True;
1210 }
1211 
1212 //UNUSED2009-05 sal_uInt16 ScColumn::GetErrorData( SCROW nRow ) const
1213 //UNUSED2009-05 {
1214 //UNUSED2009-05     SCSIZE  nIndex;
1215 //UNUSED2009-05     if (Search(nRow, nIndex))
1216 //UNUSED2009-05     {
1217 //UNUSED2009-05         ScBaseCell* pCell = pItems[nIndex].pCell;
1218 //UNUSED2009-05         switch (pCell->GetCellType())
1219 //UNUSED2009-05         {
1220 //UNUSED2009-05             case CELLTYPE_FORMULA :
1221 //UNUSED2009-05                 return ((ScFormulaCell*)pCell)->GetErrCode();
1222 //UNUSED2009-05 //            break;
1223 //UNUSED2009-05             default:
1224 //UNUSED2009-05             return 0;
1225 //UNUSED2009-05         }
1226 //UNUSED2009-05     }
1227 //UNUSED2009-05     return 0;
1228 //UNUSED2009-05 }
1229 
1230 //------------
1231 
1232 sal_Bool ScColumn::IsEmptyData() const
1233 {
1234     return (nCount == 0);
1235 }
1236 
1237 sal_Bool ScColumn::IsEmptyVisData(sal_Bool bNotes) const
1238 {
1239     if (!pItems || nCount == 0)
1240         return sal_True;
1241     else
1242     {
1243         sal_Bool bVisData = sal_False;
1244         SCSIZE i;
1245         for (i=0; i<nCount && !bVisData; i++)
1246         {
1247             ScBaseCell* pCell = pItems[i].pCell;
1248             if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1249                 bVisData = sal_True;
1250         }
1251         return !bVisData;
1252     }
1253 }
1254 
1255 SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1256 {
1257     //  Notizen werden nicht mitgezaehlt
1258 
1259     SCSIZE nVisCount = 0;
1260     SCSIZE nIndex;
1261     Search( nStartRow, nIndex );
1262     while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1263     {
1264         if ( pItems[nIndex].nRow >= nStartRow &&
1265              pItems[nIndex].pCell->GetCellType() != CELLTYPE_NOTE )
1266         {
1267             ++nVisCount;
1268         }
1269         ++nIndex;
1270     }
1271     return nVisCount;
1272 }
1273 
1274 SCROW ScColumn::GetLastVisDataPos(sal_Bool bNotes) const
1275 {
1276     SCROW nRet = 0;
1277     if (pItems)
1278     {
1279         SCSIZE i;
1280         sal_Bool bFound = sal_False;
1281         for (i=nCount; i>0 && !bFound; )
1282         {
1283             --i;
1284             ScBaseCell* pCell = pItems[i].pCell;
1285             if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1286             {
1287                 bFound = sal_True;
1288                 nRet = pItems[i].nRow;
1289             }
1290         }
1291     }
1292     return nRet;
1293 }
1294 
1295 SCROW ScColumn::GetFirstVisDataPos(sal_Bool bNotes) const
1296 {
1297     SCROW nRet = 0;
1298     if (pItems)
1299     {
1300         SCSIZE i;
1301         sal_Bool bFound = sal_False;
1302         for (i=0; i<nCount && !bFound; i++)
1303         {
1304             ScBaseCell* pCell = pItems[i].pCell;
1305             if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1306             {
1307                 bFound = sal_True;
1308                 nRet = pItems[i].nRow;
1309             }
1310         }
1311     }
1312     return nRet;
1313 }
1314 
1315 sal_Bool ScColumn::HasVisibleDataAt(SCROW nRow) const
1316 {
1317     SCSIZE nIndex;
1318     if (Search(nRow, nIndex))
1319         if (!pItems[nIndex].pCell->IsBlank())
1320             return sal_True;
1321 
1322     return sal_False;
1323 }
1324 
1325 sal_Bool ScColumn::IsEmptyAttr() const
1326 {
1327     if (pAttrArray)
1328         return pAttrArray->IsEmpty();
1329     else
1330         return sal_True;
1331 }
1332 
1333 sal_Bool ScColumn::IsEmpty() const
1334 {
1335     return (IsEmptyData() && IsEmptyAttr());
1336 }
1337 
1338 sal_Bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow, bool bIgnoreNotes) const
1339 {
1340     if ( nCount == 0 || !pItems )
1341         return sal_True;
1342 
1343     SCSIZE nIndex;
1344     Search( nStartRow, nIndex );
1345     while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1346     {
1347         if ( !pItems[nIndex].pCell->IsBlank( bIgnoreNotes ) )   // found a cell
1348             return sal_False;                           // not empty
1349         ++nIndex;
1350     }
1351     return sal_True;                                    // no cell found
1352 }
1353 
1354 SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
1355 {
1356     SCSIZE nLines = 0;
1357     sal_Bool bFound = sal_False;
1358     SCSIZE i;
1359     if (pItems && (nCount > 0))
1360     {
1361         if (eDir == DIR_BOTTOM)
1362         {
1363             i = nCount;
1364             while (!bFound && (i > 0))
1365             {
1366                 i--;
1367                 if ( pItems[i].nRow < nStartRow )
1368                     break;
1369                 bFound = pItems[i].nRow <= nEndRow && !pItems[i].pCell->IsBlank();
1370             }
1371             if (bFound)
1372                 nLines = static_cast<SCSIZE>(nEndRow - pItems[i].nRow);
1373             else
1374                 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1375         }
1376         else if (eDir == DIR_TOP)
1377         {
1378             i = 0;
1379             while (!bFound && (i < nCount))
1380             {
1381                 if ( pItems[i].nRow > nEndRow )
1382                     break;
1383                 bFound = pItems[i].nRow >= nStartRow && !pItems[i].pCell->IsBlank();
1384                 i++;
1385             }
1386             if (bFound)
1387                 nLines = static_cast<SCSIZE>(pItems[i-1].nRow - nStartRow);
1388             else
1389                 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1390         }
1391     }
1392     else
1393         nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1394     return nLines;
1395 }
1396 
1397 SCROW ScColumn::GetFirstDataPos() const
1398 {
1399     if (nCount)
1400         return pItems[0].nRow;
1401     else
1402         return 0;
1403 }
1404 
1405 SCROW ScColumn::GetLastDataPos() const
1406 {
1407     if (nCount)
1408         return pItems[nCount-1].nRow;
1409     else
1410         return 0;
1411 }
1412 
1413 sal_Bool ScColumn::GetPrevDataPos(SCROW& rRow) const
1414 {
1415     sal_Bool bFound = sal_False;
1416     SCSIZE i = nCount;
1417     while (!bFound && (i > 0))
1418     {
1419         --i;
1420         bFound = (pItems[i].nRow < rRow);
1421         if (bFound)
1422             rRow = pItems[i].nRow;
1423     }
1424     return bFound;
1425 }
1426 
1427 sal_Bool ScColumn::GetNextDataPos(SCROW& rRow) const        // greater than rRow
1428 {
1429     SCSIZE nIndex;
1430     if (Search( rRow, nIndex ))
1431         ++nIndex;                   // next cell
1432 
1433     sal_Bool bMore = ( nIndex < nCount );
1434     if ( bMore )
1435         rRow = pItems[nIndex].nRow;
1436     return bMore;
1437 }
1438 
1439 void ScColumn::FindDataAreaPos(SCROW& rRow, long nMovY) const
1440 {
1441     if (!nMovY) return;
1442     sal_Bool bForward = (nMovY>0);
1443 
1444     SCSIZE nIndex;
1445     sal_Bool bThere = Search(rRow, nIndex);
1446     if (bThere && pItems[nIndex].pCell->IsBlank())
1447         bThere = sal_False;
1448 
1449     if (bThere)
1450     {
1451         SCROW nLast = rRow;
1452         SCSIZE nOldIndex = nIndex;
1453         if (bForward)
1454         {
1455             if (nIndex<nCount-1)
1456             {
1457                 ++nIndex;
1458                 while (nIndex<nCount-1 && pItems[nIndex].nRow==nLast+1
1459                                         && !pItems[nIndex].pCell->IsBlank())
1460                 {
1461                     ++nIndex;
1462                     ++nLast;
1463                 }
1464                 if (nIndex==nCount-1)
1465                     if (pItems[nIndex].nRow==nLast+1 && !pItems[nIndex].pCell->IsBlank())
1466                         ++nLast;
1467             }
1468         }
1469         else
1470         {
1471             if (nIndex>0)
1472             {
1473                 --nIndex;
1474                 while (nIndex>0 && pItems[nIndex].nRow+1==nLast
1475                                         && !pItems[nIndex].pCell->IsBlank())
1476                 {
1477                     --nIndex;
1478                     --nLast;
1479                 }
1480                 if (nIndex==0)
1481                     if (pItems[nIndex].nRow+1==nLast && !pItems[nIndex].pCell->IsBlank())
1482                         --nLast;
1483             }
1484         }
1485         if (nLast==rRow)
1486         {
1487             bThere = sal_False;
1488             nIndex = bForward ? nOldIndex+1 : nOldIndex;
1489         }
1490         else
1491             rRow = nLast;
1492     }
1493 
1494     if (!bThere)
1495     {
1496         if (bForward)
1497         {
1498             while (nIndex<nCount && pItems[nIndex].pCell->IsBlank())
1499                 ++nIndex;
1500             if (nIndex<nCount)
1501                 rRow = pItems[nIndex].nRow;
1502             else
1503                 rRow = MAXROW;
1504         }
1505         else
1506         {
1507             while (nIndex>0 && pItems[nIndex-1].pCell->IsBlank())
1508                 --nIndex;
1509             if (nIndex>0)
1510                 rRow = pItems[nIndex-1].nRow;
1511             else
1512                 rRow = 0;
1513         }
1514     }
1515 }
1516 
1517 sal_Bool ScColumn::HasDataAt(SCROW nRow) const
1518 {
1519 /*  SCSIZE nIndex;
1520     return Search( nRow, nIndex );
1521 */
1522         //  immer nur sichtbare interessant ?
1523         //! dann HasVisibleDataAt raus
1524 
1525     SCSIZE nIndex;
1526     if (Search(nRow, nIndex))
1527         if (!pItems[nIndex].pCell->IsBlank())
1528             return sal_True;
1529 
1530     return sal_False;
1531 
1532 }
1533 
1534 sal_Bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1535 {
1536     if (pAttrArray && rCol.pAttrArray)
1537         return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1538     else
1539         return !pAttrArray && !rCol.pAttrArray;
1540 }
1541 
1542 sal_Bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1543 {
1544     if (pAttrArray && rCol.pAttrArray)
1545         return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1546     else
1547         return !pAttrArray && !rCol.pAttrArray;
1548 }
1549 
1550 sal_Bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1551 {
1552     if (pAttrArray)
1553         return pAttrArray->GetFirstVisibleAttr( rFirstRow );
1554     else
1555         return sal_False;
1556 }
1557 
1558 sal_Bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
1559 {
1560     if (pAttrArray)
1561     {
1562         // row of last cell is needed
1563         SCROW nLastData = GetLastVisDataPos( sal_True );    // always including notes, 0 if none
1564 
1565         return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
1566     }
1567     else
1568         return sal_False;
1569 }
1570 
1571 sal_Bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1572 {
1573     if (pAttrArray)
1574         return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
1575     else
1576         return sal_False;
1577 }
1578 
1579 void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, sal_Bool* pUsed ) const
1580 {
1581     SCROW nRow = 0;
1582     SCSIZE nIndex;
1583     Search( nStartRow, nIndex );
1584     while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
1585     {
1586         pUsed[nRow-nStartRow] = sal_True;
1587         ++nIndex;
1588     }
1589 }
1590 
1591 void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
1592 {
1593     SvtBroadcaster* pBC = NULL;
1594     ScBaseCell* pCell;
1595 
1596     SCSIZE nIndex;
1597     if (Search(nRow,nIndex))
1598     {
1599         pCell = pItems[nIndex].pCell;
1600         pBC = pCell->GetBroadcaster();
1601     }
1602     else
1603     {
1604         pCell = new ScNoteCell;
1605         Insert(nRow, pCell);
1606     }
1607 
1608     if (!pBC)
1609     {
1610         pBC = new SvtBroadcaster;
1611         pCell->TakeBroadcaster(pBC);
1612     }
1613     rLst.StartListening(*pBC);
1614 }
1615 
1616 void ScColumn::MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow )
1617 {
1618     SvtBroadcaster* pBC = NULL;
1619     ScBaseCell* pCell;
1620 
1621     SCSIZE nIndex;
1622     if (Search(nDestRow,nIndex))
1623     {
1624         pCell = pItems[nIndex].pCell;
1625         pBC = pCell->GetBroadcaster();
1626     }
1627     else
1628     {
1629         pCell = new ScNoteCell;
1630         Insert(nDestRow, pCell);
1631     }
1632 
1633     if (!pBC)
1634     {
1635         pBC = new SvtBroadcaster;
1636         pCell->TakeBroadcaster(pBC);
1637     }
1638 
1639     if (rSource.HasListeners())
1640     {
1641         SvtListenerIter aIter( rSource);
1642         for (SvtListener* pLst = aIter.GoStart(); pLst; pLst = aIter.GoNext())
1643         {
1644             pLst->StartListening( *pBC);
1645             pLst->EndListening( rSource);
1646         }
1647     }
1648 }
1649 
1650 void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
1651 {
1652     SCSIZE nIndex;
1653     if (Search(nRow,nIndex))
1654     {
1655         ScBaseCell* pCell = pItems[nIndex].pCell;
1656         SvtBroadcaster* pBC = pCell->GetBroadcaster();
1657         if (pBC)
1658         {
1659             rLst.EndListening(*pBC);
1660 
1661             if (!pBC->HasListeners())
1662             {
1663                 if (pCell->IsBlank())
1664                     DeleteAtIndex(nIndex);
1665                 else
1666                     pCell->DeleteBroadcaster();
1667             }
1668         }
1669 //      else
1670 //          DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
1671     }
1672 //  else
1673 //      DBG_ERROR("ScColumn::EndListening - keine Zelle");
1674 }
1675 
1676 void ScColumn::CompileDBFormula()
1677 {
1678     if (pItems)
1679         for (SCSIZE i = 0; i < nCount; i++)
1680         {
1681             ScBaseCell* pCell = pItems[i].pCell;
1682             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1683                 ((ScFormulaCell*) pCell)->CompileDBFormula();
1684         }
1685 }
1686 
1687 void ScColumn::CompileDBFormula( sal_Bool bCreateFormulaString )
1688 {
1689     if (pItems)
1690         for (SCSIZE i = 0; i < nCount; i++)
1691         {
1692             ScBaseCell* pCell = pItems[i].pCell;
1693             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1694                 ((ScFormulaCell*) pCell)->CompileDBFormula( bCreateFormulaString );
1695         }
1696 }
1697 
1698 void ScColumn::CompileNameFormula( sal_Bool bCreateFormulaString )
1699 {
1700     if (pItems)
1701         for (SCSIZE i = 0; i < nCount; i++)
1702         {
1703             ScBaseCell* pCell = pItems[i].pCell;
1704             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1705                 ((ScFormulaCell*) pCell)->CompileNameFormula( bCreateFormulaString );
1706         }
1707 }
1708 
1709 void ScColumn::CompileColRowNameFormula()
1710 {
1711     if (pItems)
1712         for (SCSIZE i = 0; i < nCount; i++)
1713         {
1714             ScBaseCell* pCell = pItems[i].pCell;
1715             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1716                 ((ScFormulaCell*) pCell)->CompileColRowNameFormula();
1717         }
1718 }
1719 
1720 void lcl_UpdateSubTotal( ScFunctionData& rData, ScBaseCell* pCell )
1721 {
1722     double nValue = 0.0;
1723     sal_Bool bVal = sal_False;
1724     sal_Bool bCell = sal_True;
1725     switch (pCell->GetCellType())
1726     {
1727         case CELLTYPE_VALUE:
1728             nValue = ((ScValueCell*)pCell)->GetValue();
1729             bVal = sal_True;
1730             break;
1731         case CELLTYPE_FORMULA:
1732             {
1733                 if ( rData.eFunc != SUBTOTAL_FUNC_CNT2 )        // da interessiert's nicht
1734                 {
1735                     ScFormulaCell* pFC = (ScFormulaCell*)pCell;
1736                     if ( pFC->GetErrCode() )
1737                     {
1738                         if ( rData.eFunc != SUBTOTAL_FUNC_CNT ) // fuer Anzahl einfach weglassen
1739                             rData.bError = sal_True;
1740                     }
1741                     else if (pFC->IsValue())
1742                     {
1743                         nValue = pFC->GetValue();
1744                         bVal = sal_True;
1745                     }
1746                     // sonst Text
1747                 }
1748             }
1749             break;
1750         case CELLTYPE_NOTE:
1751             bCell = sal_False;
1752             break;
1753         // bei Strings nichts
1754         default:
1755         {
1756             // added to avoid warnings
1757         }
1758     }
1759 
1760     if (!rData.bError)
1761     {
1762         switch (rData.eFunc)
1763         {
1764             case SUBTOTAL_FUNC_SUM:
1765             case SUBTOTAL_FUNC_AVE:
1766                 if (bVal)
1767                 {
1768                     ++rData.nCount;
1769                     if (!SubTotal::SafePlus( rData.nVal, nValue ))
1770                         rData.bError = sal_True;
1771                 }
1772                 break;
1773             case SUBTOTAL_FUNC_CNT:             // nur Werte
1774                 if (bVal)
1775                     ++rData.nCount;
1776                 break;
1777             case SUBTOTAL_FUNC_CNT2:            // alle
1778                 if (bCell)
1779                     ++rData.nCount;
1780                 break;
1781             case SUBTOTAL_FUNC_MAX:
1782                 if (bVal)
1783                     if (++rData.nCount == 1 || nValue > rData.nVal )
1784                         rData.nVal = nValue;
1785                 break;
1786             case SUBTOTAL_FUNC_MIN:
1787                 if (bVal)
1788                     if (++rData.nCount == 1 || nValue < rData.nVal )
1789                         rData.nVal = nValue;
1790                 break;
1791             default:
1792             {
1793                 // added to avoid warnings
1794             }
1795         }
1796     }
1797 }
1798 
1799 //  Mehrfachselektion:
1800 void ScColumn::UpdateSelectionFunction( const ScMarkData& rMark,
1801                                         ScFunctionData& rData,
1802                                         ScFlatBoolRowSegments& rHiddenRows,
1803                                         sal_Bool bDoExclude, SCROW nExStartRow, SCROW nExEndRow )
1804 {
1805     SCSIZE nIndex;
1806     ScMarkedDataIter aDataIter(this, &rMark, sal_False);
1807     while (aDataIter.Next( nIndex ))
1808     {
1809         SCROW nRow = pItems[nIndex].nRow;
1810         bool bRowHidden = rHiddenRows.getValue(nRow);
1811         if ( !bRowHidden )
1812             if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
1813                 lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1814     }
1815 }
1816 
1817 //  bei bNoMarked die Mehrfachselektion weglassen
1818 void ScColumn::UpdateAreaFunction( ScFunctionData& rData,
1819                                    ScFlatBoolRowSegments& rHiddenRows,
1820                                     SCROW nStartRow, SCROW nEndRow )
1821 {
1822     SCSIZE nIndex;
1823     Search( nStartRow, nIndex );
1824     while ( nIndex<nCount && pItems[nIndex].nRow<=nEndRow )
1825     {
1826         SCROW nRow = pItems[nIndex].nRow;
1827         bool bRowHidden = rHiddenRows.getValue(nRow);
1828         if ( !bRowHidden )
1829             lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1830         ++nIndex;
1831     }
1832 }
1833 
1834 sal_uLong ScColumn::GetWeightedCount() const
1835 {
1836     sal_uLong nTotal = 0;
1837 
1838     //  Notizen werden nicht gezaehlt
1839 
1840     for (SCSIZE i=0; i<nCount; i++)
1841     {
1842         ScBaseCell* pCell = pItems[i].pCell;
1843         switch ( pCell->GetCellType() )
1844         {
1845             case CELLTYPE_VALUE:
1846             case CELLTYPE_STRING:
1847                 ++nTotal;
1848                 break;
1849             case CELLTYPE_FORMULA:
1850                 nTotal += 5 + ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1851                 break;
1852             case CELLTYPE_EDIT:
1853                 nTotal += 50;
1854                 break;
1855             default:
1856             {
1857                 // added to avoid warnings
1858             }
1859         }
1860     }
1861 
1862     return nTotal;
1863 }
1864 
1865 sal_uLong ScColumn::GetCodeCount() const
1866 {
1867     sal_uLong nCodeCount = 0;
1868 
1869     for (SCSIZE i=0; i<nCount; i++)
1870     {
1871         ScBaseCell* pCell = pItems[i].pCell;
1872         if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1873             nCodeCount += ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1874     }
1875 
1876     return nCodeCount;
1877 }
1878 
1879 
1880 
1881 
1882 
1883