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