update dev300-m58
[ooovba.git] / sc / source / core / data / column2.cxx
blobc97fbda8d7aba0f663e27fbbfc436813cf2358bd
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"
72 #include "segmenttree.hxx"
74 #include <math.h>
76 // -----------------------------------------------------------------------
78 // factor from font size to optimal cell height (text width)
79 #define SC_ROT_BREAK_FACTOR 6
81 // -----------------------------------------------------------------------
83 inline BOOL IsAmbiguousScript( BYTE nScript )
85 //! move to a header file
86 return ( nScript != SCRIPTTYPE_LATIN &&
87 nScript != SCRIPTTYPE_ASIAN &&
88 nScript != SCRIPTTYPE_COMPLEX );
91 // -----------------------------------------------------------------------------------------
94 // Datei-Operationen
97 // -----------------------------------------------------------------------------------------
99 //UNUSED2008-05 SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
100 //UNUSED2008-05 {
101 //UNUSED2008-05 SCROW nNoteCount = 0;
102 //UNUSED2008-05 SCSIZE i;
103 //UNUSED2008-05
104 //UNUSED2008-05 for (i=0; i<nCount; i++)
105 //UNUSED2008-05 if ( pItems[i].pCell->GetNotePtr() && pItems[i].nRow<=nMaxRow )
106 //UNUSED2008-05 ++nNoteCount;
107 //UNUSED2008-05
108 //UNUSED2008-05 return nNoteCount;
109 //UNUSED2008-05 }
111 // -----------------------------------------------------------------------------------------
113 //UNUSED2008-05 void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
114 //UNUSED2008-05 {
115 //UNUSED2008-05 // #99139# find and correct string cells that are formatted with a symbol font,
116 //UNUSED2008-05 // but are not in the LoadedSymbolStringCellsList
117 //UNUSED2008-05 // (because CELLTYPE_SYMBOLS wasn't written in the file)
118 //UNUSED2008-05
119 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
120 //UNUSED2008-05 const ULONG nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
121 //UNUSED2008-05
122 //UNUSED2008-05 BOOL bListInitialized = FALSE;
123 //UNUSED2008-05 ScSymbolStringCellEntry* pCurrentEntry = NULL;
124 //UNUSED2008-05
125 //UNUSED2008-05 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
126 //UNUSED2008-05 SCROW nStt, nEnd;
127 //UNUSED2008-05 const ScPatternAttr* pAttr = aAttrIter.Next( nStt, nEnd );
128 //UNUSED2008-05 while ( pAttr )
129 //UNUSED2008-05 {
130 //UNUSED2008-05 if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
131 //UNUSED2008-05 pAttr->IsSymbolFont() )
132 //UNUSED2008-05 {
133 //UNUSED2008-05 ScColumnIterator aCellIter( this, nStt, nEnd );
134 //UNUSED2008-05 SCROW nRow;
135 //UNUSED2008-05 ScBaseCell* pCell;
136 //UNUSED2008-05 while ( aCellIter.Next( nRow, pCell ) )
137 //UNUSED2008-05 {
138 //UNUSED2008-05 if ( pCell->GetCellType() == CELLTYPE_STRING )
139 //UNUSED2008-05 {
140 //UNUSED2008-05 List& rList = pDocument->GetLoadedSymbolStringCellsList();
141 //UNUSED2008-05 if (!bListInitialized)
142 //UNUSED2008-05 {
143 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
144 //UNUSED2008-05 bListInitialized = TRUE;
145 //UNUSED2008-05 }
146 //UNUSED2008-05
147 //UNUSED2008-05 while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
148 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
149 //UNUSED2008-05
150 //UNUSED2008-05 if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
151 //UNUSED2008-05 {
152 //UNUSED2008-05 // found
153 //UNUSED2008-05 }
154 //UNUSED2008-05 else
155 //UNUSED2008-05 {
156 //UNUSED2008-05 // not in list -> convert and put into list
157 //UNUSED2008-05
158 //UNUSED2008-05 ScStringCell* pStrCell = (ScStringCell*)pCell;
159 //UNUSED2008-05 String aOldStr;
160 //UNUSED2008-05 pStrCell->GetString( aOldStr );
161 //UNUSED2008-05
162 //UNUSED2008-05 // convert back to stream character set (get original data)
163 //UNUSED2008-05 ByteString aByteStr( aOldStr, eStreamCharSet );
164 //UNUSED2008-05
165 //UNUSED2008-05 // convert using symbol encoding, as for CELLTYPE_SYMBOLS cells
166 //UNUSED2008-05 String aNewStr( aByteStr, RTL_TEXTENCODING_SYMBOL );
167 //UNUSED2008-05 pStrCell->SetString( aNewStr );
168 //UNUSED2008-05
169 //UNUSED2008-05 ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
170 //UNUSED2008-05 pEntry->pCell = pStrCell;
171 //UNUSED2008-05 pEntry->nRow = nRow;
172 //UNUSED2008-05
173 //UNUSED2008-05 if ( pCurrentEntry )
174 //UNUSED2008-05 rList.Insert( pEntry ); // before current entry - pCurrentEntry stays valid
175 //UNUSED2008-05 else
176 //UNUSED2008-05 rList.Insert( pEntry, LIST_APPEND ); // append if already behind last entry
177 //UNUSED2008-05 }
178 //UNUSED2008-05 }
179 //UNUSED2008-05 }
180 //UNUSED2008-05 }
181 //UNUSED2008-05
182 //UNUSED2008-05 pAttr = aAttrIter.Next( nStt, nEnd );
183 //UNUSED2008-05 }
184 //UNUSED2008-05 }
186 // -----------------------------------------------------------------------------------------
188 // GetNeededSize: optimale Hoehe / Breite in Pixeln
190 long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev,
191 double nPPTX, double nPPTY,
192 const Fraction& rZoomX, const Fraction& rZoomY,
193 BOOL bWidth, const ScNeededSizeOptions& rOptions )
195 long nValue=0;
196 SCSIZE nIndex;
197 double nPPT = bWidth ? nPPTX : nPPTY;
198 if (Search(nRow,nIndex))
200 const ScPatternAttr* pPattern = rOptions.pPattern;
201 if (!pPattern)
202 pPattern = pAttrArray->GetPattern( nRow );
204 // zusammengefasst?
205 // Merge nicht in bedingter Formatierung
207 const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
208 const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
210 if ( bWidth )
212 if ( pFlag->IsHorOverlapped() )
213 return 0;
214 if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
215 return 0;
217 else
219 if ( pFlag->IsVerOverlapped() )
220 return 0;
221 if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
222 return 0;
225 // bedingte Formatierung
226 const SfxItemSet* pCondSet = NULL;
227 if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
228 pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
230 // Zeilenumbruch?
232 const SfxPoolItem* pCondItem;
233 SvxCellHorJustify eHorJust;
234 if (pCondSet &&
235 pCondSet->GetItemState(ATTR_HOR_JUSTIFY, TRUE, &pCondItem) == SFX_ITEM_SET)
236 eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
237 else
238 eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
239 pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
240 BOOL bBreak;
241 if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
242 bBreak = TRUE;
243 else if ( pCondSet &&
244 pCondSet->GetItemState(ATTR_LINEBREAK, TRUE, &pCondItem) == SFX_ITEM_SET)
245 bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
246 else
247 bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
249 // get other attributes from pattern and conditional formatting
251 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
252 BOOL bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
253 ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
254 if ( bAsianVertical )
255 bBreak = FALSE;
257 if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
258 return 0;
260 long nRotate = 0;
261 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
262 if ( eOrient == SVX_ORIENTATION_STANDARD )
264 if (pCondSet &&
265 pCondSet->GetItemState(ATTR_ROTATE_VALUE, TRUE, &pCondItem) == SFX_ITEM_SET)
266 nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
267 else
268 nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
269 if ( nRotate )
271 if (pCondSet &&
272 pCondSet->GetItemState(ATTR_ROTATE_MODE, TRUE, &pCondItem) == SFX_ITEM_SET)
273 eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
274 else
275 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
276 pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
278 if ( nRotate == 18000 )
279 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
283 if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
285 // ignore orientation/rotation if "repeat" is active
286 eOrient = SVX_ORIENTATION_STANDARD;
287 nRotate = 0;
288 bAsianVertical = FALSE;
291 const SvxMarginItem* pMargin;
292 if (pCondSet &&
293 pCondSet->GetItemState(ATTR_MARGIN, TRUE, &pCondItem) == SFX_ITEM_SET)
294 pMargin = (const SvxMarginItem*) pCondItem;
295 else
296 pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
297 USHORT nIndent = 0;
298 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
300 if (pCondSet &&
301 pCondSet->GetItemState(ATTR_INDENT, TRUE, &pCondItem) == SFX_ITEM_SET)
302 nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
303 else
304 nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
307 ScBaseCell* pCell = pItems[nIndex].pCell;
308 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pCell );
309 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
311 // also call SetFont for edit cells, because bGetFont may be set only once
312 // bGetFont is set also if script type changes
313 if (rOptions.bGetFont)
315 Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
316 Font aFont;
317 // font color doesn't matter here
318 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
319 pDev->SetFont(aFont);
322 BOOL bAddMargin = TRUE;
323 CellType eCellType = pCell->GetCellType();
325 BOOL bEditEngine = ( eCellType == CELLTYPE_EDIT ||
326 eOrient == SVX_ORIENTATION_STACKED ||
327 IsAmbiguousScript( nScript ) ||
328 ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) );
330 if (!bEditEngine) // direkte Ausgabe
332 String aValStr;
333 Color* pColor;
334 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
335 ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
336 ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
337 *pFormatter,
338 TRUE, rOptions.bFormula, ftCheck );
339 if (aValStr.Len())
341 // SetFont ist nach oben verschoben
343 Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
344 if ( eOrient != SVX_ORIENTATION_STANDARD )
346 long nTemp = aSize.Width();
347 aSize.Width() = aSize.Height();
348 aSize.Height() = nTemp;
350 else if ( nRotate )
352 //! unterschiedliche Skalierung X/Y beruecksichtigen
354 double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
355 double nCosAbs = fabs( cos( nRealOrient ) );
356 double nSinAbs = fabs( sin( nRealOrient ) );
357 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
358 long nWidth;
359 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
360 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
361 else if ( rOptions.bTotalSize )
363 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
364 bAddMargin = FALSE;
365 // nur nach rechts:
366 //! unterscheiden nach Ausrichtung oben/unten (nur Text/ganze Hoehe)
367 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
368 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
369 nPPT * nCosAbs / nSinAbs );
371 else
372 nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
374 if ( bBreak && !rOptions.bTotalSize )
376 // #47744# limit size for line break
377 long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
378 if ( nHeight > nCmp )
379 nHeight = nCmp;
382 aSize = Size( nWidth, nHeight );
384 nValue = bWidth ? aSize.Width() : aSize.Height();
386 if ( bAddMargin )
388 if (bWidth)
390 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
391 (long) ( pMargin->GetRightMargin() * nPPT );
392 if ( nIndent )
393 nValue += (long) ( nIndent * nPPT );
395 else
396 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
397 (long) ( pMargin->GetBottomMargin() * nPPT );
400 // Zeilenumbruch ausgefuehrt ?
402 if ( bBreak && !bWidth )
404 // Test mit EditEngine zur Sicherheit schon bei 90%
405 // (wegen Rundungsfehlern und weil EditEngine teilweise anders formatiert)
407 long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
408 pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
409 nIndent )
410 * nPPT );
411 nDocPixel = (nDocPixel * 9) / 10; // zur Sicherheit
412 if ( aSize.Width() > nDocPixel )
413 bEditEngine = TRUE;
418 if (bEditEngine)
420 // der Font wird bei !bEditEngine nicht jedesmal neu gesetzt
421 Font aOldFont = pDev->GetFont();
423 MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
425 // am Dokument speichern ?
426 ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
428 pEngine->SetUpdateMode( FALSE );
429 MapMode aOld = pDev->GetMapMode();
430 pDev->SetMapMode( aHMMMode );
431 pEngine->SetRefDevice( pDev );
432 pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
433 pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
434 pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
435 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
436 pPattern->FillEditItemSet( pSet, pCondSet );
438 // no longer needed, are setted with the text (is faster)
439 // pEngine->SetDefaults( pSet );
441 if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
443 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
444 pEngine->SetHyphenator( xXHyphenator );
447 Size aPaper = Size( 1000000, 1000000 );
448 if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
449 aPaper.Width() = 1;
450 else if (bBreak)
452 double fWidthFactor = nPPTX;
453 BOOL bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
454 if ( bTextWysiwyg )
456 // #95593# if text is formatted for printer, don't use PixelToLogic,
457 // to ensure the exact same paper width (and same line breaks) as in
458 // ScEditUtil::GetEditArea, used for output.
460 fWidthFactor = HMM_PER_TWIPS;
463 // use original width for hidden columns:
464 long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
465 SCCOL nColMerge = pMerge->GetColMerge();
466 if (nColMerge > 1)
467 for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
468 nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
469 nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
470 + (long) ( pMargin->GetRightMargin() * fWidthFactor )
471 + 1; // Ausgabebereich ist Breite-1 Pixel (wegen Gitterlinien)
472 if ( nIndent )
473 nDocWidth -= (long) ( nIndent * fWidthFactor );
475 // space for AutoFilter button: 20 * nZoom/100
476 if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
477 nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
479 aPaper.Width() = nDocWidth;
481 if ( !bTextWysiwyg )
482 aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
484 pEngine->SetPaperSize(aPaper);
486 if ( pCell->GetCellType() == CELLTYPE_EDIT )
488 const EditTextObject* pData;
489 ((ScEditCell*)pCell)->GetData(pData);
490 pEngine->SetTextNewDefaults(*pData, pSet);
492 else
494 Color* pColor;
495 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
496 ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
497 String aString;
498 ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
499 *pFormatter,
500 TRUE, rOptions.bFormula, ftCheck );
501 if (aString.Len())
502 pEngine->SetTextNewDefaults(aString, pSet);
503 else
504 pEngine->SetDefaults(pSet);
507 BOOL bEngineVertical = pEngine->IsVertical();
508 pEngine->SetVertical( bAsianVertical );
509 pEngine->SetUpdateMode( TRUE );
511 BOOL bEdWidth = bWidth;
512 if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
513 bEdWidth = !bEdWidth;
514 if ( nRotate )
516 //! unterschiedliche Skalierung X/Y beruecksichtigen
518 Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
519 double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
520 double nCosAbs = fabs( cos( nRealOrient ) );
521 double nSinAbs = fabs( sin( nRealOrient ) );
522 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
523 long nWidth;
524 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
525 nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
526 else if ( rOptions.bTotalSize )
528 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
529 bAddMargin = FALSE;
530 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
531 nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
532 nPPT * nCosAbs / nSinAbs );
534 else
535 nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
536 aSize = Size( nWidth, nHeight );
538 Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
539 if ( bEdWidth )
540 nValue = aPixSize.Width();
541 else
543 nValue = aPixSize.Height();
545 if ( bBreak && !rOptions.bTotalSize )
547 // #47744# limit size for line break
548 long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
549 if ( nValue > nCmp )
550 nValue = nCmp;
554 else if ( bEdWidth )
556 if (bBreak)
557 nValue = 0;
558 else
559 nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
560 aHMMMode).Width();
562 else // Hoehe
564 nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
565 aHMMMode).Height();
568 if ( nValue && bAddMargin )
570 if (bWidth)
572 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
573 (long) ( pMargin->GetRightMargin() * nPPT );
574 if (nIndent)
575 nValue += (long) ( nIndent * nPPT );
577 else
579 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
580 (long) ( pMargin->GetBottomMargin() * nPPT );
582 if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
584 // add 1pt extra (default margin value) for line breaks with SetVertical
585 nValue += (long) ( 20 * nPPT );
590 // EditEngine is cached and re-used, so the old vertical flag must be restored
591 pEngine->SetVertical( bEngineVertical );
593 pDocument->DisposeFieldEditEngine(pEngine);
595 pDev->SetMapMode( aOld );
596 pDev->SetFont( aOldFont );
599 if (bWidth)
601 // Platz fuer Autofilter-Button
602 // 20 * nZoom/100
603 // bedingte Formatierung hier nicht interessant
605 INT16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
606 if (nFlags & SC_MF_AUTO)
607 nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
610 return nValue;
613 long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex, OutputDevice* pDev,
614 BOOL bWidth )
616 long nValue=0;
617 if ( nIndex < nCount )
619 SCROW nRow = pItems[nIndex].nRow;
620 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
621 ScBaseCell* pCell = pItems[nIndex].pCell;
622 String aValStr;
623 Color* pColor;
624 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
625 ULONG nFormat = pPattern->GetNumberFormat( pFormatter );
626 ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
627 *pFormatter, TRUE, FALSE, ftCheck );
628 if ( aValStr.Len() )
630 if ( bWidth )
631 nValue = pDev->GetTextWidth( aValStr );
632 else
633 nValue = pDev->GetTextHeight();
636 return nValue;
639 USHORT ScColumn::GetOptimalColWidth( OutputDevice* pDev, double nPPTX, double nPPTY,
640 const Fraction& rZoomX, const Fraction& rZoomY,
641 BOOL bFormula, USHORT nOldWidth,
642 const ScMarkData* pMarkData,
643 BOOL bSimpleTextImport )
645 if (nCount == 0)
646 return nOldWidth;
648 USHORT nWidth = (USHORT) (nOldWidth * nPPTX);
649 BOOL bFound = FALSE;
651 SCSIZE nIndex;
652 ScMarkedDataIter aDataIter(this, pMarkData, TRUE);
653 if ( bSimpleTextImport )
654 { // alles eins bis auf NumberFormate
655 const ScPatternAttr* pPattern = GetPattern( 0 );
656 Font aFont;
657 // font color doesn't matter here
658 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
659 pDev->SetFont( aFont );
660 const SvxMarginItem* pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
661 long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
662 (long) ( pMargin->GetRightMargin() * nPPTX );
664 while (aDataIter.Next( nIndex ))
666 USHORT nThis = (USHORT) (GetSimpleTextNeededSize( nIndex, pDev,
667 TRUE ) + nMargin);
668 if (nThis)
670 if (nThis>nWidth || !bFound)
672 nWidth = nThis;
673 bFound = TRUE;
678 else
680 ScNeededSizeOptions aOptions;
681 aOptions.bFormula = bFormula;
682 const ScPatternAttr* pOldPattern = NULL;
683 BYTE nOldScript = 0;
685 while (aDataIter.Next( nIndex ))
687 SCROW nRow = pItems[nIndex].nRow;
689 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
690 if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
692 const ScPatternAttr* pPattern = GetPattern( nRow );
693 aOptions.pPattern = pPattern;
694 aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
695 USHORT nThis = (USHORT) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
696 rZoomX, rZoomY, TRUE, aOptions );
697 pOldPattern = pPattern;
698 if (nThis)
700 if (nThis>nWidth || !bFound)
702 nWidth = nThis;
703 bFound = TRUE;
709 if (bFound)
711 nWidth += 2;
712 USHORT nTwips = (USHORT) (nWidth / nPPTX);
713 return nTwips;
715 else
716 return nOldWidth;
719 USHORT lcl_GetAttribHeight( const ScPatternAttr& rPattern, USHORT nFontHeightId )
721 USHORT nHeight = (USHORT) ((const SvxFontHeightItem&) rPattern.GetItem(nFontHeightId)).GetHeight();
722 const SvxMarginItem* pMargin = (const SvxMarginItem*) &rPattern.GetItem(ATTR_MARGIN);
723 nHeight += nHeight / 5;
724 // gibt bei 10pt 240
726 if ( ((const SvxEmphasisMarkItem&)rPattern.
727 GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
729 // add height for emphasis marks
730 //! font metrics should be used instead
731 nHeight += nHeight / 4;
734 if ( nHeight + 240 > ScGlobal::nDefFontHeight )
736 nHeight = sal::static_int_cast<USHORT>( nHeight + ScGlobal::nDefFontHeight );
737 nHeight -= 240;
740 // Standard-Hoehe: TextHeight + Raender - 23
741 // -> 257 unter Windows
743 if (nHeight > STD_ROWHEIGHT_DIFF)
744 nHeight -= STD_ROWHEIGHT_DIFF;
746 nHeight += pMargin->GetTopMargin() + pMargin->GetBottomMargin();
748 return nHeight;
751 // pHeight in Twips
752 // nMinHeight, nMinStart zur Optimierung: ab nRow >= nMinStart ist mindestens nMinHeight
753 // (wird nur bei bStdAllowed ausgewertet)
755 void ScColumn::GetOptimalHeight( SCROW nStartRow, SCROW nEndRow, USHORT* pHeight,
756 OutputDevice* pDev,
757 double nPPTX, double nPPTY,
758 const Fraction& rZoomX, const Fraction& rZoomY,
759 BOOL bShrink, USHORT nMinHeight, SCROW nMinStart )
761 ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
763 SCROW nStart;
764 SCROW nEnd;
765 SCROW nEditPos = 0;
766 SCROW nNextEnd = 0;
768 // bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
770 const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
771 while ( pPattern )
773 const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
774 const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
775 if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
777 // nix - vertikal bei der zusammengefassten und den ueberdeckten,
778 // horizontal nur bei den ueberdeckten (unsichtbaren) -
779 // eine nur horizontal zusammengefasste wird aber beruecksichtigt
781 else
783 SCROW nRow = 0;
784 BOOL bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
785 BOOL bStdOnly = FALSE;
786 if (bStdAllowed)
788 BOOL bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
789 ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
790 GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
791 SVX_HOR_JUSTIFY_BLOCK);
792 bStdOnly = !bBreak;
794 // bedingte Formatierung: Zellen durchgehen
795 if ( bStdOnly && ((const SfxUInt32Item&)pPattern->
796 GetItem(ATTR_CONDITIONAL)).GetValue() )
797 bStdOnly = FALSE;
799 // gedrehter Text: Zellen durchgehen
800 if ( bStdOnly && ((const SfxInt32Item&)pPattern->
801 GetItem(ATTR_ROTATE_VALUE)).GetValue() )
802 bStdOnly = FALSE;
805 if (bStdOnly)
806 if (HasEditCells(nStart,nEnd,nEditPos)) // includes mixed script types
808 if (nEditPos == nStart)
810 bStdOnly = FALSE;
811 if (nEnd > nEditPos)
812 nNextEnd = nEnd;
813 nEnd = nEditPos; // einzeln ausrechnen
814 bStdAllowed = FALSE; // wird auf jeden Fall per Zelle berechnet
816 else
818 nNextEnd = nEnd;
819 nEnd = nEditPos - 1; // Standard - Teil
823 if (bStdAllowed)
825 USHORT nLatHeight = 0;
826 USHORT nCjkHeight = 0;
827 USHORT nCtlHeight = 0;
828 USHORT nDefHeight;
829 BYTE nDefScript = ScGlobal::GetDefaultScriptType();
830 if ( nDefScript == SCRIPTTYPE_ASIAN )
831 nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
832 else if ( nDefScript == SCRIPTTYPE_COMPLEX )
833 nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
834 else
835 nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
837 // if everything below is already larger, the loop doesn't have to
838 // be run again
839 SCROW nStdEnd = nEnd;
840 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
841 nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
843 for (nRow=nStart; nRow<=nStdEnd; nRow++)
844 if (nDefHeight > pHeight[nRow-nStartRow])
845 pHeight[nRow-nStartRow] = nDefHeight;
847 if ( bStdOnly )
849 // if cells are not handled individually below,
850 // check for cells with different script type
852 SCSIZE nIndex;
853 Search(nStart,nIndex);
854 while ( nIndex < nCount && (nRow=pItems[nIndex].nRow) <= nEnd )
856 BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
857 if ( nScript != nDefScript )
859 if ( nScript == SCRIPTTYPE_ASIAN )
861 if ( nCjkHeight == 0 )
862 nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
863 if (nCjkHeight > pHeight[nRow-nStartRow])
864 pHeight[nRow-nStartRow] = nCjkHeight;
866 else if ( nScript == SCRIPTTYPE_COMPLEX )
868 if ( nCtlHeight == 0 )
869 nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
870 if (nCtlHeight > pHeight[nRow-nStartRow])
871 pHeight[nRow-nStartRow] = nCtlHeight;
873 else
875 if ( nLatHeight == 0 )
876 nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
877 if (nLatHeight > pHeight[nRow-nStartRow])
878 pHeight[nRow-nStartRow] = nLatHeight;
881 ++nIndex;
886 if (!bStdOnly) // belegte Zellen suchen
888 ScNeededSizeOptions aOptions;
890 SCSIZE nIndex;
891 Search(nStart,nIndex);
892 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEnd) : FALSE )
894 // Zellhoehe nur berechnen, wenn sie spaeter auch gebraucht wird (#37928#)
896 if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
898 aOptions.pPattern = pPattern;
899 USHORT nHeight = (USHORT)
900 ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
901 rZoomX, rZoomY, FALSE, aOptions ) / nPPTY );
902 if (nHeight > pHeight[nRow-nStartRow])
903 pHeight[nRow-nStartRow] = nHeight;
905 ++nIndex;
910 if (nNextEnd > 0)
912 nStart = nEnd + 1;
913 nEnd = nNextEnd;
914 nNextEnd = 0;
916 else
917 pPattern = aIter.Next(nStart,nEnd);
921 BOOL ScColumn::GetNextSpellingCell(SCROW& nRow, BOOL bInSel, const ScMarkData& rData) const
923 BOOL bStop = FALSE;
924 CellType eCellType;
925 SCSIZE nIndex;
926 if (!bInSel && Search(nRow, nIndex))
928 eCellType = GetCellType(nRow);
929 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
930 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
931 pDocument->IsTabProtected(nTab)) )
932 return TRUE;
934 while (!bStop)
936 if (bInSel)
938 nRow = rData.GetNextMarked(nCol, nRow, FALSE);
939 if (!ValidRow(nRow))
941 nRow = MAXROW+1;
942 bStop = TRUE;
944 else
946 eCellType = GetCellType(nRow);
947 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
948 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
949 pDocument->IsTabProtected(nTab)) )
950 return TRUE;
951 else
952 nRow++;
955 else if (GetNextDataPos(nRow))
957 eCellType = GetCellType(nRow);
958 if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
959 !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
960 pDocument->IsTabProtected(nTab)) )
961 return TRUE;
962 else
963 nRow++;
965 else
967 nRow = MAXROW+1;
968 bStop = TRUE;
971 return FALSE;
974 // =========================================================================================
976 void ScColumn::RemoveAutoSpellObj()
978 ScTabEditEngine* pEngine = NULL;
980 for (SCSIZE i=0; i<nCount; i++)
981 if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
983 ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
984 const EditTextObject* pData = pOldCell->GetData();
985 // keine Abfrage auf HasOnlineSpellErrors, damit es auch
986 // nach dem Laden funktioniert
988 // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
989 // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
990 // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
991 // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
992 // werden!
994 // auf Attribute testen
995 if ( !pEngine )
996 pEngine = new ScTabEditEngine(pDocument);
997 pEngine->SetText( *pData );
998 ScEditAttrTester aTester( pEngine );
999 if ( aTester.NeedsObject() ) // nur Spell-Errors entfernen
1001 EditTextObject* pNewData = pEngine->CreateTextObject(); // ohne BIGOBJ
1002 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1003 delete pNewData;
1005 else // String erzeugen
1007 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1008 ScBaseCell* pNewCell = new ScStringCell( aText );
1009 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1010 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1011 pItems[i].pCell = pNewCell;
1012 delete pOldCell;
1016 delete pEngine;
1019 void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
1021 ScFieldEditEngine* pEngine = NULL;
1023 SCSIZE i;
1024 Search( nStartRow, i );
1025 for (; i<nCount && pItems[i].nRow <= nEndRow; i++)
1026 if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
1028 ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
1029 const EditTextObject* pData = pOldCell->GetData();
1031 // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
1032 // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
1033 // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
1034 // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
1035 // werden!
1037 // auf Attribute testen
1038 if ( !pEngine )
1040 //pEngine = new ScTabEditEngine(pDocument);
1041 pEngine = new ScFieldEditEngine( pDocument->GetEditPool() );
1042 // EE_CNTRL_ONLINESPELLING falls schon Fehler drin sind
1043 pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING );
1044 pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
1045 pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
1046 pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
1048 pEngine->SetText( *pData );
1049 USHORT nParCount = pEngine->GetParagraphCount();
1050 for (USHORT nPar=0; nPar<nParCount; nPar++)
1052 pEngine->QuickRemoveCharAttribs( nPar );
1053 const SfxItemSet& rOld = pEngine->GetParaAttribs( nPar );
1054 if ( rOld.Count() )
1056 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // leer
1057 pEngine->SetParaAttribs( nPar, aNew );
1060 // URL-Felder in Text wandeln (andere gibt's nicht, darum pType=0)
1061 pEngine->RemoveFields( TRUE );
1063 BOOL bSpellErrors = pEngine->HasOnlineSpellErrors();
1064 BOOL bNeedObject = bSpellErrors || nParCount>1; // Errors/Absaetze behalten
1065 // ScEditAttrTester nicht mehr noetig, Felder sind raus
1067 if ( bNeedObject ) // bleibt Edit-Zelle
1069 ULONG nCtrl = pEngine->GetControlWord();
1070 ULONG nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
1071 if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
1072 pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
1073 EditTextObject* pNewData = pEngine->CreateTextObject();
1074 pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
1075 delete pNewData;
1077 else // String erzeugen
1079 String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
1080 ScBaseCell* pNewCell = new ScStringCell( aText );
1081 pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
1082 pNewCell->TakeNote( pOldCell->ReleaseNote() );
1083 pItems[i].pCell = pNewCell;
1084 delete pOldCell;
1088 delete pEngine;
1091 // =========================================================================================
1093 BOOL ScColumn::TestTabRefAbs(SCTAB nTable)
1095 BOOL bRet = FALSE;
1096 if (pItems)
1097 for (SCSIZE i = 0; i < nCount; i++)
1098 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1099 if (((ScFormulaCell*)pItems[i].pCell)->TestTabRefAbs(nTable))
1100 bRet = TRUE;
1101 return bRet;
1104 // =========================================================================================
1106 ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
1107 pColumn( pCol ),
1108 nTop( nStart ),
1109 nBottom( nEnd )
1111 pColumn->Search( nTop, nPos );
1114 ScColumnIterator::~ScColumnIterator()
1118 BOOL ScColumnIterator::Next( SCROW& rRow, ScBaseCell*& rpCell )
1120 if ( nPos < pColumn->nCount )
1122 rRow = pColumn->pItems[nPos].nRow;
1123 if ( rRow <= nBottom )
1125 rpCell = pColumn->pItems[nPos].pCell;
1126 ++nPos;
1127 return TRUE;
1131 rRow = 0;
1132 rpCell = NULL;
1133 return FALSE;
1136 SCSIZE ScColumnIterator::GetIndex() const // Index zur letzen abgefragten Zelle
1138 return nPos - 1; // bei Next ist Pos hochgezaehlt worden
1141 // -----------------------------------------------------------------------------------------
1143 ScMarkedDataIter::ScMarkedDataIter( const ScColumn* pCol, const ScMarkData* pMarkData,
1144 BOOL bAllIfNone ) :
1145 pColumn( pCol ),
1146 pMarkIter( NULL ),
1147 bNext( TRUE ),
1148 bAll( bAllIfNone )
1150 if (pMarkData && pMarkData->IsMultiMarked())
1151 pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
1154 ScMarkedDataIter::~ScMarkedDataIter()
1156 delete pMarkIter;
1159 BOOL ScMarkedDataIter::Next( SCSIZE& rIndex )
1161 BOOL bFound = FALSE;
1164 if (bNext)
1166 if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
1168 if (bAll) // ganze Spalte
1170 nTop = 0;
1171 nBottom = MAXROW;
1173 else
1174 return FALSE;
1176 pColumn->Search( nTop, nPos );
1177 bNext = FALSE;
1178 bAll = FALSE; // nur beim ersten Versuch
1181 if ( nPos >= pColumn->nCount )
1182 return FALSE;
1184 if ( pColumn->pItems[nPos].nRow <= nBottom )
1185 bFound = TRUE;
1186 else
1187 bNext = TRUE;
1189 while (!bFound);
1191 rIndex = nPos++;
1192 return TRUE;
1195 //UNUSED2009-05 USHORT ScColumn::GetErrorData( SCROW nRow ) const
1196 //UNUSED2009-05 {
1197 //UNUSED2009-05 SCSIZE nIndex;
1198 //UNUSED2009-05 if (Search(nRow, nIndex))
1199 //UNUSED2009-05 {
1200 //UNUSED2009-05 ScBaseCell* pCell = pItems[nIndex].pCell;
1201 //UNUSED2009-05 switch (pCell->GetCellType())
1202 //UNUSED2009-05 {
1203 //UNUSED2009-05 case CELLTYPE_FORMULA :
1204 //UNUSED2009-05 return ((ScFormulaCell*)pCell)->GetErrCode();
1205 //UNUSED2009-05 // break;
1206 //UNUSED2009-05 default:
1207 //UNUSED2009-05 return 0;
1208 //UNUSED2009-05 }
1209 //UNUSED2009-05 }
1210 //UNUSED2009-05 return 0;
1211 //UNUSED2009-05 }
1213 //------------
1215 BOOL ScColumn::IsEmptyData() const
1217 return (nCount == 0);
1220 BOOL ScColumn::IsEmptyVisData(BOOL bNotes) const
1222 if (!pItems || nCount == 0)
1223 return TRUE;
1224 else
1226 BOOL bVisData = FALSE;
1227 SCSIZE i;
1228 for (i=0; i<nCount && !bVisData; i++)
1230 ScBaseCell* pCell = pItems[i].pCell;
1231 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1232 bVisData = TRUE;
1234 return !bVisData;
1238 SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1240 // Notizen werden nicht mitgezaehlt
1242 SCSIZE nVisCount = 0;
1243 SCSIZE nIndex;
1244 Search( nStartRow, nIndex );
1245 while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1247 if ( pItems[nIndex].nRow >= nStartRow &&
1248 pItems[nIndex].pCell->GetCellType() != CELLTYPE_NOTE )
1250 ++nVisCount;
1252 ++nIndex;
1254 return nVisCount;
1257 SCROW ScColumn::GetLastVisDataPos(BOOL bNotes) const
1259 SCROW nRet = 0;
1260 if (pItems)
1262 SCSIZE i;
1263 BOOL bFound = FALSE;
1264 for (i=nCount; i>0 && !bFound; )
1266 --i;
1267 ScBaseCell* pCell = pItems[i].pCell;
1268 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1270 bFound = TRUE;
1271 nRet = pItems[i].nRow;
1275 return nRet;
1278 SCROW ScColumn::GetFirstVisDataPos(BOOL bNotes) const
1280 SCROW nRet = 0;
1281 if (pItems)
1283 SCSIZE i;
1284 BOOL bFound = FALSE;
1285 for (i=0; i<nCount && !bFound; i++)
1287 ScBaseCell* pCell = pItems[i].pCell;
1288 if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
1290 bFound = TRUE;
1291 nRet = pItems[i].nRow;
1295 return nRet;
1298 BOOL ScColumn::HasVisibleDataAt(SCROW nRow) const
1300 SCSIZE nIndex;
1301 if (Search(nRow, nIndex))
1302 if (!pItems[nIndex].pCell->IsBlank())
1303 return TRUE;
1305 return FALSE;
1308 BOOL ScColumn::IsEmptyAttr() const
1310 if (pAttrArray)
1311 return pAttrArray->IsEmpty();
1312 else
1313 return TRUE;
1316 BOOL ScColumn::IsEmpty() const
1318 return (IsEmptyData() && IsEmptyAttr());
1321 BOOL ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow, bool bIgnoreNotes) const
1323 Rectangle aRect;
1324 if (pAttrArray->HasLines(nStartRow, nEndRow, aRect, TRUE, TRUE))
1325 return FALSE;
1327 if ( nCount == 0 || !pItems )
1328 return TRUE;
1330 SCSIZE nIndex;
1331 Search( nStartRow, nIndex );
1332 while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
1334 if ( !pItems[nIndex].pCell->IsBlank( bIgnoreNotes ) ) // found a cell
1335 return FALSE; // not empty
1336 ++nIndex;
1338 return TRUE; // no cell found
1341 SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
1343 SCSIZE nLines = 0;
1344 BOOL bFound = FALSE;
1345 SCSIZE i;
1346 if (pItems && (nCount > 0))
1348 if (eDir == DIR_BOTTOM)
1350 i = nCount;
1351 while (!bFound && (i > 0))
1353 i--;
1354 if ( pItems[i].nRow < nStartRow )
1355 break;
1356 bFound = pItems[i].nRow <= nEndRow && !pItems[i].pCell->IsBlank();
1358 if (bFound)
1359 nLines = static_cast<SCSIZE>(nEndRow - pItems[i].nRow);
1360 else
1361 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1363 else if (eDir == DIR_TOP)
1365 i = 0;
1366 while (!bFound && (i < nCount))
1368 if ( pItems[i].nRow > nEndRow )
1369 break;
1370 bFound = pItems[i].nRow >= nStartRow && !pItems[i].pCell->IsBlank();
1371 i++;
1373 if (bFound)
1374 nLines = static_cast<SCSIZE>(pItems[i-1].nRow - nStartRow);
1375 else
1376 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1379 else
1380 nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
1381 return nLines;
1384 SCROW ScColumn::GetFirstDataPos() const
1386 if (nCount)
1387 return pItems[0].nRow;
1388 else
1389 return 0;
1392 SCROW ScColumn::GetLastDataPos() const
1394 if (nCount)
1395 return pItems[nCount-1].nRow;
1396 else
1397 return 0;
1400 BOOL ScColumn::GetPrevDataPos(SCROW& rRow) const
1402 BOOL bFound = FALSE;
1403 SCSIZE i = nCount;
1404 while (!bFound && (i > 0))
1406 --i;
1407 bFound = (pItems[i].nRow < rRow);
1408 if (bFound)
1409 rRow = pItems[i].nRow;
1411 return bFound;
1414 BOOL ScColumn::GetNextDataPos(SCROW& rRow) const // groesser als rRow
1416 SCSIZE nIndex;
1417 if (Search( rRow, nIndex ))
1418 ++nIndex; // naechste Zelle
1420 BOOL bMore = ( nIndex < nCount );
1421 if ( bMore )
1422 rRow = pItems[nIndex].nRow;
1423 return bMore;
1426 void ScColumn::FindDataAreaPos(SCROW& rRow, long nMovY) const
1428 if (!nMovY) return;
1429 BOOL bForward = (nMovY>0);
1431 SCSIZE nIndex;
1432 BOOL bThere = Search(rRow, nIndex);
1433 if (bThere && pItems[nIndex].pCell->IsBlank())
1434 bThere = FALSE;
1436 if (bThere)
1438 SCROW nLast = rRow;
1439 SCSIZE nOldIndex = nIndex;
1440 if (bForward)
1442 if (nIndex<nCount-1)
1444 ++nIndex;
1445 while (nIndex<nCount-1 && pItems[nIndex].nRow==nLast+1
1446 && !pItems[nIndex].pCell->IsBlank())
1448 ++nIndex;
1449 ++nLast;
1451 if (nIndex==nCount-1)
1452 if (pItems[nIndex].nRow==nLast+1 && !pItems[nIndex].pCell->IsBlank())
1453 ++nLast;
1456 else
1458 if (nIndex>0)
1460 --nIndex;
1461 while (nIndex>0 && pItems[nIndex].nRow+1==nLast
1462 && !pItems[nIndex].pCell->IsBlank())
1464 --nIndex;
1465 --nLast;
1467 if (nIndex==0)
1468 if (pItems[nIndex].nRow+1==nLast && !pItems[nIndex].pCell->IsBlank())
1469 --nLast;
1472 if (nLast==rRow)
1474 bThere = FALSE;
1475 nIndex = bForward ? nOldIndex+1 : nOldIndex;
1477 else
1478 rRow = nLast;
1481 if (!bThere)
1483 if (bForward)
1485 while (nIndex<nCount && pItems[nIndex].pCell->IsBlank())
1486 ++nIndex;
1487 if (nIndex<nCount)
1488 rRow = pItems[nIndex].nRow;
1489 else
1490 rRow = MAXROW;
1492 else
1494 while (nIndex>0 && pItems[nIndex-1].pCell->IsBlank())
1495 --nIndex;
1496 if (nIndex>0)
1497 rRow = pItems[nIndex-1].nRow;
1498 else
1499 rRow = 0;
1504 BOOL ScColumn::HasDataAt(SCROW nRow) const
1506 /* SCSIZE nIndex;
1507 return Search( nRow, nIndex );
1509 // immer nur sichtbare interessant ?
1510 //! dann HasVisibleDataAt raus
1512 SCSIZE nIndex;
1513 if (Search(nRow, nIndex))
1514 if (!pItems[nIndex].pCell->IsBlank())
1515 return TRUE;
1517 return FALSE;
1521 BOOL ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1523 if (pAttrArray && rCol.pAttrArray)
1524 return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1525 else
1526 return !pAttrArray && !rCol.pAttrArray;
1529 BOOL ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
1531 if (pAttrArray && rCol.pAttrArray)
1532 return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
1533 else
1534 return !pAttrArray && !rCol.pAttrArray;
1537 BOOL ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1539 if (pAttrArray)
1540 return pAttrArray->GetFirstVisibleAttr( rFirstRow );
1541 else
1542 return FALSE;
1545 BOOL ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
1547 if (pAttrArray)
1549 // row of last cell is needed
1550 SCROW nLastData = GetLastVisDataPos( TRUE ); // always including notes, 0 if none
1552 return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
1554 else
1555 return FALSE;
1558 BOOL ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1560 if (pAttrArray)
1561 return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
1562 else
1563 return FALSE;
1566 void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, BOOL* pUsed ) const
1568 SCROW nRow = 0;
1569 SCSIZE nIndex;
1570 Search( nStartRow, nIndex );
1571 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
1573 pUsed[nRow-nStartRow] = TRUE;
1574 ++nIndex;
1578 void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
1580 SvtBroadcaster* pBC = NULL;
1581 ScBaseCell* pCell;
1583 SCSIZE nIndex;
1584 if (Search(nRow,nIndex))
1586 pCell = pItems[nIndex].pCell;
1587 pBC = pCell->GetBroadcaster();
1589 else
1591 pCell = new ScNoteCell;
1592 Insert(nRow, pCell);
1595 if (!pBC)
1597 pBC = new SvtBroadcaster;
1598 pCell->TakeBroadcaster(pBC);
1600 rLst.StartListening(*pBC);
1603 void ScColumn::MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow )
1605 SvtBroadcaster* pBC = NULL;
1606 ScBaseCell* pCell;
1608 SCSIZE nIndex;
1609 if (Search(nDestRow,nIndex))
1611 pCell = pItems[nIndex].pCell;
1612 pBC = pCell->GetBroadcaster();
1614 else
1616 pCell = new ScNoteCell;
1617 Insert(nDestRow, pCell);
1620 if (!pBC)
1622 pBC = new SvtBroadcaster;
1623 pCell->TakeBroadcaster(pBC);
1626 if (rSource.HasListeners())
1628 SvtListenerIter aIter( rSource);
1629 for (SvtListener* pLst = aIter.GoStart(); pLst; pLst = aIter.GoNext())
1631 pLst->StartListening( *pBC);
1632 pLst->EndListening( rSource);
1637 void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
1639 SCSIZE nIndex;
1640 if (Search(nRow,nIndex))
1642 ScBaseCell* pCell = pItems[nIndex].pCell;
1643 SvtBroadcaster* pBC = pCell->GetBroadcaster();
1644 if (pBC)
1646 rLst.EndListening(*pBC);
1648 if (!pBC->HasListeners())
1650 if (pCell->IsBlank())
1651 DeleteAtIndex(nIndex);
1652 else
1653 pCell->DeleteBroadcaster();
1656 // else
1657 // DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
1659 // else
1660 // DBG_ERROR("ScColumn::EndListening - keine Zelle");
1663 void ScColumn::CompileDBFormula()
1665 if (pItems)
1666 for (SCSIZE i = 0; i < nCount; i++)
1668 ScBaseCell* pCell = pItems[i].pCell;
1669 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1670 ((ScFormulaCell*) pCell)->CompileDBFormula();
1674 void ScColumn::CompileDBFormula( BOOL bCreateFormulaString )
1676 if (pItems)
1677 for (SCSIZE i = 0; i < nCount; i++)
1679 ScBaseCell* pCell = pItems[i].pCell;
1680 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1681 ((ScFormulaCell*) pCell)->CompileDBFormula( bCreateFormulaString );
1685 void ScColumn::CompileNameFormula( BOOL bCreateFormulaString )
1687 if (pItems)
1688 for (SCSIZE i = 0; i < nCount; i++)
1690 ScBaseCell* pCell = pItems[i].pCell;
1691 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1692 ((ScFormulaCell*) pCell)->CompileNameFormula( bCreateFormulaString );
1696 void ScColumn::CompileColRowNameFormula()
1698 if (pItems)
1699 for (SCSIZE i = 0; i < nCount; i++)
1701 ScBaseCell* pCell = pItems[i].pCell;
1702 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1703 ((ScFormulaCell*) pCell)->CompileColRowNameFormula();
1707 void lcl_UpdateSubTotal( ScFunctionData& rData, ScBaseCell* pCell )
1709 double nValue = 0.0;
1710 BOOL bVal = FALSE;
1711 BOOL bCell = TRUE;
1712 switch (pCell->GetCellType())
1714 case CELLTYPE_VALUE:
1715 nValue = ((ScValueCell*)pCell)->GetValue();
1716 bVal = TRUE;
1717 break;
1718 case CELLTYPE_FORMULA:
1720 if ( rData.eFunc != SUBTOTAL_FUNC_CNT2 ) // da interessiert's nicht
1722 ScFormulaCell* pFC = (ScFormulaCell*)pCell;
1723 if ( pFC->GetErrCode() )
1725 if ( rData.eFunc != SUBTOTAL_FUNC_CNT ) // fuer Anzahl einfach weglassen
1726 rData.bError = TRUE;
1728 else if (pFC->IsValue())
1730 nValue = pFC->GetValue();
1731 bVal = TRUE;
1733 // sonst Text
1736 break;
1737 case CELLTYPE_NOTE:
1738 bCell = FALSE;
1739 break;
1740 // bei Strings nichts
1741 default:
1743 // added to avoid warnings
1747 if (!rData.bError)
1749 switch (rData.eFunc)
1751 case SUBTOTAL_FUNC_SUM:
1752 case SUBTOTAL_FUNC_AVE:
1753 if (bVal)
1755 ++rData.nCount;
1756 if (!SubTotal::SafePlus( rData.nVal, nValue ))
1757 rData.bError = TRUE;
1759 break;
1760 case SUBTOTAL_FUNC_CNT: // nur Werte
1761 if (bVal)
1762 ++rData.nCount;
1763 break;
1764 case SUBTOTAL_FUNC_CNT2: // alle
1765 if (bCell)
1766 ++rData.nCount;
1767 break;
1768 case SUBTOTAL_FUNC_MAX:
1769 if (bVal)
1770 if (++rData.nCount == 1 || nValue > rData.nVal )
1771 rData.nVal = nValue;
1772 break;
1773 case SUBTOTAL_FUNC_MIN:
1774 if (bVal)
1775 if (++rData.nCount == 1 || nValue < rData.nVal )
1776 rData.nVal = nValue;
1777 break;
1778 default:
1780 // added to avoid warnings
1786 // Mehrfachselektion:
1787 void ScColumn::UpdateSelectionFunction( const ScMarkData& rMark,
1788 ScFunctionData& rData,
1789 ScFlatBoolRowSegments& rHiddenRows,
1790 BOOL bDoExclude, SCROW nExStartRow, SCROW nExEndRow )
1792 SCSIZE nIndex;
1793 ScMarkedDataIter aDataIter(this, &rMark, FALSE);
1794 while (aDataIter.Next( nIndex ))
1796 SCROW nRow = pItems[nIndex].nRow;
1797 bool bRowHidden = rHiddenRows.getValue(nRow);
1798 if ( !bRowHidden )
1799 if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
1800 lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1804 // bei bNoMarked die Mehrfachselektion weglassen
1805 void ScColumn::UpdateAreaFunction( ScFunctionData& rData,
1806 ScFlatBoolRowSegments& rHiddenRows,
1807 SCROW nStartRow, SCROW nEndRow )
1809 SCSIZE nIndex;
1810 Search( nStartRow, nIndex );
1811 while ( nIndex<nCount && pItems[nIndex].nRow<=nEndRow )
1813 SCROW nRow = pItems[nIndex].nRow;
1814 bool bRowHidden = rHiddenRows.getValue(nRow);
1815 if ( !bRowHidden )
1816 lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
1817 ++nIndex;
1821 ULONG ScColumn::GetWeightedCount() const
1823 ULONG nTotal = 0;
1825 // Notizen werden nicht gezaehlt
1827 for (SCSIZE i=0; i<nCount; i++)
1829 ScBaseCell* pCell = pItems[i].pCell;
1830 switch ( pCell->GetCellType() )
1832 case CELLTYPE_VALUE:
1833 case CELLTYPE_STRING:
1834 ++nTotal;
1835 break;
1836 case CELLTYPE_FORMULA:
1837 nTotal += 5 + ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1838 break;
1839 case CELLTYPE_EDIT:
1840 nTotal += 50;
1841 break;
1842 default:
1844 // added to avoid warnings
1849 return nTotal;
1852 ULONG ScColumn::GetCodeCount() const
1854 ULONG nCodeCount = 0;
1856 for (SCSIZE i=0; i<nCount; i++)
1858 ScBaseCell* pCell = pItems[i].pCell;
1859 if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1860 nCodeCount += ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
1863 return nCodeCount;