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"
72 #include "segmenttree.hxx"
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 // -----------------------------------------------------------------------------------------
97 // -----------------------------------------------------------------------------------------
99 //UNUSED2008-05 SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
101 //UNUSED2008-05 SCROW nNoteCount = 0;
102 //UNUSED2008-05 SCSIZE i;
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;
108 //UNUSED2008-05 return nNoteCount;
111 // -----------------------------------------------------------------------------------------
113 //UNUSED2008-05 void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
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)
119 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
120 //UNUSED2008-05 const ULONG nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
122 //UNUSED2008-05 BOOL bListInitialized = FALSE;
123 //UNUSED2008-05 ScSymbolStringCellEntry* pCurrentEntry = NULL;
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 )
130 //UNUSED2008-05 if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
131 //UNUSED2008-05 pAttr->IsSymbolFont() )
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 ) )
138 //UNUSED2008-05 if ( pCell->GetCellType() == CELLTYPE_STRING )
140 //UNUSED2008-05 List& rList = pDocument->GetLoadedSymbolStringCellsList();
141 //UNUSED2008-05 if (!bListInitialized)
143 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
144 //UNUSED2008-05 bListInitialized = TRUE;
147 //UNUSED2008-05 while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
148 //UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
150 //UNUSED2008-05 if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
152 //UNUSED2008-05 // found
156 //UNUSED2008-05 // not in list -> convert and put into list
158 //UNUSED2008-05 ScStringCell* pStrCell = (ScStringCell*)pCell;
159 //UNUSED2008-05 String aOldStr;
160 //UNUSED2008-05 pStrCell->GetString( aOldStr );
162 //UNUSED2008-05 // convert back to stream character set (get original data)
163 //UNUSED2008-05 ByteString aByteStr( aOldStr, eStreamCharSet );
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 );
169 //UNUSED2008-05 ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
170 //UNUSED2008-05 pEntry->pCell = pStrCell;
171 //UNUSED2008-05 pEntry->nRow = nRow;
173 //UNUSED2008-05 if ( pCurrentEntry )
174 //UNUSED2008-05 rList.Insert( pEntry ); // before current entry - pCurrentEntry stays valid
176 //UNUSED2008-05 rList.Insert( pEntry, LIST_APPEND ); // append if already behind last entry
182 //UNUSED2008-05 pAttr = aAttrIter.Next( nStt, nEnd );
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
)
197 double nPPT
= bWidth
? nPPTX
: nPPTY
;
198 if (Search(nRow
,nIndex
))
200 const ScPatternAttr
* pPattern
= rOptions
.pPattern
;
202 pPattern
= pAttrArray
->GetPattern( nRow
);
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
);
212 if ( pFlag
->IsHorOverlapped() )
214 if ( rOptions
.bSkipMerged
&& pMerge
->GetColMerge() > 1 )
219 if ( pFlag
->IsVerOverlapped() )
221 if ( rOptions
.bSkipMerged
&& pMerge
->GetRowMerge() > 1 )
225 // bedingte Formatierung
226 const SfxItemSet
* pCondSet
= NULL
;
227 if ( ((const SfxUInt32Item
&)pPattern
->GetItem(ATTR_CONDITIONAL
)).GetValue() )
228 pCondSet
= pDocument
->GetCondResult( nCol
, nRow
, nTab
);
232 const SfxPoolItem
* pCondItem
;
233 SvxCellHorJustify eHorJust
;
235 pCondSet
->GetItemState(ATTR_HOR_JUSTIFY
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
236 eHorJust
= (SvxCellHorJustify
)((const SvxHorJustifyItem
*)pCondItem
)->GetValue();
238 eHorJust
= (SvxCellHorJustify
)((const SvxHorJustifyItem
&)
239 pPattern
->GetItem( ATTR_HOR_JUSTIFY
)).GetValue();
241 if ( eHorJust
== SVX_HOR_JUSTIFY_BLOCK
)
243 else if ( pCondSet
&&
244 pCondSet
->GetItemState(ATTR_LINEBREAK
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
245 bBreak
= ((const SfxBoolItem
*)pCondItem
)->GetValue();
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
)
257 if ( bWidth
&& bBreak
) // after determining bAsianVertical (bBreak may be reset)
261 SvxRotateMode eRotMode
= SVX_ROTATE_MODE_STANDARD
;
262 if ( eOrient
== SVX_ORIENTATION_STANDARD
)
265 pCondSet
->GetItemState(ATTR_ROTATE_VALUE
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
266 nRotate
= ((const SfxInt32Item
*)pCondItem
)->GetValue();
268 nRotate
= ((const SfxInt32Item
&)pPattern
->GetItem(ATTR_ROTATE_VALUE
)).GetValue();
272 pCondSet
->GetItemState(ATTR_ROTATE_MODE
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
273 eRotMode
= (SvxRotateMode
)((const SvxRotateModeItem
*)pCondItem
)->GetValue();
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
;
288 bAsianVertical
= FALSE
;
291 const SvxMarginItem
* pMargin
;
293 pCondSet
->GetItemState(ATTR_MARGIN
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
294 pMargin
= (const SvxMarginItem
*) pCondItem
;
296 pMargin
= (const SvxMarginItem
*) &pPattern
->GetItem(ATTR_MARGIN
);
298 if ( eHorJust
== SVX_HOR_JUSTIFY_LEFT
)
301 pCondSet
->GetItemState(ATTR_INDENT
, TRUE
, &pCondItem
) == SFX_ITEM_SET
)
302 nIndent
= ((const SfxUInt16Item
*)pCondItem
)->GetValue();
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
;
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
334 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
335 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
, pCondSet
);
336 ScCellFormat::GetString( pCell
, nFormat
, aValStr
, &pColor
,
338 TRUE
, rOptions
.bFormula
, ftCheck
);
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
;
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
);
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
);
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
);
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
)
382 aSize
= Size( nWidth
, nHeight
);
384 nValue
= bWidth
? aSize
.Width() : aSize
.Height();
390 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
391 (long) ( pMargin
->GetRightMargin() * nPPT
);
393 nValue
+= (long) ( nIndent
* nPPT
);
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() -
411 nDocPixel
= (nDocPixel
* 9) / 10; // zur Sicherheit
412 if ( aSize
.Width() > nDocPixel
)
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
)
452 double fWidthFactor
= nPPTX
;
453 BOOL bTextWysiwyg
= ( pDev
->GetOutDevType() == OUTDEV_PRINTER
);
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();
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)
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
;
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
);
495 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
496 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
, pCondSet
);
498 ScCellFormat::GetString( pCell
, nFormat
, aString
, &pColor
,
500 TRUE
, rOptions
.bFormula
, ftCheck
);
502 pEngine
->SetTextNewDefaults(aString
, pSet
);
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
;
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
);
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
);
530 if ( pPattern
->GetRotateDir( pCondSet
) == SC_ROTDIR_RIGHT
)
531 nWidth
+= (long)( pDocument
->GetRowHeight( nRow
,nTab
) *
532 nPPT
* nCosAbs
/ nSinAbs
);
535 nWidth
= (long)( aSize
.Height() / nSinAbs
); //! begrenzen?
536 aSize
= Size( nWidth
, nHeight
);
538 Size aPixSize
= pDev
->LogicToPixel( aSize
, aHMMMode
);
540 nValue
= aPixSize
.Width();
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
;
559 nValue
= pDev
->LogicToPixel(Size( pEngine
->CalcTextWidth(), 0 ),
564 nValue
= pDev
->LogicToPixel(Size( 0, pEngine
->GetTextHeight() ),
568 if ( nValue
&& bAddMargin
)
572 nValue
+= (long) ( pMargin
->GetLeftMargin() * nPPT
) +
573 (long) ( pMargin
->GetRightMargin() * nPPT
);
575 nValue
+= (long) ( nIndent
* nPPT
);
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
);
601 // Platz fuer Autofilter-Button
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();
613 long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex
, OutputDevice
* pDev
,
617 if ( nIndex
< nCount
)
619 SCROW nRow
= pItems
[nIndex
].nRow
;
620 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
621 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
624 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
625 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
);
626 ScCellFormat::GetString( pCell
, nFormat
, aValStr
, &pColor
,
627 *pFormatter
, TRUE
, FALSE
, ftCheck
);
631 nValue
= pDev
->GetTextWidth( aValStr
);
633 nValue
= pDev
->GetTextHeight();
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
)
648 USHORT nWidth
= (USHORT
) (nOldWidth
* nPPTX
);
652 ScMarkedDataIter
aDataIter(this, pMarkData
, TRUE
);
653 if ( bSimpleTextImport
)
654 { // alles eins bis auf NumberFormate
655 const ScPatternAttr
* pPattern
= GetPattern( 0 );
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
,
670 if (nThis
>nWidth
|| !bFound
)
680 ScNeededSizeOptions aOptions
;
681 aOptions
.bFormula
= bFormula
;
682 const ScPatternAttr
* pOldPattern
= NULL
;
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
;
700 if (nThis
>nWidth
|| !bFound
)
712 USHORT nTwips
= (USHORT
) (nWidth
/ nPPTX
);
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;
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
);
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();
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
,
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
);
768 // bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
770 const ScPatternAttr
* pPattern
= aIter
.Next(nStart
,nEnd
);
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
784 BOOL bStdAllowed
= (pPattern
->GetCellOrientation() == SVX_ORIENTATION_STANDARD
);
785 BOOL bStdOnly
= FALSE
;
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
);
794 // bedingte Formatierung: Zellen durchgehen
795 if ( bStdOnly
&& ((const SfxUInt32Item
&)pPattern
->
796 GetItem(ATTR_CONDITIONAL
)).GetValue() )
799 // gedrehter Text: Zellen durchgehen
800 if ( bStdOnly
&& ((const SfxInt32Item
&)pPattern
->
801 GetItem(ATTR_ROTATE_VALUE
)).GetValue() )
806 if (HasEditCells(nStart
,nEnd
,nEditPos
)) // includes mixed script types
808 if (nEditPos
== nStart
)
813 nEnd
= nEditPos
; // einzeln ausrechnen
814 bStdAllowed
= FALSE
; // wird auf jeden Fall per Zelle berechnet
819 nEnd
= nEditPos
- 1; // Standard - Teil
825 USHORT nLatHeight
= 0;
826 USHORT nCjkHeight
= 0;
827 USHORT nCtlHeight
= 0;
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
);
835 nDefHeight
= nLatHeight
= lcl_GetAttribHeight( *pPattern
, ATTR_FONT_HEIGHT
);
837 // if everything below is already larger, the loop doesn't have to
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
;
849 // if cells are not handled individually below,
850 // check for cells with different script type
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
;
875 if ( nLatHeight
== 0 )
876 nLatHeight
= lcl_GetAttribHeight( *pPattern
, ATTR_FONT_HEIGHT
);
877 if (nLatHeight
> pHeight
[nRow
-nStartRow
])
878 pHeight
[nRow
-nStartRow
] = nLatHeight
;
886 if (!bStdOnly
) // belegte Zellen suchen
888 ScNeededSizeOptions aOptions
;
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
;
917 pPattern
= aIter
.Next(nStart
,nEnd
);
921 BOOL
ScColumn::GetNextSpellingCell(SCROW
& nRow
, BOOL bInSel
, const ScMarkData
& rData
) const
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
)) )
938 nRow
= rData
.GetNextMarked(nCol
, nRow
, FALSE
);
946 eCellType
= GetCellType(nRow
);
947 if ( (eCellType
== CELLTYPE_STRING
|| eCellType
== CELLTYPE_EDIT
) &&
948 !(HasAttrib( nRow
, nRow
, HASATTR_PROTECTED
) &&
949 pDocument
->IsTabProtected(nTab
)) )
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
)) )
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
994 // auf Attribute testen
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() );
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
;
1019 void ScColumn::RemoveEditAttribs( SCROW nStartRow
, SCROW nEndRow
)
1021 ScFieldEditEngine
* pEngine
= NULL
;
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
1037 // auf Attribute testen
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
);
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() );
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
;
1091 // =========================================================================================
1093 BOOL
ScColumn::TestTabRefAbs(SCTAB nTable
)
1097 for (SCSIZE i
= 0; i
< nCount
; i
++)
1098 if ( pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1099 if (((ScFormulaCell
*)pItems
[i
].pCell
)->TestTabRefAbs(nTable
))
1104 // =========================================================================================
1106 ScColumnIterator::ScColumnIterator( const ScColumn
* pCol
, SCROW nStart
, SCROW 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
;
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
,
1150 if (pMarkData
&& pMarkData
->IsMultiMarked())
1151 pMarkIter
= new ScMarkArrayIter( pMarkData
->GetArray() + pCol
->GetCol() );
1154 ScMarkedDataIter::~ScMarkedDataIter()
1159 BOOL
ScMarkedDataIter::Next( SCSIZE
& rIndex
)
1161 BOOL bFound
= FALSE
;
1166 if (!pMarkIter
|| !pMarkIter
->Next( nTop
, nBottom
))
1168 if (bAll
) // ganze Spalte
1176 pColumn
->Search( nTop
, nPos
);
1178 bAll
= FALSE
; // nur beim ersten Versuch
1181 if ( nPos
>= pColumn
->nCount
)
1184 if ( pColumn
->pItems
[nPos
].nRow
<= nBottom
)
1195 //UNUSED2009-05 USHORT ScColumn::GetErrorData( SCROW nRow ) const
1197 //UNUSED2009-05 SCSIZE nIndex;
1198 //UNUSED2009-05 if (Search(nRow, nIndex))
1200 //UNUSED2009-05 ScBaseCell* pCell = pItems[nIndex].pCell;
1201 //UNUSED2009-05 switch (pCell->GetCellType())
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;
1210 //UNUSED2009-05 return 0;
1215 BOOL
ScColumn::IsEmptyData() const
1217 return (nCount
== 0);
1220 BOOL
ScColumn::IsEmptyVisData(BOOL bNotes
) const
1222 if (!pItems
|| nCount
== 0)
1226 BOOL bVisData
= FALSE
;
1228 for (i
=0; i
<nCount
&& !bVisData
; i
++)
1230 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1231 if ( pCell
->GetCellType() != CELLTYPE_NOTE
|| (bNotes
&& pCell
->HasNote()) )
1238 SCSIZE
ScColumn::VisibleCount( SCROW nStartRow
, SCROW nEndRow
) const
1240 // Notizen werden nicht mitgezaehlt
1242 SCSIZE nVisCount
= 0;
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
)
1257 SCROW
ScColumn::GetLastVisDataPos(BOOL bNotes
) const
1263 BOOL bFound
= FALSE
;
1264 for (i
=nCount
; i
>0 && !bFound
; )
1267 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1268 if ( pCell
->GetCellType() != CELLTYPE_NOTE
|| (bNotes
&& pCell
->HasNote()) )
1271 nRet
= pItems
[i
].nRow
;
1278 SCROW
ScColumn::GetFirstVisDataPos(BOOL bNotes
) const
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()) )
1291 nRet
= pItems
[i
].nRow
;
1298 BOOL
ScColumn::HasVisibleDataAt(SCROW nRow
) const
1301 if (Search(nRow
, nIndex
))
1302 if (!pItems
[nIndex
].pCell
->IsBlank())
1308 BOOL
ScColumn::IsEmptyAttr() const
1311 return pAttrArray
->IsEmpty();
1316 BOOL
ScColumn::IsEmpty() const
1318 return (IsEmptyData() && IsEmptyAttr());
1321 BOOL
ScColumn::IsEmptyBlock(SCROW nStartRow
, SCROW nEndRow
, bool bIgnoreNotes
) const
1324 if (pAttrArray
->HasLines(nStartRow
, nEndRow
, aRect
, TRUE
, TRUE
))
1327 if ( nCount
== 0 || !pItems
)
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
1338 return TRUE
; // no cell found
1341 SCSIZE
ScColumn::GetEmptyLinesInBlock( SCROW nStartRow
, SCROW nEndRow
, ScDirection eDir
) const
1344 BOOL bFound
= FALSE
;
1346 if (pItems
&& (nCount
> 0))
1348 if (eDir
== DIR_BOTTOM
)
1351 while (!bFound
&& (i
> 0))
1354 if ( pItems
[i
].nRow
< nStartRow
)
1356 bFound
= pItems
[i
].nRow
<= nEndRow
&& !pItems
[i
].pCell
->IsBlank();
1359 nLines
= static_cast<SCSIZE
>(nEndRow
- pItems
[i
].nRow
);
1361 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1363 else if (eDir
== DIR_TOP
)
1366 while (!bFound
&& (i
< nCount
))
1368 if ( pItems
[i
].nRow
> nEndRow
)
1370 bFound
= pItems
[i
].nRow
>= nStartRow
&& !pItems
[i
].pCell
->IsBlank();
1374 nLines
= static_cast<SCSIZE
>(pItems
[i
-1].nRow
- nStartRow
);
1376 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1380 nLines
= static_cast<SCSIZE
>(nEndRow
- nStartRow
);
1384 SCROW
ScColumn::GetFirstDataPos() const
1387 return pItems
[0].nRow
;
1392 SCROW
ScColumn::GetLastDataPos() const
1395 return pItems
[nCount
-1].nRow
;
1400 BOOL
ScColumn::GetPrevDataPos(SCROW
& rRow
) const
1402 BOOL bFound
= FALSE
;
1404 while (!bFound
&& (i
> 0))
1407 bFound
= (pItems
[i
].nRow
< rRow
);
1409 rRow
= pItems
[i
].nRow
;
1414 BOOL
ScColumn::GetNextDataPos(SCROW
& rRow
) const // groesser als rRow
1417 if (Search( rRow
, nIndex
))
1418 ++nIndex
; // naechste Zelle
1420 BOOL bMore
= ( nIndex
< nCount
);
1422 rRow
= pItems
[nIndex
].nRow
;
1426 void ScColumn::FindDataAreaPos(SCROW
& rRow
, long nMovY
) const
1429 BOOL bForward
= (nMovY
>0);
1432 BOOL bThere
= Search(rRow
, nIndex
);
1433 if (bThere
&& pItems
[nIndex
].pCell
->IsBlank())
1439 SCSIZE nOldIndex
= nIndex
;
1442 if (nIndex
<nCount
-1)
1445 while (nIndex
<nCount
-1 && pItems
[nIndex
].nRow
==nLast
+1
1446 && !pItems
[nIndex
].pCell
->IsBlank())
1451 if (nIndex
==nCount
-1)
1452 if (pItems
[nIndex
].nRow
==nLast
+1 && !pItems
[nIndex
].pCell
->IsBlank())
1461 while (nIndex
>0 && pItems
[nIndex
].nRow
+1==nLast
1462 && !pItems
[nIndex
].pCell
->IsBlank())
1468 if (pItems
[nIndex
].nRow
+1==nLast
&& !pItems
[nIndex
].pCell
->IsBlank())
1475 nIndex
= bForward
? nOldIndex
+1 : nOldIndex
;
1485 while (nIndex
<nCount
&& pItems
[nIndex
].pCell
->IsBlank())
1488 rRow
= pItems
[nIndex
].nRow
;
1494 while (nIndex
>0 && pItems
[nIndex
-1].pCell
->IsBlank())
1497 rRow
= pItems
[nIndex
-1].nRow
;
1504 BOOL
ScColumn::HasDataAt(SCROW nRow
) const
1507 return Search( nRow, nIndex );
1509 // immer nur sichtbare interessant ?
1510 //! dann HasVisibleDataAt raus
1513 if (Search(nRow
, nIndex
))
1514 if (!pItems
[nIndex
].pCell
->IsBlank())
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
);
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
);
1534 return !pAttrArray
&& !rCol
.pAttrArray
;
1537 BOOL
ScColumn::GetFirstVisibleAttr( SCROW
& rFirstRow
) const
1540 return pAttrArray
->GetFirstVisibleAttr( rFirstRow
);
1545 BOOL
ScColumn::GetLastVisibleAttr( SCROW
& rLastRow
) const
1549 // row of last cell is needed
1550 SCROW nLastData
= GetLastVisDataPos( TRUE
); // always including notes, 0 if none
1552 return pAttrArray
->GetLastVisibleAttr( rLastRow
, nLastData
);
1558 BOOL
ScColumn::HasVisibleAttrIn( SCROW nStartRow
, SCROW nEndRow
) const
1561 return pAttrArray
->HasVisibleAttrIn( nStartRow
, nEndRow
);
1566 void ScColumn::FindUsed( SCROW nStartRow
, SCROW nEndRow
, BOOL
* pUsed
) const
1570 Search( nStartRow
, nIndex
);
1571 while ( (nIndex
< nCount
) ? ((nRow
=pItems
[nIndex
].nRow
) <= nEndRow
) : FALSE
)
1573 pUsed
[nRow
-nStartRow
] = TRUE
;
1578 void ScColumn::StartListening( SvtListener
& rLst
, SCROW nRow
)
1580 SvtBroadcaster
* pBC
= NULL
;
1584 if (Search(nRow
,nIndex
))
1586 pCell
= pItems
[nIndex
].pCell
;
1587 pBC
= pCell
->GetBroadcaster();
1591 pCell
= new ScNoteCell
;
1592 Insert(nRow
, pCell
);
1597 pBC
= new SvtBroadcaster
;
1598 pCell
->TakeBroadcaster(pBC
);
1600 rLst
.StartListening(*pBC
);
1603 void ScColumn::MoveListeners( SvtBroadcaster
& rSource
, SCROW nDestRow
)
1605 SvtBroadcaster
* pBC
= NULL
;
1609 if (Search(nDestRow
,nIndex
))
1611 pCell
= pItems
[nIndex
].pCell
;
1612 pBC
= pCell
->GetBroadcaster();
1616 pCell
= new ScNoteCell
;
1617 Insert(nDestRow
, pCell
);
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
)
1640 if (Search(nRow
,nIndex
))
1642 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
1643 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
1646 rLst
.EndListening(*pBC
);
1648 if (!pBC
->HasListeners())
1650 if (pCell
->IsBlank())
1651 DeleteAtIndex(nIndex
);
1653 pCell
->DeleteBroadcaster();
1657 // DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
1660 // DBG_ERROR("ScColumn::EndListening - keine Zelle");
1663 void ScColumn::CompileDBFormula()
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
)
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
)
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()
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;
1712 switch (pCell
->GetCellType())
1714 case CELLTYPE_VALUE
:
1715 nValue
= ((ScValueCell
*)pCell
)->GetValue();
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();
1740 // bei Strings nichts
1743 // added to avoid warnings
1749 switch (rData
.eFunc
)
1751 case SUBTOTAL_FUNC_SUM
:
1752 case SUBTOTAL_FUNC_AVE
:
1756 if (!SubTotal::SafePlus( rData
.nVal
, nValue
))
1757 rData
.bError
= TRUE
;
1760 case SUBTOTAL_FUNC_CNT
: // nur Werte
1764 case SUBTOTAL_FUNC_CNT2
: // alle
1768 case SUBTOTAL_FUNC_MAX
:
1770 if (++rData
.nCount
== 1 || nValue
> rData
.nVal
)
1771 rData
.nVal
= nValue
;
1773 case SUBTOTAL_FUNC_MIN
:
1775 if (++rData
.nCount
== 1 || nValue
< rData
.nVal
)
1776 rData
.nVal
= nValue
;
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
)
1793 ScMarkedDataIter
aDataIter(this, &rMark
, FALSE
);
1794 while (aDataIter
.Next( nIndex
))
1796 SCROW nRow
= pItems
[nIndex
].nRow
;
1797 bool bRowHidden
= rHiddenRows
.getValue(nRow
);
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
)
1810 Search( nStartRow
, nIndex
);
1811 while ( nIndex
<nCount
&& pItems
[nIndex
].nRow
<=nEndRow
)
1813 SCROW nRow
= pItems
[nIndex
].nRow
;
1814 bool bRowHidden
= rHiddenRows
.getValue(nRow
);
1816 lcl_UpdateSubTotal( rData
, pItems
[nIndex
].pCell
);
1821 ULONG
ScColumn::GetWeightedCount() const
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
:
1836 case CELLTYPE_FORMULA
:
1837 nTotal
+= 5 + ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen();
1844 // added to avoid warnings
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();