xref: /aoo42x/main/sc/inc/cell.hxx (revision b4df81e3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef SC_CELL_HXX
25 #define SC_CELL_HXX
26 
27 #include <stddef.h>
28 
29 #include <set>
30 #include <tools/mempool.hxx>
31 #include <svl/listener.hxx>
32 #include "global.hxx"
33 #include "rangenam.hxx"
34 #include "formula/grammar.hxx"
35 #include "tokenarray.hxx"
36 #include "formularesult.hxx"
37 #include <rtl/ustrbuf.hxx>
38 #include <unotools/fontcvt.hxx>
39 #include "scdllapi.h"
40 
41 #include <cellform.hxx>
42 
43 #define USE_MEMPOOL
44 #define TEXTWIDTH_DIRTY		0xffff
45 
46 // in addition to SCRIPTTYPE_... flags from scripttypeitem.hxx:
47 // set (in nScriptType) if type has not been determined yet
48 #define SC_SCRIPTTYPE_UNKNOWN	0x08
49 
50 class ScDocument;
51 class EditTextObject;
52 class ScMatrix;
53 class SvtBroadcaster;
54 class ScCodeArray;
55 class ScProgress;
56 class ScPostIt;
57 
58 // ============================================================================
59 
60 /** Default cell clone flags: do not start listening, do not adjust 3D refs to
61     old position, clone note captions of cell notes. */
62 const int SC_CLONECELL_DEFAULT          = 0x0000;
63 
64 /** If set, cloned formula cells will start to listen to the document. */
65 const int SC_CLONECELL_STARTLISTENING   = 0x0001;
66 
67 /** If set, relative 3D references of cloned formula cells will be adjusted to
68     old position (used while swapping cells for sorting a cell range). */
69 const int SC_CLONECELL_ADJUST3DREL      = 0x0002;
70 
71 /** If set, the caption object of a cell note will not be cloned (used while
72     copying cells to undo document, where captions are handled in drawing undo). */
73 const int SC_CLONECELL_NOCAPTION        = 0x0004;
74 
75 // ============================================================================
76 
77 class SC_DLLPUBLIC ScBaseCell
78 {
79 protected:
80 					~ScBaseCell();	// nicht virtuell -> darf nicht direkt aufgerufen werden
81 
82 public:
83     explicit        ScBaseCell( CellType eNewType );
84 
85     /** Base copy constructor. Does NOT clone cell note or broadcaster! */
86                     ScBaseCell( const ScBaseCell& rCell );
87 
88     /** Returns a clone of this cell at the same position, cell note and
89         broadcaster will not be cloned. */
90     ScBaseCell*     CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;
91 
92     /** Returns a clone of this cell for the passed document position, cell
93         note and broadcaster will not be cloned. */
94     ScBaseCell*     CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;
95 
96     /** Returns a clone of this cell, clones cell note and caption object too
97         (unless SC_CLONECELL_NOCAPTION flag is set). Broadcaster will not be cloned. */
98     ScBaseCell*     CloneWithNote( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const;
99 
100     /** Due to the fact that ScBaseCell does not have a vtable, this function
101         deletes the cell by calling the appropriate d'tor of the derived class. */
102     void            Delete();
103 
104     inline CellType GetCellType() const	{ return (CellType)eCellType; }
105 
106     /** Returns true, if the cell is empty (neither value nor formula nor cell note).
107         Returns false for formula cells returning nothing, use HasEmptyData() for that. */
108     bool            IsBlank( bool bIgnoreNotes = false ) const;
109 
110 // fuer Idle-Berechnung
111     inline sal_uInt16   GetTextWidth() const { return nTextWidth; }
112     inline void     SetTextWidth( sal_uInt16 nNew ) { nTextWidth = nNew; }
113 
114     inline sal_uInt8     GetScriptType() const { return nScriptType; }
115     inline void     SetScriptType( sal_uInt8 nNew ) { nScriptType = nNew; }
116 
117     /** Returns true, if the cell contains a note. */
118     inline bool     HasNote() const { return mpNote != 0; }
119     /** Returns the pointer to a cell note object (read-only). */
120     inline const ScPostIt* GetNote() const { return mpNote; }
121     /** Returns the pointer to a cell note object. */
122     inline ScPostIt* GetNote() { return mpNote; }
123     /** Takes ownership of the passed cell note object. */
124     void            TakeNote( ScPostIt* pNote );
125     /** Returns and forgets the own cell note object. Caller takes ownership! */
126     ScPostIt*       ReleaseNote();
127     /** Deletes the own cell note object. */
128     void            DeleteNote();
129 
130     /** Returns true, if the cell contains a broadcaster. */
131     inline bool     HasBroadcaster() const { return mpBroadcaster != 0; }
132     /** Returns the pointer to the cell broadcaster. */
133     inline SvtBroadcaster* GetBroadcaster() const { return mpBroadcaster; }
134     /** Takes ownership of the passed cell broadcaster. */
135     void            TakeBroadcaster( SvtBroadcaster* pBroadcaster );
136     /** Returns and forgets the own cell broadcaster. Caller takes ownership! */
137     SvtBroadcaster* ReleaseBroadcaster();
138     /** Deletes the own cell broadcaster. */
139     void            DeleteBroadcaster();
140 
141 						// String- oder EditCell
142 	static ScBaseCell* CreateTextCell( const String& rString, ScDocument* );
143 
144     // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
145 	void			StartListeningTo( ScDocument* pDoc );
146 	void			EndListeningTo( ScDocument* pDoc,
147 									ScTokenArray* pArr = NULL,
148 									ScAddress aPos = ScAddress() );
149 
150     /** Error code if ScFormulaCell, else 0. */
151     sal_uInt16          GetErrorCode() const;
152     /** ScFormulaCell with formula::svEmptyCell result, or ScNoteCell (may have been
153         created due to reference to empty cell). */
154 	sal_Bool			HasEmptyData() const;
155 	sal_Bool			HasValueData() const;
156 	sal_Bool			HasStringData() const;
157 	String			GetStringData() const;			// nur echte Strings
158 
159 	static sal_Bool		CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 );
160 
161 private:
162     ScBaseCell&     operator=( const ScBaseCell& );
163 
164 private:
165     ScPostIt*       mpNote;         /// The cell note. Cell takes ownership!
166     SvtBroadcaster* mpBroadcaster;  /// Broadcaster for changed values. Cell takes ownership!
167 
168 protected:
169     sal_uInt16          nTextWidth;
170     sal_uInt8            eCellType;      // enum CellType - sal_uInt8 spart Speicher
171     sal_uInt8            nScriptType;
172 };
173 
174 // ============================================================================
175 
176 class SC_DLLPUBLIC ScNoteCell : public ScBaseCell
177 {
178 public:
179 #ifdef USE_MEMPOOL
180 	DECL_FIXEDMEMPOOL_NEWDEL( ScNoteCell )
181 #endif
182 
183     /** Cell takes ownership of the passed broadcaster. */
184     explicit        ScNoteCell( SvtBroadcaster* pBC = 0 );
185     /** Cell takes ownership of the passed note and broadcaster. */
186     explicit        ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC = 0 );
187 
188 #ifdef DBG_UTIL
189 					~ScNoteCell();
190 #endif
191 
192 private:
193                     ScNoteCell( const ScNoteCell& );
194 };
195 
196 // ============================================================================
197 
198 class SC_DLLPUBLIC ScValueCell : public ScBaseCell
199 {
200 public:
201 #ifdef USE_MEMPOOL
202 	DECL_FIXEDMEMPOOL_NEWDEL( ScValueCell )
203 #endif
204 					ScValueCell();
205     explicit		ScValueCell( double fValue );
206 
207 #ifdef DBG_UTIL
208 					~ScValueCell();
209 #endif
210 
211     inline void     SetValue( double fValue ) { mfValue = fValue; }
212     inline double   GetValue() const { return mfValue; }
213 
214 private:
215 	double		    mfValue;
216 };
217 
218 // ============================================================================
219 
220 class SC_DLLPUBLIC ScStringCell : public ScBaseCell
221 {
222 public:
223 #ifdef USE_MEMPOOL
224 	DECL_FIXEDMEMPOOL_NEWDEL( ScStringCell )
225 #endif
226 
227 					ScStringCell();
228     explicit		ScStringCell( const String& rString );
229 
230 #ifdef DBG_UTIL
231 					~ScStringCell();
232 #endif
233 
234     inline void		SetString( const String& rString ) { maString = rString; }
235     inline void		GetString( String& rString ) const { rString = maString; }
236 	inline const String& GetString() const { return maString; }
237 
238 private:
239 	String		    maString;
240 };
241 
242 // ============================================================================
243 
244 class SC_DLLPUBLIC ScEditCell : public ScBaseCell
245 {
246 private:
247 	EditTextObject*		pData;
248 	String*				pString;		// fuer schnelleren Zugriff von Formeln
249 	ScDocument*			pDoc;			// fuer EditEngine Zugriff mit Pool
250 
251 	void			SetTextObject( const EditTextObject* pObject,
252 									const SfxItemPool* pFromPool );
253 
254 					// not implemented
255 					ScEditCell( const ScEditCell& );
256 
257 public:
258 
259 #ifdef USE_MEMPOOL
260 	DECL_FIXEDMEMPOOL_NEWDEL( ScEditCell )
261 #endif
262 
263 					~ScEditCell();				// wegen pData immer!
264 
265 					ScEditCell( const EditTextObject* pObject, ScDocument*,
266 								const SfxItemPool* pFromPool /* = NULL */ );
267                     ScEditCell( const ScEditCell& rCell, ScDocument& rDoc );
268 					// fuer Zeilenumbrueche
269 					ScEditCell( const String& rString, ScDocument* );
270 
271 	void			SetData( const EditTextObject* pObject,
272 							const SfxItemPool* pFromPool /* = NULL */ );
273 	void			GetData( const EditTextObject*& rpObject ) const;
274 	void			GetString( String& rString ) const;
275 
276 	const EditTextObject* GetData() const	{ return pData; }
277 };
278 
279 // ============================================================================
280 
281 enum ScMatrixMode {
282     MM_NONE      = 0,                   // No matrix formula
283     MM_FORMULA   = 1,                   // Upper left matrix formula cell
284     MM_REFERENCE = 2,                   // Remaining cells, via ocMatRef reference token
285     MM_FAKE      = 3                    // Interpret "as-if" matrix formula (legacy)
286 };
287 
288 class SC_DLLPUBLIC ScFormulaCell : public ScBaseCell, public SvtListener
289 {
290 private:
291     ScFormulaResult aResult;
292     formula::FormulaGrammar::Grammar  eTempGrammar;   // used between string (creation) and (re)compilation
293     ScTokenArray*   pCode;              // The (new) token array
294     ScDocument*     pDocument;
295     ScFormulaCell*  pPrevious;
296     ScFormulaCell*  pNext;
297     ScFormulaCell*  pPreviousTrack;
298     ScFormulaCell*  pNextTrack;
299     sal_uLong           nFormatIndex;       // Number format set by calculation
300     short           nFormatType;        // Number format type set by calculation
301     sal_uInt16          nSeenInIteration;   // Iteration cycle in which the cell was last encountered
302     sal_uInt8            cMatrixFlag;        // One of ScMatrixMode
303     sal_Bool            bDirty         : 1; // Must be (re)calculated
304     sal_Bool            bChanged       : 1; // Whether something changed regarding display/representation
305     sal_Bool            bRunning       : 1; // Already interpreting right now
306     sal_Bool            bCompile       : 1; // Must be (re)compiled
307     sal_Bool            bSubTotal      : 1; // Cell is part of or contains a SubTotal
308     sal_Bool            bIsIterCell    : 1; // Cell is part of a circular reference
309     sal_Bool            bInChangeTrack : 1; // Cell is in ChangeTrack
310     sal_Bool            bTableOpDirty  : 1; // Dirty flag for TableOp
311     sal_Bool            bNeedListening : 1; // Listeners need to be re-established after UpdateReference
312 
313                     enum ScInterpretTailParameter
314                     {
315                         SCITP_NORMAL,
316                         SCITP_FROM_ITERATION,
317                         SCITP_CLOSE_ITERATION_CIRCLE
318                     };
319 	void			InterpretTail( ScInterpretTailParameter );
320 
321     ScFormulaCell( const ScFormulaCell& );
322 
323 public:
324 
325 #ifdef USE_MEMPOOL
326 	DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
327 #endif
328 
329 	ScAddress		aPos;
330 
331 					~ScFormulaCell();
332 					ScFormulaCell();
333 
334     /** Empty formula cell, or with a preconstructed token array. */
335     ScFormulaCell( ScDocument*, const ScAddress&, const ScTokenArray* = NULL,
336                     const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
337                     sal_uInt8 = MM_NONE );
338 
339     /** With formula string and grammar to compile with.
340        formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
341         also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefor uses the address
342         convention associated with rPos::nTab by default. */
343     ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
344                     const String& rFormula,
345                     const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
346                     sal_uInt8 cMatInd = MM_NONE );
347 
348     ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT );
349 
350 	void			GetFormula( String& rFormula,
351 								const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
352 	void			GetFormula( rtl::OUStringBuffer& rBuffer,
353 								const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
354 
355 	void			SetDirty();
356 	inline void		SetDirtyVar() { bDirty = sal_True; }
357     // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
358     void            SetDirtyAfterLoad();
359 	inline void		ResetTableOpDirtyVar() { bTableOpDirty = sal_False; }
360 	void			SetTableOpDirty();
361 	sal_Bool			IsDirtyOrInTableOpDirty() const;
362 	sal_Bool			GetDirty() const { return bDirty; }
363     sal_Bool            NeedsListening() const { return bNeedListening; }
364     void            SetNeedsListening( sal_Bool bVar ) { bNeedListening = bVar; }
365 	void			Compile(const String& rFormula,
366 							sal_Bool bNoListening = sal_False,
367                             const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT );
368 	void			CompileTokenArray( sal_Bool bNoListening = sal_False );
369 	void			CompileXML( ScProgress& rProgress );		// compile temporary string tokens
370 	void			CalcAfterLoad();
371     bool            MarkUsedExternalReferences();
372 	void			Interpret();
373     inline sal_Bool     IsIterCell() const { return bIsIterCell; }
374     inline sal_uInt16   GetSeenInIteration() const { return nSeenInIteration; }
375 
376 	sal_Bool			HasOneReference( ScRange& r ) const;
377     /* Checks if the formula contains reference list that can be
378        expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
379        reference list is not required to be sorted (i.e. A3;A1;A2 is
380        still recognized as A1:A3), but no overlapping is allowed.
381        If one reference is recognized, the rRange is filled.
382 
383        It is similar to HasOneReference(), but more general.
384      */
385     bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
386 	sal_Bool			HasRelNameReference() const;
387 	sal_Bool			HasColRowName() const;
388 
389 	void			UpdateReference(UpdateRefMode eUpdateRefMode,
390 									const ScRange& r,
391 									SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
392                                     ScDocument* pUndoDoc = NULL,
393                                     const ScAddress* pUndoCellPos = NULL );
394 
395 	void			TransposeReference();
396 	void			UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
397 										ScDocument* pUndoDoc );
398 
399 	void			UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
400 
401 	void			UpdateInsertTab(SCTAB nTable);
402 	void 			UpdateInsertTabAbs(SCTAB nTable);
403 	sal_Bool			UpdateDeleteTab(SCTAB nTable, sal_Bool bIsMove = sal_False);
404 	void			UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo);
405 	void			UpdateRenameTab(SCTAB nTable, const String& rName);
406 	sal_Bool 			TestTabRefAbs(SCTAB nTable);
407 	void			UpdateCompile( sal_Bool bForceIfNameInUse = sal_False );
408 	sal_Bool			IsRangeNameInUse(sal_uInt16 nIndex) const;
409     void            FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const;
410 	void 			ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap );
411 	sal_Bool			IsSubTotal() const 						{ return bSubTotal; }
412 	sal_Bool			IsChanged() const  						{ return bChanged; }
413 	void			ResetChanged()							{ bChanged = sal_False; }
414 	sal_Bool			IsEmpty();      // formula::svEmptyCell result
415                     // display as empty string if formula::svEmptyCell result
416 	sal_Bool			IsEmptyDisplayedAsString();
417 	sal_Bool			IsValue();      // also sal_True if formula::svEmptyCell
418 	double			GetValue();
419 	double			GetValueAlways();	// ignore errors
420 	void			GetString( String& rString );
421 	const ScMatrix* GetMatrix();
422 	sal_Bool			GetMatrixOrigin( ScAddress& rPos ) const;
423 	void			GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
424 	sal_uInt16 			GetMatrixEdge( ScAddress& rOrgPos );
425 	sal_uInt16			GetErrCode();   // interpret first if necessary
426 	sal_uInt16			GetRawError();  // don't interpret, just return code or result error
427 	short			GetFormatType() const   				{ return nFormatType; }
428 	sal_uLong			GetFormatIndex() const					{ return nFormatIndex; }
429 	void			GetFormatInfo( short& nType, sal_uLong& nIndex ) const
430 						{ nType = nFormatType; nIndex = nFormatIndex; }
431 	sal_uInt8			GetMatrixFlag() const   				{ return cMatrixFlag; }
432 	ScTokenArray*   GetCode() const                         { return pCode; }
433 
434 	sal_Bool			IsRunning() const						{ return bRunning; }
435 	void			SetRunning( sal_Bool bVal )					{ bRunning = bVal; }
436 	void 			CompileDBFormula();
437 	void 			CompileDBFormula( sal_Bool bCreateFormulaString );
438 	void 			CompileNameFormula( sal_Bool bCreateFormulaString );
439 	void 			CompileColRowNameFormula();
440 	ScFormulaCell*	GetPrevious() const					{ return pPrevious; }
441 	ScFormulaCell*	GetNext() const						{ return pNext; }
442 	void			SetPrevious( ScFormulaCell* pF )	{ pPrevious = pF; }
443 	void			SetNext( ScFormulaCell* pF )		{ pNext = pF; }
444 	ScFormulaCell*	GetPreviousTrack() const				{ return pPreviousTrack; }
445 	ScFormulaCell*	GetNextTrack() const					{ return pNextTrack; }
446 	void			SetPreviousTrack( ScFormulaCell* pF )	{ pPreviousTrack = pF; }
447 	void			SetNextTrack( ScFormulaCell* pF )		{ pNextTrack = pF; }
448 
449 	virtual void    Notify( SvtBroadcaster& rBC, const SfxHint& rHint);
450 	void			SetCompile( sal_Bool bVal ) { bCompile = bVal; }
451 	ScDocument*		GetDocument() const		{ return pDocument; }
452 	void			SetMatColsRows( SCCOL nCols, SCROW nRows );
453 	void			GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
454 
455 					// ob Zelle im ChangeTrack und nicht im echten Dokument ist
456 	void			SetInChangeTrack( sal_Bool bVal ) { bInChangeTrack = bVal; }
457 	sal_Bool			IsInChangeTrack() const { return bInChangeTrack; }
458 
459 					// Zu Typ und Format das entsprechende Standardformat.
460 					// Bei Format "Standard" evtl. das in die Formelzelle
461 					// uebernommene Format.
462 	sal_uLong			GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const;
463 
464 	// For import filters!
465     void 			AddRecalcMode( formula::ScRecalcMode );
466     /** For import only: set a double result. */
467 	void			SetHybridDouble( double n )     { aResult.SetHybridDouble( n); }
468     /** For import only: set a string result.
469         If for whatever reason you have to use both, SetHybridDouble() and
470         SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
471         for performance reasons.*/
472     void            SetHybridString( const String& r )
473                         { aResult.SetHybridString( r); }
474     /** For import only: set a temporary formula string to be compiled later.
475         If for whatever reason you have to use both, SetHybridDouble() and
476         SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
477         for performance reasons.*/
478     void            SetHybridFormula( const String& r,
479                                     const formula::FormulaGrammar::Grammar eGrammar )
480                         { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; }
481 	void			SetErrCode( sal_uInt16 n );
482 	inline sal_Bool		IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); }
483 	EditTextObject*		CreateURLObject() ;
484     void            GetURLResult( String& rURL, String& rCellText );
485 
486     /** Determines whether or not the result string contains more than one paragraph */
487     bool            IsMultilineResult();
488 };
489 
490 //			Iterator fuer Referenzen in einer Formelzelle
491 class ScDetectiveRefIter
492 {
493 private:
494 	ScTokenArray* pCode;
495 	ScAddress aPos;
496 public:
497 				ScDetectiveRefIter( ScFormulaCell* pCell );
498 	sal_Bool		GetNextRef( ScRange& rRange );
499 };
500 
501 // ============================================================================
502 inline double GetValueFromCell( const ScBaseCell * pCell )
503 {
504     switch (pCell->GetCellType())
505     {
506     case CELLTYPE_VALUE:
507         return ((ScValueCell*)pCell)->GetValue();
508     case CELLTYPE_FORMULA:
509         {
510             if (((ScFormulaCell*)pCell)->IsValue())
511                 return ((ScFormulaCell*)pCell)->GetValue();
512             else
513                 return 0.0;
514         }
515     default:
516         return 0.0;
517     }
518 }
519 // ============================================================================
520 
521 
522 inline String GetStringFromCell( const ScBaseCell * pCell, sal_uLong nFormat, SvNumberFormatter* pFormatter )
523 {
524     if (pCell->GetCellType() != CELLTYPE_NOTE)
525     {
526         String strResult;
527 	Color* pColor = NULL;
528         ScCellFormat::GetString( const_cast<ScBaseCell*>(pCell), nFormat, strResult, &pColor, *(pFormatter) );
529         return strResult;
530     }
531     else
532         return String();
533 }
534 
535 #endif
536 
537