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>
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"
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"
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 // -----------------------------------------------------------------------------------------
96 // -----------------------------------------------------------------------------------------
98 //UNUSED2008-05 SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
100 //UNUSED2008-05 SCROW nNoteCount = 0;
101 //UNUSED2008-05 SCSIZE i;
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;
107 //UNUSED2008-05 return nNoteCount;
110 // -----------------------------------------------------------------------------------------
112 //UNUSED2008-05 void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
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)
118 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
119 //UNUSED2008-05 const ULONG nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
121 //UNUSED2008-05 BOOL bListInitialized = FALSE;
122 //UNUSED2008-05 ScSymbolStringCellEntry* pCurrentEntry = NULL;
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 )
129 //UNUSED2008-05 if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
130 //UNUSED2008-05 pAttr->IsSymbolFont() )
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 ) )
137 //UNUSED2008-05 if ( pCell->GetCellType() == CELLTYPE_STRING )
139 //UNUSED2008-05 List& rList = pDocument->GetLoadedSymbolStringCellsList();
140 //UNUSED2008-05 if (!bListInitialized)
142 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
143 //UNUSED2008-05 bListInitialized = TRUE;
146 //UNUSED2008-05 while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
147 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
149 //UNUSED2008-05 if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
151 //UNUSED2008-05 // found
155 //UNUSED2008-05 // not in list -> convert and put into list
157 //UNUSED2008-05 ScStringCell* pStrCell = (ScStringCell*)pCell;
158 //UNUSED2008-05 String aOldStr;
159 //UNUSED2008-05 pStrCell->GetString( aOldStr );
161 //UNUSED2008-05 // convert back to stream character set (get original data)
162 //UNUSED2008-05 ByteString aByteStr( aOldStr, eStreamCharSet );
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 );
168 //UNUSED2008-05 ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
169 //UNUSED2008-05 pEntry->pCell = pStrCell;
170 //UNUSED2008-05 pEntry->nRow = nRow;
172 //UNUSED2008-05 if ( pCurrentEntry )
173 //UNUSED2008-05 rList.Insert( pEntry ); // before current entry - pCurrentEntry stays valid
175 //UNUSED2008-05 rList.Insert( pEntry, LIST_APPEND ); // append if already behind last entry
181 //UNUSED2008-05 pAttr = aAttrIter.Next( nStt, nEnd );
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
)
196 double nPPT
= bWidth
? nPPTX
: nPPTY
;
197 if (Search(nRow
,nIndex
))
199 const ScPatternAttr
* pPattern
= rOptions
.pPattern
;
201 pPattern
= pAttrArray
->GetPattern( nRow
);
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
);
211 if ( pFlag
->IsHorOverlapped() )
213 if ( rOptions
.bSkipMerged
&& pMerge
->GetColMerge() > 1 )
218 if ( pFlag
->IsVerOverlapped() )
220 if ( rOptions
.bSkipMerged
&& pMerge
->GetRowMerge() > 1 )
224 // bedingte Formatierung
225 const SfxItemSet
* pCondSet
= NULL
;
226 if ( ((const SfxUInt32Item
&)pPattern
->GetItem(ATTR_CONDITIONAL
)).GetValue() )
227 pCondSet
= pDocument
->GetCondResult( nCol
, nRow
, nTab
);
231 const SfxPoolItem
* pCondItem
;
232 SvxCellHorJustify eHorJust
;
234 pCondSet
->GetItemState(ATTR_HOR_JUSTIFY
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
235 eHorJust
= (SvxCellHorJustify
)((const SvxHorJustifyItem
*)pCondItem
)->GetValue();
237 eHorJust
= (SvxCellHorJustify
)((const SvxHorJustifyItem
&)
238 pPattern
->GetItem( ATTR_HOR_JUSTIFY
)).GetValue();
240 if ( eHorJust
== SVX_HOR_JUSTIFY_BLOCK
)
242 else if ( pCondSet
&&
243 pCondSet
->GetItemState(ATTR_LINEBREAK
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
244 bBreak
= ((const SfxBoolItem
*)pCondItem
)->GetValue();
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
)
256 if ( bWidth
&& bBreak
) // after determining bAsianVertical (bBreak may be reset)
260 SvxRotateMode eRotMode
= SVX_ROTATE_MODE_STANDARD
;
261 if ( eOrient
== SVX_ORIENTATION_STANDARD
)
264 pCondSet
->GetItemState(ATTR_ROTATE_VALUE
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
265 nRotate
= ((const SfxInt32Item
*)pCondItem
)->GetValue();
267 nRotate
= ((const SfxInt32Item
&)pPattern
->GetItem(ATTR_ROTATE_VALUE
)).GetValue();
271 pCondSet
->GetItemState(ATTR_ROTATE_MODE
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
272 eRotMode
= (SvxRotateMode
)((const SvxRotateModeItem
*)pCondItem
)->GetValue();
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
;
287 bAsianVertical
= FALSE
;
290 const SvxMarginItem
* pMargin
;
292 pCondSet
->GetItemState(ATTR_MARGIN
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
293 pMargin
= (const SvxMarginItem
*) pCondItem
;
295 pMargin
= (const SvxMarginItem
*) &pPattern
->GetItem(ATTR_MARGIN
);
297 if ( eHorJust
== SVX_HOR_JUSTIFY_LEFT
)
300 pCondSet
->GetItemState(ATTR_INDENT
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
301 nIndent
= ((const SfxUInt16Item
*)pCondItem
)->GetValue();
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
;
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
333 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
334 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
, pCondSet
);
335 ScCellFormat::GetString( pCell
, nFormat
, aValStr
, &pColor
,
337 TRUE
, rOptions
.bFormula
, ftCheck
);
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
;
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
);
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
);
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
);
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
)
381 aSize
= Size( nWidth
, nHeight
);
383 nValue
= bWidth
? aSize
.Width() : aSize
.Height();
389 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
390 (long) ( pMargin
->GetRightMargin() * nPPT
);
392 nValue
+= (long) ( nIndent
* nPPT
);
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() -
410 nDocPixel
= (nDocPixel
* 9) / 10; // zur Sicherheit
411 if ( aSize
.Width() > nDocPixel
)
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
)
451 double fWidthFactor
= nPPTX
;
452 BOOL bTextWysiwyg
= ( pDev
->GetOutDevType() == OUTDEV_PRINTER
);
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();
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)
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
;
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
);
494 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
495 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
, pCondSet
);
497 ScCellFormat::GetString( pCell
, nFormat
, aString
, &pColor
,
499 TRUE
, rOptions
.bFormula
, ftCheck
);
501 pEngine
->SetTextNewDefaults(aString
, pSet
);
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
;
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
);
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
);
529 if ( pPattern
->GetRotateDir( pCondSet
) == SC_ROTDIR_RIGHT
)
530 nWidth
+= (long)( pDocument
->GetRowHeight( nRow
,nTab
) *
531 nPPT
* nCosAbs
/ nSinAbs
);
534 nWidth
= (long)( aSize
.Height() / nSinAbs
); //! begrenzen?
535 aSize
= Size( nWidth
, nHeight
);
537 Size aPixSize
= pDev
->LogicToPixel( aSize
, aHMMMode
);
539 nValue
= aPixSize
.Width();
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
;
558 nValue
= pDev
->LogicToPixel(Size( pEngine
->CalcTextWidth(), 0 ),
563 nValue
= pDev
->LogicToPixel(Size( 0, pEngine
->GetTextHeight() ),
567 if ( nValue
&& bAddMargin
)
571 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
572 (long) ( pMargin
->GetRightMargin() * nPPT
);
574 nValue
+= (long) ( nIndent
* nPPT
);
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
);
600 // Platz fuer Autofilter-Button
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();
612 long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex
, OutputDevice
* pDev
,
616 if ( nIndex
< nCount
)
618 SCROW nRow
= pItems
[nIndex
].nRow
;
619 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
620 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
623 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
624 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
);
625 ScCellFormat::GetString( pCell
, nFormat
, aValStr
, &pColor
,
626 *pFormatter
, TRUE
, FALSE
, ftCheck
);
630 nValue
= pDev
->GetTextWidth( aValStr
);
632 nValue
= pDev
->GetTextHeight();
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
)
647 USHORT nWidth
= (USHORT
) (nOldWidth
* nPPTX
);
651 ScMarkedDataIter
aDataIter(this, pMarkData
, TRUE
);
652 if ( bSimpleTextImport
)
653 { // alles eins bis auf NumberFormate
654 const ScPatternAttr
* pPattern
= GetPattern( 0 );
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
,
669 if (nThis
>nWidth
|| !bFound
)
679 ScNeededSizeOptions aOptions
;
680 aOptions
.bFormula
= bFormula
;
681 const ScPatternAttr
* pOldPattern
= NULL
;
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
;
699 if (nThis
>nWidth
|| !bFound
)
711 USHORT nTwips
= (USHORT
) (nWidth
/ nPPTX
);
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;
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
);
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();
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
,
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
);
767 // bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
769 const ScPatternAttr
* pPattern
= aIter
.Next(nStart
,nEnd
);
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
783 BOOL bStdAllowed
= (pPattern
->GetCellOrientation() == SVX_ORIENTATION_STANDARD
);
784 BOOL bStdOnly
= FALSE
;
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
);
793 // bedingte Formatierung: Zellen durchgehen
794 if ( bStdOnly
&& ((const SfxUInt32Item
&)pPattern
->
795 GetItem(ATTR_CONDITIONAL
)).GetValue() )
798 // gedrehter Text: Zellen durchgehen
799 if ( bStdOnly
&& ((const SfxInt32Item
&)pPattern
->
800 GetItem(ATTR_ROTATE_VALUE
)).GetValue() )
805 if (HasEditCells(nStart
,nEnd
,nEditPos
)) // includes mixed script types
807 if (nEditPos
== nStart
)
812 nEnd
= nEditPos
; // einzeln ausrechnen
813 bStdAllowed
= FALSE
; // wird auf jeden Fall per Zelle berechnet
818 nEnd
= nEditPos
- 1; // Standard - Teil
824 USHORT nLatHeight
= 0;
825 USHORT nCjkHeight
= 0;
826 USHORT nCtlHeight
= 0;
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
);
834 nDefHeight
= nLatHeight
= lcl_GetAttribHeight( *pPattern
, ATTR_FONT_HEIGHT
);
836 // if everything below is already larger, the loop doesn't have to
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
;
848 // if cells are not handled individually below,
849 // check for cells with different script type
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
;
874 if ( nLatHeight
== 0 )
875 nLatHeight
= lcl_GetAttribHeight( *pPattern
, ATTR_FONT_HEIGHT
);
876 if (nLatHeight
> pHeight
[nRow
-nStartRow
])
877 pHeight
[nRow
-nStartRow
] = nLatHeight
;
885 if (!bStdOnly
) // belegte Zellen suchen
887 ScNeededSizeOptions aOptions
;
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
;
916 pPattern
= aIter
.Next(nStart
,nEnd
);
920 BOOL
ScColumn::GetNextSpellingCell(SCROW
& nRow
, BOOL bInSel
, const ScMarkData
& rData
) const
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
)) )
937 nRow
= rData
.GetNextMarked(nCol
, nRow
, FALSE
);
945 eCellType
= GetCellType(nRow
);
946 if ( (eCellType
== CELLTYPE_STRING
|| eCellType
== CELLTYPE_EDIT
) &&
947 !(HasAttrib( nRow
, nRow
, HASATTR_PROTECTED
) &&
948 pDocument
->IsTabProtected(nTab
)) )
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
)) )
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
993 // auf Attribute testen
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() );
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
;
1018 void ScColumn::RemoveEditAttribs( SCROW nStartRow
, SCROW nEndRow
)
1020 ScFieldEditEngine
* pEngine
= NULL
;
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
1036 // auf Attribute testen
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
);
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() );
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
;
1090 // =========================================================================================
1092 BOOL
ScColumn::TestTabRefAbs(SCTAB nTable
)
1096 for (SCSIZE i
= 0; i
< nCount
; i
++)
1097 if ( pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1098 if (((ScFormulaCell
*)pItems
[i
].pCell
)->TestTabRefAbs(nTable
))
1103 // =========================================================================================
1105 ScColumnIterator::ScColumnIterator( const ScColumn
* pCol
, SCROW nStart
, SCROW 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
;
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
,
1149 if (pMarkData
&& pMarkData
->IsMultiMarked())
1150 pMarkIter
= new ScMarkArrayIter( pMarkData
->GetArray() + pCol
->GetCol() );
1153 ScMarkedDataIter::~ScMarkedDataIter()
1158 BOOL
ScMarkedDataIter::Next( SCSIZE
& rIndex
)
1160 BOOL bFound
= FALSE
;
1165 if (!pMarkIter
|| !pMarkIter
->Next( nTop
, nBottom
))
1167 if (bAll
) // ganze Spalte
1175 pColumn
->Search( nTop
, nPos
);
1177 bAll
= FALSE
; // nur beim ersten Versuch
1180 if ( nPos
>= pColumn
->nCount
)
1183 if ( pColumn
->pItems
[nPos
].nRow
<= nBottom
)
1194 //UNUSED2009-05 USHORT ScColumn::GetErrorData( SCROW nRow ) const
1196 //UNUSED2009-05 SCSIZE nIndex;
1197 //UNUSED2009-05 if (Search(nRow, nIndex))
1199 //UNUSED2009-05 ScBaseCell* pCell = pItems[nIndex].pCell;
1200 //UNUSED2009-05 switch (pCell->GetCellType())
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;
1209 //UNUSED2009-05 return 0;
1214 BOOL
ScColumn::IsEmptyData() const
1216 return (nCount
== 0);
1219 BOOL
ScColumn::IsEmptyVisData(BOOL bNotes
) const
1221 if (!pItems
|| nCount
== 0)
1225 BOOL bVisData
= FALSE
;
1227 for (i
=0; i
<nCount
&& !bVisData
; i
++)
1229 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1230 if ( pCell
->GetCellType() != CELLTYPE_NOTE
|| (bNotes
&& pCell
->HasNote()) )
1237 SCSIZE
ScColumn::VisibleCount( SCROW nStartRow
, SCROW nEndRow
) const
1239 // Notizen werden nicht mitgezaehlt
1241 SCSIZE nVisCount
= 0;
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
)
1256 SCROW
ScColumn::GetLastVisDataPos(BOOL bNotes
) const
1262 BOOL bFound
= FALSE
;
1263 for (i
=nCount
; i
>0 && !bFound
; )
1266 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1267 if ( pCell
->GetCellType() != CELLTYPE_NOTE
|| (bNotes
&& pCell
->HasNote()) )
1270 nRet
= pItems
[i
].nRow
;
1277 SCROW
ScColumn::GetFirstVisDataPos(BOOL bNotes
) const
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()) )
1290 nRet
= pItems
[i
].nRow
;
1297 BOOL
ScColumn::HasVisibleDataAt(SCROW nRow
) const
1300 if (Search(nRow
, nIndex
))
1301 if (!pItems
[nIndex
].pCell
->IsBlank())
1307 BOOL
ScColumn::IsEmptyAttr() const
1310 return pAttrArray
->IsEmpty();
1315 BOOL
ScColumn::IsEmpty() const
1317 return (IsEmptyData() && IsEmptyAttr());
1320 BOOL
ScColumn::IsEmptyBlock(SCROW nStartRow
, SCROW nEndRow
, bool bIgnoreNotes
) const
1323 if (pAttrArray
->HasLines(nStartRow
, nEndRow
, aRect
, TRUE
, TRUE
))
1326 if ( nCount
== 0 || !pItems
)
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
1337 return TRUE
; // no cell found
1340 SCSIZE
ScColumn::GetEmptyLinesInBlock( SCROW nStartRow
, SCROW nEndRow
, ScDirection eDir
) const
1343 BOOL bFound
= FALSE
;
1345 if (pItems
&& (nCount
> 0))
1347 if (eDir
== DIR_BOTTOM
)
1350 while (!bFound
&& (i
> 0))
1353 if ( pItems
[i
].nRow
< nStartRow
)
1355 bFound
= pItems
[i
].nRow
<= nEndRow
&& !pItems
[i
].pCell
->IsBlank();
1358 nLines
= static_cast<SCSIZE
>(nEndRow
- pItems
[i
].nRow
);
1360 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1362 else if (eDir
== DIR_TOP
)
1365 while (!bFound
&& (i
< nCount
))
1367 if ( pItems
[i
].nRow
> nEndRow
)
1369 bFound
= pItems
[i
].nRow
>= nStartRow
&& !pItems
[i
].pCell
->IsBlank();
1373 nLines
= static_cast<SCSIZE
>(pItems
[i
-1].nRow
- nStartRow
);
1375 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1379 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1383 SCROW
ScColumn::GetFirstDataPos() const
1386 return pItems
[0].nRow
;
1391 SCROW
ScColumn::GetLastDataPos() const
1394 return pItems
[nCount
-1].nRow
;
1399 BOOL
ScColumn::GetPrevDataPos(SCROW
& rRow
) const
1401 BOOL bFound
= FALSE
;
1403 while (!bFound
&& (i
> 0))
1406 bFound
= (pItems
[i
].nRow
< rRow
);
1408 rRow
= pItems
[i
].nRow
;
1413 BOOL
ScColumn::GetNextDataPos(SCROW
& rRow
) const // groesser als rRow
1416 if (Search( rRow
, nIndex
))
1417 ++nIndex
; // naechste Zelle
1419 BOOL bMore
= ( nIndex
< nCount
);
1421 rRow
= pItems
[nIndex
].nRow
;
1425 void ScColumn::FindDataAreaPos(SCROW
& rRow
, long nMovY
) const
1428 BOOL bForward
= (nMovY
>0);
1431 BOOL bThere
= Search(rRow
, nIndex
);
1432 if (bThere
&& pItems
[nIndex
].pCell
->IsBlank())
1438 SCSIZE nOldIndex
= nIndex
;
1441 if (nIndex
<nCount
-1)
1444 while (nIndex
<nCount
-1 && pItems
[nIndex
].nRow
==nLast
+1
1445 && !pItems
[nIndex
].pCell
->IsBlank())
1450 if (nIndex
==nCount
-1)
1451 if (pItems
[nIndex
].nRow
==nLast
+1 && !pItems
[nIndex
].pCell
->IsBlank())
1460 while (nIndex
>0 && pItems
[nIndex
].nRow
+1==nLast
1461 && !pItems
[nIndex
].pCell
->IsBlank())
1467 if (pItems
[nIndex
].nRow
+1==nLast
&& !pItems
[nIndex
].pCell
->IsBlank())
1474 nIndex
= bForward
? nOldIndex
+1 : nOldIndex
;
1484 while (nIndex
<nCount
&& pItems
[nIndex
].pCell
->IsBlank())
1487 rRow
= pItems
[nIndex
].nRow
;
1493 while (nIndex
>0 && pItems
[nIndex
-1].pCell
->IsBlank())
1496 rRow
= pItems
[nIndex
-1].nRow
;
1503 BOOL
ScColumn::HasDataAt(SCROW nRow
) const
1506 return Search( nRow, nIndex );
1508 // immer nur sichtbare interessant ?
1509 //! dann HasVisibleDataAt raus
1512 if (Search(nRow
, nIndex
))
1513 if (!pItems
[nIndex
].pCell
->IsBlank())
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
);
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
);
1533 return !pAttrArray
&& !rCol
.pAttrArray
;
1536 BOOL
ScColumn::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
1539 return pAttrArray
->GetFirstVisibleAttr( rFirstRow
);
1544 BOOL
ScColumn::GetLastVisibleAttr( SCROW
& rLastRow
) const
1548 // row of last cell is needed
1549 SCROW nLastData
= GetLastVisDataPos( TRUE
); // always including notes, 0 if none
1551 return pAttrArray
->GetLastVisibleAttr( rLastRow
, nLastData
);
1557 BOOL
ScColumn::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
1560 return pAttrArray
->HasVisibleAttrIn( nStartRow
, nEndRow
);
1565 void ScColumn::FindUsed( SCROW nStartRow
, SCROW nEndRow
, BOOL
* pUsed
) const
1569 Search( nStartRow
, nIndex
);
1570 while ( (nIndex
< nCount
) ? ((nRow
=pItems
[nIndex
].nRow
) <= nEndRow
) : FALSE
)
1572 pUsed
[nRow
-nStartRow
] = TRUE
;
1577 void ScColumn::StartListening( SvtListener
& rLst
, SCROW nRow
)
1579 SvtBroadcaster
* pBC
= NULL
;
1583 if (Search(nRow
,nIndex
))
1585 pCell
= pItems
[nIndex
].pCell
;
1586 pBC
= pCell
->GetBroadcaster();
1590 pCell
= new ScNoteCell
;
1591 Insert(nRow
, pCell
);
1596 pBC
= new SvtBroadcaster
;
1597 pCell
->TakeBroadcaster(pBC
);
1599 rLst
.StartListening(*pBC
);
1602 void ScColumn::MoveListeners( SvtBroadcaster
& rSource
, SCROW nDestRow
)
1604 SvtBroadcaster
* pBC
= NULL
;
1608 if (Search(nDestRow
,nIndex
))
1610 pCell
= pItems
[nIndex
].pCell
;
1611 pBC
= pCell
->GetBroadcaster();
1615 pCell
= new ScNoteCell
;
1616 Insert(nDestRow
, pCell
);
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
)
1639 if (Search(nRow
,nIndex
))
1641 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1642 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
1645 rLst
.EndListening(*pBC
);
1647 if (!pBC
->HasListeners())
1649 if (pCell
->IsBlank())
1650 DeleteAtIndex(nIndex
);
1652 pCell
->DeleteBroadcaster();
1656 // DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
1659 // DBG_ERROR("ScColumn::EndListening - keine Zelle");
1662 void ScColumn::CompileDBFormula()
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
)
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
)
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()
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;
1711 switch (pCell
->GetCellType())
1713 case CELLTYPE_VALUE
:
1714 nValue
= ((ScValueCell
*)pCell
)->GetValue();
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();
1739 // bei Strings nichts
1742 // added to avoid warnings
1748 switch (rData
.eFunc
)
1750 case SUBTOTAL_FUNC_SUM
:
1751 case SUBTOTAL_FUNC_AVE
:
1755 if (!SubTotal::SafePlus( rData
.nVal
, nValue
))
1756 rData
.bError
= TRUE
;
1759 case SUBTOTAL_FUNC_CNT
: // nur Werte
1763 case SUBTOTAL_FUNC_CNT2
: // alle
1767 case SUBTOTAL_FUNC_MAX
:
1769 if (++rData
.nCount
== 1 || nValue
> rData
.nVal
)
1770 rData
.nVal
= nValue
;
1772 case SUBTOTAL_FUNC_MIN
:
1774 if (++rData
.nCount
== 1 || nValue
< rData
.nVal
)
1775 rData
.nVal
= nValue
;
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
)
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
)
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
);
1818 ULONG
ScColumn::GetWeightedCount() const
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
:
1833 case CELLTYPE_FORMULA
:
1834 nTotal
+= 5 + ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen();
1841 // added to avoid warnings
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();