update dev300-m57
[ooovba.git] / sc / source / core / data / column2.cxx
blob2291859d6ed09b3c1c982852191c042a8d56d00a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: column2.cxx,v $
10 * $Revision: 1.32.126.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <svx/eeitem.hxx>
41 #include <svx/algitem.hxx>
42 #include <svx/editobj.hxx>
43 #include <svx/editstat.hxx>
44 #include <svx/emphitem.hxx>
45 #include <svx/fhgtitem.hxx>
46 #include <svx/forbiddencharacterstable.hxx>
47 #include <svx/rotmodit.hxx>
48 #include <svx/scripttypeitem.hxx>
49 #include <svx/unolingu.hxx>
50 #include <svtools/zforlist.hxx>
51 #include <svtools/broadcast.hxx>
52 #include <svtools/listeneriter.hxx>
53 #include <vcl/outdev.hxx>
55 #include "column.hxx"
56 #include "cell.hxx"
57 #include "document.hxx"
58 #include "docpool.hxx"
59 #include "attarray.hxx"
60 #include "patattr.hxx"
61 #include "cellform.hxx"
62 #include "collect.hxx"
63 #include "stlsheet.hxx"
64 #include "rechead.hxx"
65 #include "brdcst.hxx"
66 #include "editutil.hxx"
67 #include "subtotal.hxx"
68 #include "markdata.hxx"
69 #include "compiler.hxx" // ScTokenArray GetCodeLen
70 #include "dbcolect.hxx"
71 #include "fillinfo.hxx"
73 #include <math.h>
75 // -----------------------------------------------------------------------
77 // factor from font size to optimal cell height (text width)
78 #define SC_ROT_BREAK_FACTOR 6
80 // -----------------------------------------------------------------------
82 inline BOOL IsAmbiguousScript( BYTE nScript )
84 //! move to a header file
85 return ( nScript != SCRIPTTYPE_LATIN &&
86 nScript != SCRIPTTYPE_ASIAN &&
87 nScript != SCRIPTTYPE_COMPLEX );
90 // -----------------------------------------------------------------------------------------
93 // Datei-Operationen
96 // -----------------------------------------------------------------------------------------
98 //UNUSED2008-05 SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
99 //UNUSED2008-05 {
100 //UNUSED2008-05 SCROW nNoteCount = 0;
101 //UNUSED2008-05 SCSIZE i;
102 //UNUSED2008-05
103 //UNUSED2008-05 for (i=0; i<nCount; i++)
104 //UNUSED2008-05 if ( pItems[i].pCell->GetNotePtr() && pItems[i].nRow<=nMaxRow )
105 //UNUSED2008-05 ++nNoteCount;
106 //UNUSED2008-05
107 //UNUSED2008-05 return nNoteCount;
108 //UNUSED2008-05 }
110 // -----------------------------------------------------------------------------------------
112 //UNUSED2008-05 void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
113 //UNUSED2008-05 {
114 //UNUSED2008-05 // #99139# find and correct string cells that are formatted with a symbol font,
115 //UNUSED2008-05 // but are not in the LoadedSymbolStringCellsList
116 //UNUSED2008-05 // (because CELLTYPE_SYMBOLS wasn't written in the file)
117 //UNUSED2008-05
118 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
119 //UNUSED2008-05 const ULONG nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
120 //UNUSED2008-05
121 //UNUSED2008-05 BOOL bListInitialized = FALSE;
122 //UNUSED2008-05 ScSymbolStringCellEntry* pCurrentEntry = NULL;
123 //UNUSED2008-05
124 //UNUSED2008-05 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
125 //UNUSED2008-05 SCROW nStt, nEnd;
126 //UNUSED2008-05 const ScPatternAttr* pAttr = aAttrIter.Next( nStt, nEnd );
127 //UNUSED2008-05 while ( pAttr )
128 //UNUSED2008-05 {
129 //UNUSED2008-05 if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
130 //UNUSED2008-05 pAttr->IsSymbolFont() )
131 //UNUSED2008-05 {
132 //UNUSED2008-05 ScColumnIterator aCellIter( this, nStt, nEnd );
133 //UNUSED2008-05 SCROW nRow;
134 //UNUSED2008-05 ScBaseCell* pCell;
135 //UNUSED2008-05 while ( aCellIter.Next( nRow, pCell ) )
136 //UNUSED2008-05 {
137 //UNUSED2008-05 if ( pCell->GetCellType() == CELLTYPE_STRING )
138 //UNUSED2008-05 {
139 //UNUSED2008-05 List& rList = pDocument->GetLoadedSymbolStringCellsList();
140 //UNUSED2008-05 if (!bListInitialized)
141 //UNUSED2008-05 {
142 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
143 //UNUSED2008-05 bListInitialized = TRUE;
144 //UNUSED2008-05 }
145 //UNUSED2008-05
146 //UNUSED2008-05 while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
147 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
148 //UNUSED2008-05
149 //UNUSED2008-05 if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
150 //UNUSED2008-05 {
151 //UNUSED2008-05 // found
152 //UNUSED2008-05 }
153 //UNUSED2008-05 else
154 //UNUSED2008-05 {
155 //UNUSED2008-05 // not in list -> convert and put into list
156 //UNUSED2008-05
157 //UNUSED2008-05 ScStringCell* pStrCell = (ScStringCell*)pCell;
158 //UNUSED2008-05 String aOldStr;
159 //UNUSED2008-05 pStrCell->GetString( aOldStr );
160 //UNUSED2008-05
161 //UNUSED2008-05 // convert back to stream character set (get original data)
162 //UNUSED2008-05 ByteString aByteStr( aOldStr, eStreamCharSet );
163 //UNUSED2008-05
164 //UNUSED2008-05 // convert using symbol encoding, as for CELLTYPE_SYMBOLS cells
165 //UNUSED2008-05 String aNewStr( aByteStr, RTL_TEXTENCODING_SYMBOL );
166 //UNUSED2008-05 pStrCell->SetString( aNewStr );
167 //UNUSED2008-05
168 //UNUSED2008-05 ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
169 //UNUSED2008-05 pEntry->pCell = pStrCell;
170 //UNUSED2008-05 pEntry->nRow = nRow;
171 //UNUSED2008-05
172 //UNUSED2008-05 if ( pCurrentEntry )
173 //UNUSED2008-05 rList.Insert( pEntry ); // before current entry - pCurrentEntry stays valid
174 //UNUSED2008-05 else
175 //UNUSED2008-05 rList.Insert( pEntry, LIST_APPEND ); // append if already behind last entry
176 //UNUSED2008-05 }
177 //UNUSED2008-05 }
178 //UNUSED2008-05 }
179 //UNUSED2008-05 }
180 //UNUSED2008-05
181 //UNUSED2008-05 pAttr = aAttrIter.Next( nStt, nEnd );
182 //UNUSED2008-05 }
183 //UNUSED2008-05 }
185 // -----------------------------------------------------------------------------------------
187 // GetNeededSize: optimale Hoehe / Breite in Pixeln
189 long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev,
190 double nPPTX, double nPPTY,
191 const Fraction& rZoomX, const Fraction& rZoomY,
192 BOOL bWidth, const ScNeededSizeOptions& rOptions )
194 long nValue=0;
195 SCSIZE nIndex;
196 double nPPT = bWidth ? nPPTX : nPPTY;
197 if (Search(nRow,nIndex))
199 const ScPatternAttr* pPattern = rOptions.pPattern;
200 if (!pPattern)
201 pPattern = pAttrArray->GetPattern( nRow );
203 // zusammengefasst?
204 // Merge nicht in bedingter Formatierung
206 const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
207 const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
209 if ( bWidth )
211 if ( pFlag->IsHorOverlapped() )
212 return 0;
213 if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
214 return 0;
216 else
218 if ( pFlag->IsVerOverlapped() )
219 return 0;
220 if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
221 return 0;
224 // bedingte Formatierung
225 const SfxItemSet* pCondSet = NULL;
226 if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
227 pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
229 // Zeilenumbruch?
231 const SfxPoolItem* pCondItem;
232 SvxCellHorJustify eHorJust;
233 if (pCondSet &&
234 pCondSet->GetItemState(ATTR_HOR_JUSTIFY, TRUE, &pCondItem) == SFX_ITEM_SET)
235 eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
236 else
237 eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
238 pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
239 BOOL bBreak;
240 if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
241 bBreak = TRUE;
242 else if ( pCondSet &&
243 pCondSet->GetItemState(ATTR_LINEBREAK, TRUE, &pCondItem) == SFX_ITEM_SET)
244 bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
245 else
246 bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
248 // get other attributes from pattern and conditional formatting
250 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
251 BOOL bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
252 ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
253 if ( bAsianVertical )
254 bBreak = FALSE;
256 if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
257 return 0;
259 long nRotate = 0;
260 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
261 if ( eOrient == SVX_ORIENTATION_STANDARD )
263 if (pCondSet &&
264 pCondSet->GetItemState(ATTR_ROTATE_VALUE, TRUE, &pCondItem) == SFX_ITEM_SET)
265 nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
266 else
267 nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
268 if ( nRotate )
270 if (pCondSet &&
271 pCondSet->GetItemState(ATTR_ROTATE_MODE, TRUE, &pCondItem) == SFX_ITEM_SET)
272 eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
273 else
274 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
275 pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
277 if ( nRotate == 18000 )
278 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
282 if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
284 // ignore orientation/rotation if "repeat" is active
285 eOrient = SVX_ORIENTATION_STANDARD;
286 nRotate = 0;
287 bAsianVertical = FALSE;
290 const SvxMarginItem* pMargin;
291 if (pCondSet &&
292 pCondSet->GetItemState(ATTR_MARGIN, TRUE, &pCondItem) == SFX_ITEM_SET)
293 pMargin = (const SvxMarginItem*) pCondItem;
294 else
295 pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
296 USHORT nIndent = 0;
297 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
299 if (pCondSet &&
300 pCondSet->GetItemState(ATTR_INDENT, TRUE, &pCondItem) == SFX_ITEM_SET)
301 nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
302 else
303 nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
306 ScBaseCell* pCell = pItems[nIndex].pCell;
307 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pCell );
308 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
310 // also call SetFont for edit cells, because bGetFont may be set only once
311 // bGetFont is set also if script type changes
312 if (rOptions.bGetFont)
314 Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
315 Font aFont;
316 // font color doesn't matter here
317 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
318 pDev->SetFont(aFont);
321 BOOL bAddMargin = TRUE;
322 CellType eCellType = pCell->GetCellType();
324 BOOL bEditEngine = ( eCellType == CELLTYPE_EDIT ||
325 eOrient == SVX_ORIENTATION_STACKED ||
326 IsAmbiguousScript( nScript ) ||
327 ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) );
329 if (!bEditEngine) // direkte Ausgabe
331 String aValStr;
332 Color* pColor;
333 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
334 ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
335 ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
336 *pFormatter,
337 TRUE, rOptions.bFormula, ftCheck );
338 if (aValStr.Len())
340 // SetFont ist nach oben verschoben
342 Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
343 if ( eOrient != SVX_ORIENTATION_STANDARD )
345 long nTemp = aSize.Width();
346 aSize.Width() = aSize.Height();
347 aSize.Height() = nTemp;
349 else if ( nRotate )
351 //! unterschiedliche Skalierung X/Y beruecksichtigen
353 double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
354 double nCosAbs = fabs( cos( nRealOrient ) );
355 double nSinAbs = fabs( sin( nRealOrient ) );
356 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
357 long nWidth;
358 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
359 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
360 else if ( rOptions.bTotalSize )
362 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
363 bAddMargin = FALSE;
364 // nur nach rechts:
365 //! unterscheiden nach Ausrichtung oben/unten (nur Text/ganze Hoehe)
366 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
367 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
368 nPPT * nCosAbs / nSinAbs );
370 else
371 nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
373 if ( bBreak && !rOptions.bTotalSize )
375 // #47744# limit size for line break
376 long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
377 if ( nHeight > nCmp )
378 nHeight = nCmp;
381 aSize = Size( nWidth, nHeight );
383 nValue = bWidth ? aSize.Width() : aSize.Height();
385 if ( bAddMargin )
387 if (bWidth)
389 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
390 (long) ( pMargin->GetRightMargin() * nPPT );
391 if ( nIndent )
392 nValue += (long) ( nIndent * nPPT );
394 else
395 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
396 (long) ( pMargin->GetBottomMargin() * nPPT );
399 // Zeilenumbruch ausgefuehrt ?
401 if ( bBreak && !bWidth )
403 // Test mit EditEngine zur Sicherheit schon bei 90%
404 // (wegen Rundungsfehlern und weil EditEngine teilweise anders formatiert)
406 long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
407 pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
408 nIndent )
409 * nPPT );
410 nDocPixel = (nDocPixel * 9) / 10; // zur Sicherheit
411 if ( aSize.Width() > nDocPixel )
412 bEditEngine = TRUE;
417 if (bEditEngine)
419 // der Font wird bei !bEditEngine nicht jedesmal neu gesetzt
420 Font aOldFont = pDev->GetFont();
422 MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
424 // am Dokument speichern ?
425 ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
427 pEngine->SetUpdateMode( FALSE );
428 MapMode aOld = pDev->GetMapMode();
429 pDev->SetMapMode( aHMMMode );
430 pEngine->SetRefDevice( pDev );
431 pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
432 pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
433 pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
434 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
435 pPattern->FillEditItemSet( pSet, pCondSet );
437 // no longer needed, are setted with the text (is faster)
438 // pEngine->SetDefaults( pSet );
440 if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
442 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
443 pEngine->SetHyphenator( xXHyphenator );
446 Size aPaper = Size( 1000000, 1000000 );
447 if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
448 aPaper.Width() = 1;
449 else if (bBreak)
451 double fWidthFactor = nPPTX;
452 BOOL bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
453 if ( bTextWysiwyg )
455 // #95593# if text is formatted for printer, don't use PixelToLogic,
456 // to ensure the exact same paper width (and same line breaks) as in
457 // ScEditUtil::GetEditArea, used for output.
459 fWidthFactor = HMM_PER_TWIPS;
462 // use original width for hidden columns:
463 long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
464 SCCOL nColMerge = pMerge->GetColMerge();
465 if (nColMerge > 1)
466 for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
467 nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
468 nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
469 + (long) ( pMargin->GetRightMargin() * fWidthFactor )
470 + 1; // Ausgabebereich ist Breite-1 Pixel (wegen Gitterlinien)
471 if ( nIndent )
472 nDocWidth -= (long) ( nIndent * fWidthFactor );
474 // space for AutoFilter button: 20 * nZoom/100
475 if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
476 nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
478 aPaper.Width() = nDocWidth;
480 if ( !bTextWysiwyg )
481 aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
483 pEngine->SetPaperSize(aPaper);
485 if ( pCell->GetCellType() == CELLTYPE_EDIT )
487 const EditTextObject* pData;
488 ((ScEditCell*)pCell)->GetData(pData);
489 pEngine->SetTextNewDefaults(*pData, pSet);
491 else
493 Color* pColor;
494 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
495 ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
496 String aString;
497 ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
498 *pFormatter,
499 TRUE, rOptions.bFormula, ftCheck );
500 if (aString.Len())
501 pEngine->SetTextNewDefaults(aString, pSet);
502 else
503 pEngine->SetDefaults(pSet);
506 BOOL bEngineVertical = pEngine->IsVertical();
507 pEngine->SetVertical( bAsianVertical );
508 pEngine->SetUpdateMode( TRUE );
510 BOOL bEdWidth = bWidth;
511 if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
512 bEdWidth = !bEdWidth;
513 if ( nRotate )
515 //! unterschiedliche Skalierung X/Y beruecksichtigen
517 Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
518 double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
519 double nCosAbs = fabs( cos( nRealOrient ) );
520 double nSinAbs = fabs( sin( nRealOrient ) );
521 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
522 long nWidth;
523 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
524 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
525 else if ( rOptions.bTotalSize )
527 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
528 bAddMargin = FALSE;
529 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
530 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
531 nPPT * nCosAbs / nSinAbs );
533 else
534 nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
535 aSize = Size( nWidth, nHeight );
537 Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
538 if ( bEdWidth )
539 nValue = aPixSize.Width();
540 else
542 nValue = aPixSize.Height();
544 if ( bBreak && !rOptions.bTotalSize )
546 // #47744# limit size for line break
547 long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
548 if ( nValue > nCmp )
549 nValue = nCmp;
553 else if ( bEdWidth )
555 if (bBreak)
556 nValue = 0;
557 else
558 nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
559 aHMMMode).Width();
561 else // Hoehe
563 nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
564 aHMMMode).Height();
567 if ( nValue && bAddMargin )
569 if (bWidth)
571 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
572 (long) ( pMargin->GetRightMargin() * nPPT );
573 if (nIndent)
574 nValue += (long) ( nIndent * nPPT );
576 else
578 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
579 (long) ( pMargin->GetBottomMargin() * nPPT );
581 if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
583 // add 1pt extra (default margin value) for line breaks with SetVertical
584 nValue += (long) ( 20 * nPPT );
589 // EditEngine is cached and re-used, so the old vertical flag must be restored
590 pEngine->SetVertical( bEngineVertical );
592 pDocument->DisposeFieldEditEngine(pEngine);
594 pDev->SetMapMode( aOld );
595 pDev->SetFont( aOldFont );
598 if (bWidth)
600 // Platz fuer Autofilter-Button
601 // 20 * nZoom/100
602 // bedingte Formatierung hier nicht interessant
604 INT16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
605 if (nFlags & SC_MF_AUTO)
606 nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
609 return nValue;
612 long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex, OutputDevice* pDev,
613 BOOL bWidth )
615 long nValue=0;
616 if ( nIndex < nCount )
618 SCROW nRow = pItems[nIndex].nRow;
619 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
620 ScBaseCell* pCell = pItems[nIndex].pCell;
621 String aValStr;
622 Color* pColor;
623 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
624 ULONG nFormat = pPattern->GetNumberFormat( pFormatter );
625 ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
626 *pFormatter, TRUE, FALSE, ftCheck );
627 if ( aValStr.Len() )
629 if ( bWidth )
630 nValue = pDev->GetTextWidth( aValStr );
631 else
632 nValue = pDev->GetTextHeight();
635 return nValue;
638 USHORT ScColumn::GetOptimalColWidth( OutputDevice* pDev, double nPPTX, double nPPTY,
639 const Fraction& rZoomX, const Fraction& rZoomY,
640 BOOL bFormula, USHORT nOldWidth,
641 const ScMarkData* pMarkData,
642 BOOL bSimpleTextImport )
644 if (nCount == 0)
645 return nOldWidth;
647 USHORT nWidth = (USHORT) (nOldWidth * nPPTX);
648 BOOL bFound = FALSE;
650 SCSIZE nIndex;
651 ScMarkedDataIter aDataIter(this, pMarkData, TRUE);
652 if ( bSimpleTextImport )
653 { // alles eins bis auf NumberFormate
654 const ScPatternAttr* pPattern = GetPattern( 0 );
655 Font aFont;
656 // font color doesn't matter here
657 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
658 pDev->SetFont( aFont );
659 const SvxMarginItem* pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
660 long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
661 (long) ( pMargin->GetRightMargin() * nPPTX );
663 while (aDataIter.Next( nIndex ))
665 USHORT nThis = (USHORT) (GetSimpleTextNeededSize( nIndex, pDev,
666 TRUE ) + nMargin);
667 if (nThis)
669 if (nThis>nWidth || !bFound)
671 nWidth = nThis;
672 bFound = TRUE;
677 else
679 ScNeededSizeOptions aOptions;
680 aOptions.bFormula = bFormula;
681 const ScPatternAttr* pOldPattern = NULL;
682 BYTE nOldScript = 0;
684 while (aDataIter.Next( nIndex ))
686 SCROW nRow = pItems[nIndex].nRow;
688 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
689 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
691 const ScPatternAttr* pPattern = GetPattern( nRow );
692 aOptions.pPattern = pPattern;
693 aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
694 USHORT nThis = (USHORT) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
695 rZoomX, rZoomY, TRUE, aOptions );
696 pOldPattern = pPattern;
697 if (nThis)
699 if (nThis>nWidth || !bFound)
701 nWidth = nThis;
702 bFound = TRUE;
708 if (bFound)
710 nWidth += 2;
711 USHORT nTwips = (USHORT) (nWidth / nPPTX);
712 return nTwips;
714 else
715 return nOldWidth;
718 USHORT lcl_GetAttribHeight( const ScPatternAttr& rPattern, USHORT nFontHeightId )
720 USHORT nHeight = (USHORT) ((const SvxFontHeightItem&) rPattern.GetItem(nFontHeightId)).GetHeight();
721 const SvxMarginItem* pMargin = (const SvxMarginItem*) &rPattern.GetItem(ATTR_MARGIN);
722 nHeight += nHeight / 5;
723 // gibt bei 10pt 240
725 if ( ((const SvxEmphasisMarkItem&)rPattern.
726 GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
728 // add height for emphasis marks
729 //! font metrics should be used instead
730 nHeight += nHeight / 4;
733 if ( nHeight + 240 > ScGlobal::nDefFontHeight )
735 nHeight = sal::static_int_cast<USHORT>( nHeight + ScGlobal::nDefFontHeight );
736 nHeight -= 240;
739 // Standard-Hoehe: TextHeight + Raender - 23
740 // -> 257 unter Windows
742 if (nHeight > STD_ROWHEIGHT_DIFF)
743 nHeight -= STD_ROWHEIGHT_DIFF;
745 nHeight += pMargin->GetTopMargin() + pMargin->GetBottomMargin();
747 return nHeight;
750 // pHeight in Twips
751 // nMinHeight, nMinStart zur Optimierung: ab nRow >= nMinStart ist mindestens nMinHeight
752 // (wird nur bei bStdAllowed ausgewertet)
754 void ScColumn::GetOptimalHeight( SCROW nStartRow, SCROW nEndRow, USHORT* pHeight,
755 OutputDevice* pDev,
756 double nPPTX, double nPPTY,
757 const Fraction& rZoomX, const Fraction& rZoomY,
758 BOOL bShrink, USHORT nMinHeight, SCROW nMinStart )
760 ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
762 SCROW nStart;
763 SCROW nEnd;
764 SCROW nEditPos = 0;
765 SCROW nNextEnd = 0;
767 // bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
769 const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
770 while ( pPattern )
772 const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
773 const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
774 if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
776 // nix - vertikal bei der zusammengefassten und den ueberdeckten,
777 // horizontal nur bei den ueberdeckten (unsichtbaren) -
778 // eine nur horizontal zusammengefasste wird aber beruecksichtigt
780 else
782 SCROW nRow = 0;
783 BOOL bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
784 BOOL bStdOnly = FALSE;
785 if (bStdAllowed)
787 BOOL bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
788 ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
789 GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
790 SVX_HOR_JUSTIFY_BLOCK);
791 bStdOnly = !bBreak;
793 // bedingte Formatierung: Zellen durchgehen
794 if ( bStdOnly && ((const SfxUInt32Item&)pPattern->
795 GetItem(ATTR_CONDITIONAL)).GetValue() )
796 bStdOnly = FALSE;
798 // gedrehter Text: Zellen durchgehen
799 if ( bStdOnly && ((const SfxInt32Item&)pPattern->
800 GetItem(ATTR_ROTATE_VALUE)).GetValue() )
801 bStdOnly = FALSE;
804 if (bStdOnly)
805 if (HasEditCells(nStart,nEnd,nEditPos)) // includes mixed script types
807 if (nEditPos == nStart)
809 bStdOnly = FALSE;
810 if (nEnd > nEditPos)
811 nNextEnd = nEnd;
812 nEnd = nEditPos; // einzeln ausrechnen
813 bStdAllowed = FALSE; // wird auf jeden Fall per Zelle berechnet
815 else
817 nNextEnd = nEnd;
818 nEnd = nEditPos - 1; // Standard - Teil
822 if (bStdAllowed)
824 USHORT nLatHeight = 0;
825 USHORT nCjkHeight = 0;
826 USHORT nCtlHeight = 0;
827 USHORT nDefHeight;
828 BYTE nDefScript = ScGlobal::GetDefaultScriptType();
829 if ( nDefScript == SCRIPTTYPE_ASIAN )
830 nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
831 else if ( nDefScript == SCRIPTTYPE_COMPLEX )
832 nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
833 else
834 nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
836 // if everything below is already larger, the loop doesn't have to
837 // be run again
838 SCROW nStdEnd = nEnd;
839 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
840 nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
842 for (nRow=nStart; nRow<=nStdEnd; nRow++)
843 if (nDefHeight > pHeight[nRow-nStartRow])
844 pHeight[nRow-nStartRow] = nDefHeight;
846 if ( bStdOnly )
848 // if cells are not handled individually below,
849 // check for cells with different script type
851 SCSIZE nIndex;
852 Search(nStart,nIndex);
853 while ( nIndex < nCount && (nRow=pItems[nIndex].nRow) <= nEnd )
855 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
856 if ( nScript != nDefScript )
858 if ( nScript == SCRIPTTYPE_ASIAN )
860 if ( nCjkHeight == 0 )
861 nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
862 if (nCjkHeight > pHeight[nRow-nStartRow])
863 pHeight[nRow-nStartRow] = nCjkHeight;
865 else if ( nScript == SCRIPTTYPE_COMPLEX )
867 if ( nCtlHeight == 0 )
868 nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
869 if (nCtlHeight > pHeight[nRow-nStartRow])
870 pHeight[nRow-nStartRow] = nCtlHeight;
872 else
874 if ( nLatHeight == 0 )
875 nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
876 if (nLatHeight > pHeight[nRow-nStartRow])
877 pHeight[nRow-nStartRow] = nLatHeight;
880 ++nIndex;
885 if (!bStdOnly) // belegte Zellen suchen
887 ScNeededSizeOptions aOptions;
889 SCSIZE nIndex;
890 Search(nStart,nIndex);
891 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEnd) : FALSE )
893 // Zellhoehe nur berechnen, wenn sie spaeter auch gebraucht wird (#37928#)
895 if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
897 aOptions.pPattern = pPattern;
898 USHORT nHeight = (USHORT)
899 ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
900 rZoomX, rZoomY, FALSE, aOptions ) / nPPTY );
901 if (nHeight > pHeight[nRow-nStartRow])
902 pHeight[nRow-nStartRow] = nHeight;
904 ++nIndex;
909 if (nNextEnd > 0)
911 nStart = nEnd + 1;
912 nEnd = nNextEnd;
913 nNextEnd = 0;
915 else
916 pPattern = aIter.Next(nStart,nEnd);
920 BOOL ScColumn::GetNextSpellingCell(SCROW& nRow, BOOL bInSel, const ScMarkData& rData) const
922 BOOL bStop = FALSE;
923 CellType eCellType;
924 SCSIZE nIndex;
925 if (!bInSel && Search(nRow, nIndex))
927 eCellType = GetCellType(nRow);
928 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
929 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
930 pDocument->IsTabProtected(nTab)) )
931 return TRUE;
933 while (!bStop)
935 if (bInSel)
937 nRow = rData.GetNextMarked(nCol, nRow, FALSE);
938 if (!ValidRow(nRow))
940 nRow = MAXROW+1;
941 bStop = TRUE;
943 else
945 eCellType = GetCellType(nRow);
946 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
947 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
948 pDocument->IsTabProtected(nTab)) )
949 return TRUE;
950 else
951 nRow++;
954 else if (GetNextDataPos(nRow))
956 eCellType = GetCellType(nRow);
957 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
958 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
959 pDocument->IsTabProtected(nTab)) )
960 return TRUE;
961 else
962 nRow++;
964 else
966 nRow = MAXROW+1;
967 bStop = TRUE;
970 return FALSE;
973 // =========================================================================================
975 void ScColumn::RemoveAutoSpellObj()
977 ScTabEditEngine* pEngine = NULL;
979 for (SCSIZE i=0; i<nCount; i++)
980 if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
982 ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
983 const EditTextObject* pData = pOldCell->GetData();
984 // keine Abfrage auf HasOnlineSpellErrors, damit es auch
985 // nach dem Laden funktioniert
987 // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
988 // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
989 // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
990 // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
991 // werden!
993 // auf Attribute testen
994 if ( !pEngine )
995 pEngine = new ScTabEditEngine(pDocument);
996 pEngine->SetText( *pData );
997 ScEditAttrTester aTester( pEngine );
998 if ( aTester.NeedsObject() ) // nur Spell-Errors entfernen
1000 EditTextObject* pNewData = pEngine->CreateTextObject(); // ohne BIGOBJ
1001 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1002 delete pNewData;
1004 else // String erzeugen
1006 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1007 ScBaseCell* pNewCell = new ScStringCell( aText );
1008 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1009 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1010 pItems[i].pCell = pNewCell;
1011 delete pOldCell;
1015 delete pEngine;
1018 void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
1020 ScFieldEditEngine* pEngine = NULL;
1022 SCSIZE i;
1023 Search( nStartRow, i );
1024 for (; i<nCount && pItems[i].nRow <= nEndRow; i++)
1025 if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
1027 ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
1028 const EditTextObject* pData = pOldCell->GetData();
1030 // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
1031 // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
1032 // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
1033 // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
1034 // werden!
1036 // auf Attribute testen
1037 if ( !pEngine )
1039 //pEngine = new ScTabEditEngine(pDocument);
1040 pEngine = new ScFieldEditEngine( pDocument->GetEditPool() );
1041 // EE_CNTRL_ONLINESPELLING falls schon Fehler drin sind
1042 pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING );
1043 pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
1044 pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
1045 pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
1047 pEngine->SetText( *pData );
1048 USHORT nParCount = pEngine->GetParagraphCount();
1049 for (USHORT nPar=0; nPar<nParCount; nPar++)
1051 pEngine->QuickRemoveCharAttribs( nPar );
1052 const SfxItemSet& rOld = pEngine->GetParaAttribs( nPar );
1053 if ( rOld.Count() )
1055 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // leer
1056 pEngine->SetParaAttribs( nPar, aNew );
1059 // URL-Felder in Text wandeln (andere gibt's nicht, darum pType=0)
1060 pEngine->RemoveFields( TRUE );
1062 BOOL bSpellErrors = pEngine->HasOnlineSpellErrors();
1063 BOOL bNeedObject = bSpellErrors || nParCount>1; // Errors/Absaetze behalten
1064 // ScEditAttrTester nicht mehr noetig, Felder sind raus
1066 if ( bNeedObject ) // bleibt Edit-Zelle
1068 ULONG nCtrl = pEngine->GetControlWord();
1069 ULONG nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
1070 if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
1071 pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
1072 EditTextObject* pNewData = pEngine->CreateTextObject();
1073 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1074 delete pNewData;
1076 else // String erzeugen
1078 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1079 ScBaseCell* pNewCell = new ScStringCell( aText );
1080 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1081 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1082 pItems[i].pCell = pNewCell;
1083 delete pOldCell;
1087 delete pEngine;
1090 // =========================================================================================
1092 BOOL ScColumn::TestTabRefAbs(SCTAB nTable)
1094 BOOL bRet = FALSE;
1095 if (pItems)
1096 for (SCSIZE i = 0; i < nCount; i++)
1097 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1098 if (((ScFormulaCell*)pItems[i].pCell)->TestTabRefAbs(nTable))
1099 bRet = TRUE;
1100 return bRet;
1103 // =========================================================================================
1105 ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
1106 pColumn( pCol ),
1107 nTop( nStart ),
1108 nBottom( nEnd )
1110 pColumn->Search( nTop, nPos );
1113 ScColumnIterator::~ScColumnIterator()
1117 BOOL ScColumnIterator::Next( SCROW& rRow, ScBaseCell*& rpCell )
1119 if ( nPos < pColumn->nCount )
1121 rRow = pColumn->pItems[nPos].nRow;
1122 if ( rRow <= nBottom )
1124 rpCell = pColumn->pItems[nPos].pCell;
1125 ++nPos;
1126 return TRUE;
1130 rRow = 0;
1131 rpCell = NULL;
1132 return FALSE;
1135 SCSIZE ScColumnIterator::GetIndex() const // Index zur letzen abgefragten Zelle
1137 return nPos - 1; // bei Next ist Pos hochgezaehlt worden
1140 // -----------------------------------------------------------------------------------------
1142 ScMarkedDataIter::ScMarkedDataIter( const ScColumn* pCol, const ScMarkData* pMarkData,
1143 BOOL bAllIfNone ) :
1144 pColumn( pCol ),
1145 pMarkIter( NULL ),
1146 bNext( TRUE ),
1147 bAll( bAllIfNone )
1149 if (pMarkData && pMarkData->IsMultiMarked())
1150 pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
1153 ScMarkedDataIter::~ScMarkedDataIter()
1155 delete pMarkIter;
1158 BOOL ScMarkedDataIter::Next( SCSIZE& rIndex )
1160 BOOL bFound = FALSE;
1163 if (bNext)
1165 if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
1167 if (bAll) // ganze Spalte
1169 nTop = 0;
1170 nBottom = MAXROW;
1172 else
1173 return FALSE;
1175 pColumn->Search( nTop, nPos );
1176 bNext = FALSE;
1177 bAll = FALSE; // nur beim ersten Versuch
1180 if ( nPos >= pColumn->nCount )
1181 return FALSE;
1183 if ( pColumn->pItems[nPos].nRow <= nBottom )
1184 bFound = TRUE;
1185 else
1186 bNext = TRUE;
1188 while (!bFound);
1190 rIndex = nPos++;
1191 return TRUE;
1194 //UNUSED2009-05 USHORT ScColumn::GetErrorData( SCROW nRow ) const
1195 //UNUSED2009-05 {
1196 //UNUSED2009-05 SCSIZE nIndex;
1197 //UNUSED2009-05 if (Search(nRow, nIndex))
1198 //UNUSED2009-05 {
1199 //UNUSED2009-05 ScBaseCell* pCell = pItems[nIndex].pCell;
1200 //UNUSED2009-05 switch (pCell->GetCellType())
1201 //UNUSED2009-05 {
1202 //UNUSED2009-05 case CELLTYPE_FORMULA :
1203 //UNUSED2009-05 return ((ScFormulaCell*)pCell)->GetErrCode();
1204 //UNUSED2009-05 // break;
1205 //UNUSED2009-05 default:
1206 //UNUSED2009-05 return 0;
1207 //UNUSED2009-05 }
1208 //UNUSED2009-05 }
1209 //UNUSED2009-05 return 0;
1210 //UNUSED2009-05 }
1212 //------------
1214 BOOL ScColumn::IsEmptyData() const
1216 return (nCount == 0);
1219 BOOL ScColumn::IsEmptyVisData(BOOL bNotes) const
1221 if (!pItems || nCount == 0)
1222 return TRUE;
1223 else
1225 BOOL bVisData = FALSE;
1226 SCSIZE i;
1227 for (i=0; i<nCount && !bVisData; i++)
1229 ScBaseCell* pCell = pItems[i].pCell;
1230 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1231 bVisData = TRUE;
1233 return !bVisData;
1237 SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1239 // Notizen werden nicht mitgezaehlt
1241 SCSIZE nVisCount = 0;
1242 SCSIZE nIndex;
1243 Search( nStartRow, nIndex );
1244 while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1246 if ( pItems[nIndex].nRow >= nStartRow &&
1247 pItems[nIndex].pCell->GetCellType() != CELLTYPE_NOTE )
1249 ++nVisCount;
1251 ++nIndex;
1253 return nVisCount;
1256 SCROW ScColumn::GetLastVisDataPos(BOOL bNotes) const
1258 SCROW nRet = 0;
1259 if (pItems)
1261 SCSIZE i;
1262 BOOL bFound = FALSE;
1263 for (i=nCount; i>0 && !bFound; )
1265 --i;
1266 ScBaseCell* pCell = pItems[i].pCell;
1267 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1269 bFound = TRUE;
1270 nRet = pItems[i].nRow;
1274 return nRet;
1277 SCROW ScColumn::GetFirstVisDataPos(BOOL bNotes) const
1279 SCROW nRet = 0;
1280 if (pItems)
1282 SCSIZE i;
1283 BOOL bFound = FALSE;
1284 for (i=0; i<nCount && !bFound; i++)
1286 ScBaseCell* pCell = pItems[i].pCell;
1287 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1289 bFound = TRUE;
1290 nRet = pItems[i].nRow;
1294 return nRet;
1297 BOOL ScColumn::HasVisibleDataAt(SCROW nRow) const
1299 SCSIZE nIndex;
1300 if (Search(nRow, nIndex))
1301 if (!pItems[nIndex].pCell->IsBlank())
1302 return TRUE;
1304 return FALSE;
1307 BOOL ScColumn::IsEmptyAttr() const
1309 if (pAttrArray)
1310 return pAttrArray->IsEmpty();
1311 else
1312 return TRUE;
1315 BOOL ScColumn::IsEmpty() const
1317 return (IsEmptyData() && IsEmptyAttr());
1320 BOOL ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow, bool bIgnoreNotes) const
1322 Rectangle aRect;
1323 if (pAttrArray->HasLines(nStartRow, nEndRow, aRect, TRUE, TRUE))
1324 return FALSE;
1326 if ( nCount == 0 || !pItems )
1327 return TRUE;
1329 SCSIZE nIndex;
1330 Search( nStartRow, nIndex );
1331 while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1333 if ( !pItems[nIndex].pCell->IsBlank( bIgnoreNotes ) ) // found a cell
1334 return FALSE; // not empty
1335 ++nIndex;
1337 return TRUE; // no cell found
1340 SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
1342 SCSIZE nLines = 0;
1343 BOOL bFound = FALSE;
1344 SCSIZE i;
1345 if (pItems && (nCount > 0))
1347 if (eDir == DIR_BOTTOM)
1349 i = nCount;
1350 while (!bFound && (i > 0))
1352 i--;
1353 if ( pItems[i].nRow < nStartRow )
1354 break;
1355 bFound = pItems[i].nRow <= nEndRow && !pItems[i].pCell->IsBlank();
1357 if (bFound)
1358 nLines = static_cast<SCSIZE>(nEndRow - pItems[i].nRow);
1359 else
1360 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1362 else if (eDir == DIR_TOP)
1364 i = 0;
1365 while (!bFound && (i < nCount))
1367 if ( pItems[i].nRow > nEndRow )
1368 break;
1369 bFound = pItems[i].nRow >= nStartRow && !pItems[i].pCell->IsBlank();
1370 i++;
1372 if (bFound)
1373 nLines = static_cast<SCSIZE>(pItems[i-1].nRow - nStartRow);
1374 else
1375 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1378 else
1379 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1380 return nLines;
1383 SCROW ScColumn::GetFirstDataPos() const
1385 if (nCount)
1386 return pItems[0].nRow;
1387 else
1388 return 0;
1391 SCROW ScColumn::GetLastDataPos() const
1393 if (nCount)
1394 return pItems[nCount-1].nRow;
1395 else
1396 return 0;
1399 BOOL ScColumn::GetPrevDataPos(SCROW& rRow) const
1401 BOOL bFound = FALSE;
1402 SCSIZE i = nCount;
1403 while (!bFound && (i > 0))
1405 --i;
1406 bFound = (pItems[i].nRow < rRow);
1407 if (bFound)
1408 rRow = pItems[i].nRow;
1410 return bFound;
1413 BOOL ScColumn::GetNextDataPos(SCROW& rRow) const // groesser als rRow
1415 SCSIZE nIndex;
1416 if (Search( rRow, nIndex ))
1417 ++nIndex; // naechste Zelle
1419 BOOL bMore = ( nIndex < nCount );
1420 if ( bMore )
1421 rRow = pItems[nIndex].nRow;
1422 return bMore;
1425 void ScColumn::FindDataAreaPos(SCROW& rRow, long nMovY) const
1427 if (!nMovY) return;
1428 BOOL bForward = (nMovY>0);
1430 SCSIZE nIndex;
1431 BOOL bThere = Search(rRow, nIndex);
1432 if (bThere && pItems[nIndex].pCell->IsBlank())
1433 bThere = FALSE;
1435 if (bThere)
1437 SCROW nLast = rRow;
1438 SCSIZE nOldIndex = nIndex;
1439 if (bForward)
1441 if (nIndex<nCount-1)
1443 ++nIndex;
1444 while (nIndex<nCount-1 && pItems[nIndex].nRow==nLast+1
1445 && !pItems[nIndex].pCell->IsBlank())
1447 ++nIndex;
1448 ++nLast;
1450 if (nIndex==nCount-1)
1451 if (pItems[nIndex].nRow==nLast+1 && !pItems[nIndex].pCell->IsBlank())
1452 ++nLast;
1455 else
1457 if (nIndex>0)
1459 --nIndex;
1460 while (nIndex>0 && pItems[nIndex].nRow+1==nLast
1461 && !pItems[nIndex].pCell->IsBlank())
1463 --nIndex;
1464 --nLast;
1466 if (nIndex==0)
1467 if (pItems[nIndex].nRow+1==nLast && !pItems[nIndex].pCell->IsBlank())
1468 --nLast;
1471 if (nLast==rRow)
1473 bThere = FALSE;
1474 nIndex = bForward ? nOldIndex+1 : nOldIndex;
1476 else
1477 rRow = nLast;
1480 if (!bThere)
1482 if (bForward)
1484 while (nIndex<nCount && pItems[nIndex].pCell->IsBlank())
1485 ++nIndex;
1486 if (nIndex<nCount)
1487 rRow = pItems[nIndex].nRow;
1488 else
1489 rRow = MAXROW;
1491 else
1493 while (nIndex>0 && pItems[nIndex-1].pCell->IsBlank())
1494 --nIndex;
1495 if (nIndex>0)
1496 rRow = pItems[nIndex-1].nRow;
1497 else
1498 rRow = 0;
1503 BOOL ScColumn::HasDataAt(SCROW nRow) const
1505 /* SCSIZE nIndex;
1506 return Search( nRow, nIndex );
1508 // immer nur sichtbare interessant ?
1509 //! dann HasVisibleDataAt raus
1511 SCSIZE nIndex;
1512 if (Search(nRow, nIndex))
1513 if (!pItems[nIndex].pCell->IsBlank())
1514 return TRUE;
1516 return FALSE;
1520 BOOL ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1522 if (pAttrArray && rCol.pAttrArray)
1523 return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1524 else
1525 return !pAttrArray && !rCol.pAttrArray;
1528 BOOL ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1530 if (pAttrArray && rCol.pAttrArray)
1531 return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1532 else
1533 return !pAttrArray && !rCol.pAttrArray;
1536 BOOL ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1538 if (pAttrArray)
1539 return pAttrArray->GetFirstVisibleAttr( rFirstRow );
1540 else
1541 return FALSE;
1544 BOOL ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
1546 if (pAttrArray)
1548 // row of last cell is needed
1549 SCROW nLastData = GetLastVisDataPos( TRUE ); // always including notes, 0 if none
1551 return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
1553 else
1554 return FALSE;
1557 BOOL ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1559 if (pAttrArray)
1560 return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
1561 else
1562 return FALSE;
1565 void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, BOOL* pUsed ) const
1567 SCROW nRow = 0;
1568 SCSIZE nIndex;
1569 Search( nStartRow, nIndex );
1570 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
1572 pUsed[nRow-nStartRow] = TRUE;
1573 ++nIndex;
1577 void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
1579 SvtBroadcaster* pBC = NULL;
1580 ScBaseCell* pCell;
1582 SCSIZE nIndex;
1583 if (Search(nRow,nIndex))
1585 pCell = pItems[nIndex].pCell;
1586 pBC = pCell->GetBroadcaster();
1588 else
1590 pCell = new ScNoteCell;
1591 Insert(nRow, pCell);
1594 if (!pBC)
1596 pBC = new SvtBroadcaster;
1597 pCell->TakeBroadcaster(pBC);
1599 rLst.StartListening(*pBC);
1602 void ScColumn::MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow )
1604 SvtBroadcaster* pBC = NULL;
1605 ScBaseCell* pCell;
1607 SCSIZE nIndex;
1608 if (Search(nDestRow,nIndex))
1610 pCell = pItems[nIndex].pCell;
1611 pBC = pCell->GetBroadcaster();
1613 else
1615 pCell = new ScNoteCell;
1616 Insert(nDestRow, pCell);
1619 if (!pBC)
1621 pBC = new SvtBroadcaster;
1622 pCell->TakeBroadcaster(pBC);
1625 if (rSource.HasListeners())
1627 SvtListenerIter aIter( rSource);
1628 for (SvtListener* pLst = aIter.GoStart(); pLst; pLst = aIter.GoNext())
1630 pLst->StartListening( *pBC);
1631 pLst->EndListening( rSource);
1636 void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
1638 SCSIZE nIndex;
1639 if (Search(nRow,nIndex))
1641 ScBaseCell* pCell = pItems[nIndex].pCell;
1642 SvtBroadcaster* pBC = pCell->GetBroadcaster();
1643 if (pBC)
1645 rLst.EndListening(*pBC);
1647 if (!pBC->HasListeners())
1649 if (pCell->IsBlank())
1650 DeleteAtIndex(nIndex);
1651 else
1652 pCell->DeleteBroadcaster();
1655 // else
1656 // DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
1658 // else
1659 // DBG_ERROR("ScColumn::EndListening - keine Zelle");
1662 void ScColumn::CompileDBFormula()
1664 if (pItems)
1665 for (SCSIZE i = 0; i < nCount; i++)
1667 ScBaseCell* pCell = pItems[i].pCell;
1668 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1669 ((ScFormulaCell*) pCell)->CompileDBFormula();
1673 void ScColumn::CompileDBFormula( BOOL bCreateFormulaString )
1675 if (pItems)
1676 for (SCSIZE i = 0; i < nCount; i++)
1678 ScBaseCell* pCell = pItems[i].pCell;
1679 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1680 ((ScFormulaCell*) pCell)->CompileDBFormula( bCreateFormulaString );
1684 void ScColumn::CompileNameFormula( BOOL bCreateFormulaString )
1686 if (pItems)
1687 for (SCSIZE i = 0; i < nCount; i++)
1689 ScBaseCell* pCell = pItems[i].pCell;
1690 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1691 ((ScFormulaCell*) pCell)->CompileNameFormula( bCreateFormulaString );
1695 void ScColumn::CompileColRowNameFormula()
1697 if (pItems)
1698 for (SCSIZE i = 0; i < nCount; i++)
1700 ScBaseCell* pCell = pItems[i].pCell;
1701 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1702 ((ScFormulaCell*) pCell)->CompileColRowNameFormula();
1706 void lcl_UpdateSubTotal( ScFunctionData& rData, ScBaseCell* pCell )
1708 double nValue = 0.0;
1709 BOOL bVal = FALSE;
1710 BOOL bCell = TRUE;
1711 switch (pCell->GetCellType())
1713 case CELLTYPE_VALUE:
1714 nValue = ((ScValueCell*)pCell)->GetValue();
1715 bVal = TRUE;
1716 break;
1717 case CELLTYPE_FORMULA:
1719 if ( rData.eFunc != SUBTOTAL_FUNC_CNT2 ) // da interessiert's nicht
1721 ScFormulaCell* pFC = (ScFormulaCell*)pCell;
1722 if ( pFC->GetErrCode() )
1724 if ( rData.eFunc != SUBTOTAL_FUNC_CNT ) // fuer Anzahl einfach weglassen
1725 rData.bError = TRUE;
1727 else if (pFC->IsValue())
1729 nValue = pFC->GetValue();
1730 bVal = TRUE;
1732 // sonst Text
1735 break;
1736 case CELLTYPE_NOTE:
1737 bCell = FALSE;
1738 break;
1739 // bei Strings nichts
1740 default:
1742 // added to avoid warnings
1746 if (!rData.bError)
1748 switch (rData.eFunc)
1750 case SUBTOTAL_FUNC_SUM:
1751 case SUBTOTAL_FUNC_AVE:
1752 if (bVal)
1754 ++rData.nCount;
1755 if (!SubTotal::SafePlus( rData.nVal, nValue ))
1756 rData.bError = TRUE;
1758 break;
1759 case SUBTOTAL_FUNC_CNT: // nur Werte
1760 if (bVal)
1761 ++rData.nCount;
1762 break;
1763 case SUBTOTAL_FUNC_CNT2: // alle
1764 if (bCell)
1765 ++rData.nCount;
1766 break;
1767 case SUBTOTAL_FUNC_MAX:
1768 if (bVal)
1769 if (++rData.nCount == 1 || nValue > rData.nVal )
1770 rData.nVal = nValue;
1771 break;
1772 case SUBTOTAL_FUNC_MIN:
1773 if (bVal)
1774 if (++rData.nCount == 1 || nValue < rData.nVal )
1775 rData.nVal = nValue;
1776 break;
1777 default:
1779 // added to avoid warnings
1785 // Mehrfachselektion:
1786 void ScColumn::UpdateSelectionFunction( const ScMarkData& rMark,
1787 ScFunctionData& rData,
1788 const ScBitMaskCompressedArray< SCROW, BYTE>* pRowFlags,
1789 BOOL bDoExclude, SCROW nExStartRow, SCROW nExEndRow )
1791 SCSIZE nIndex;
1792 ScMarkedDataIter aDataIter(this, &rMark, FALSE);
1793 while (aDataIter.Next( nIndex ))
1795 SCROW nRow = pItems[nIndex].nRow;
1796 if ( !pRowFlags || !( pRowFlags->GetValue(nRow) & CR_HIDDEN ) )
1797 if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
1798 lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1802 // bei bNoMarked die Mehrfachselektion weglassen
1803 void ScColumn::UpdateAreaFunction( ScFunctionData& rData,
1804 const ScBitMaskCompressedArray< SCROW, BYTE>* pRowFlags,
1805 SCROW nStartRow, SCROW nEndRow )
1807 SCSIZE nIndex;
1808 Search( nStartRow, nIndex );
1809 while ( nIndex<nCount && pItems[nIndex].nRow<=nEndRow )
1811 SCROW nRow = pItems[nIndex].nRow;
1812 if ( !pRowFlags || !( pRowFlags->GetValue(nRow) & CR_HIDDEN ) )
1813 lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1814 ++nIndex;
1818 ULONG ScColumn::GetWeightedCount() const
1820 ULONG nTotal = 0;
1822 // Notizen werden nicht gezaehlt
1824 for (SCSIZE i=0; i<nCount; i++)
1826 ScBaseCell* pCell = pItems[i].pCell;
1827 switch ( pCell->GetCellType() )
1829 case CELLTYPE_VALUE:
1830 case CELLTYPE_STRING:
1831 ++nTotal;
1832 break;
1833 case CELLTYPE_FORMULA:
1834 nTotal += 5 + ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1835 break;
1836 case CELLTYPE_EDIT:
1837 nTotal += 50;
1838 break;
1839 default:
1841 // added to avoid warnings
1846 return nTotal;
1849 ULONG ScColumn::GetCodeCount() const
1851 ULONG nCodeCount = 0;
1853 for (SCSIZE i=0; i<nCount; i++)
1855 ScBaseCell* pCell = pItems[i].pCell;
1856 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1857 nCodeCount += ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1860 return nCodeCount;