Update to m13
[ooovba.git] / applied_patches / 0162-calc-multiline-formula-ref.diff
blob42d3b05f129e704899e010195f87e4b020cc5765
1 diff --git sc/inc/cell.hxx sc/inc/cell.hxx
2 index 3f99c56..0bef331 100644
3 --- sc/inc/cell.hxx
4 +++ sc/inc/cell.hxx
5 @@ -647,6 +647,9 @@ public:
6 inline BOOL IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); }
7 EditTextObject* CreateURLObject() ;
8 void GetURLResult( String& rURL, String& rCellText );
10 + /** Determines whether or not the result string contains more than one paragraph */
11 + bool IsMultilineResult();
14 // Iterator fuer Referenzen in einer Formelzelle
15 diff --git sc/inc/editutil.hxx sc/inc/editutil.hxx
16 index 4cb209f..79ef1ad 100644
17 --- sc/inc/editutil.hxx
18 +++ sc/inc/editutil.hxx
19 @@ -63,8 +63,13 @@ class ScEditUtil
21 public:
22 static String ModifyDelimiters( const String& rOld );
24 + /// Retrieves string with paragraphs delimited by spaces
25 static String GetSpaceDelimitedString( const EditEngine& rEngine );
27 + /// Retrieves string with paragraphs delimited by new lines ('\n').
28 + static String GetMultilineString( const EditEngine& rEngine );
30 public:
31 ScEditUtil( ScDocument* pDocument, SCCOL nX, SCROW nY, SCTAB nZ,
32 const Point& rScrPosPixel,
33 diff --git sc/inc/formularesult.hxx sc/inc/formularesult.hxx
34 index 8c70f43..5865f60 100644
35 --- sc/inc/formularesult.hxx
36 +++ sc/inc/formularesult.hxx
37 @@ -38,6 +38,11 @@
38 and memory consumption. */
39 class ScFormulaResult
41 + typedef unsigned char Multiline;
42 + static const Multiline MULTILINE_UNKNOWN = 0;
43 + static const Multiline MULTILINE_FALSE = 1;
44 + static const Multiline MULTILINE_TRUE = 2;
46 union
48 double mfValue; // double result direct for performance and memory consumption
49 @@ -47,6 +52,7 @@ class ScFormulaResult
50 bool mbToken :1; // whether content of union is a token
51 bool mbEmpty :1; // empty cell result
52 bool mbEmptyDisplayedAsString :1; // only if mbEmpty
53 + Multiline meMultiline :2; // result is multiline
55 /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
56 prior to assigning other types */
57 @@ -69,12 +75,14 @@ public:
58 /** Effectively type svUnknown. */
59 ScFormulaResult()
60 : mpToken(NULL), mnError(0), mbToken(true),
61 - mbEmpty(false), mbEmptyDisplayedAsString(false) {}
62 + mbEmpty(false), mbEmptyDisplayedAsString(false),
63 + meMultiline(MULTILINE_UNKNOWN) {}
65 ScFormulaResult( const ScFormulaResult & r )
66 : mnError( r.mnError), mbToken( r.mbToken),
67 mbEmpty( r.mbEmpty),
68 - mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString)
69 + mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
70 + meMultiline( r.meMultiline)
72 if (mbToken)
74 @@ -99,7 +107,8 @@ public:
75 /** Same comments as for SetToken() apply! */
76 explicit ScFormulaResult( const formula::FormulaToken* p )
77 : mnError(0), mbToken(false),
78 - mbEmpty(false), mbEmptyDisplayedAsString(false)
79 + mbEmpty(false), mbEmptyDisplayedAsString(false),
80 + meMultiline(MULTILINE_UNKNOWN)
82 SetToken( p);
84 @@ -153,6 +162,10 @@ public:
85 details instead. */
86 inline bool IsValue() const;
88 + /** Determines whether or not the result is a string containing more than
89 + one paragraph */
90 + inline bool IsMultiline();
92 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
93 else 0. */
94 inline USHORT GetResultError() const;
95 @@ -211,6 +224,7 @@ inline void ScFormulaResult::ResetToDefaults()
96 mnError = 0;
97 mbEmpty = false;
98 mbEmptyDisplayedAsString = false;
99 + meMultiline = MULTILINE_UNKNOWN;
103 @@ -232,10 +246,12 @@ inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
104 mbToken = false;
105 // set in case mnError is 0 now, which shouldn't happen but ...
106 mfValue = 0.0;
107 + meMultiline = MULTILINE_FALSE;
108 break;
109 case formula::svEmptyCell:
110 mbEmpty = true;
111 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
112 + meMultiline = MULTILINE_FALSE;
113 p->DecRef();
114 mbToken = false;
115 break;
116 @@ -243,6 +259,7 @@ inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
117 mfValue = p->GetDouble();
118 p->DecRef();
119 mbToken = false;
120 + meMultiline = MULTILINE_FALSE;
121 break;
122 default:
123 mpToken = p;
124 @@ -270,6 +287,7 @@ inline void ScFormulaResult::Assign( const ScFormulaResult & r )
125 mbToken = false;
126 mbEmpty = true;
127 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
128 + meMultiline = r.meMultiline;
130 else if (r.mbToken)
132 @@ -352,6 +370,7 @@ inline void ScFormulaResult::SetDouble( double f )
133 mpToken->DecRef();
134 mfValue = f;
135 mbToken = false;
136 + meMultiline = MULTILINE_FALSE;
140 @@ -405,6 +424,20 @@ inline bool ScFormulaResult::IsValue() const
144 +inline bool ScFormulaResult::IsMultiline()
146 + if (meMultiline == MULTILINE_UNKNOWN)
148 + const String& rStr = GetString();
149 + if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
150 + meMultiline = MULTILINE_TRUE;
151 + else
152 + meMultiline = MULTILINE_FALSE;
154 + return meMultiline == MULTILINE_TRUE;
158 inline USHORT ScFormulaResult::GetResultError() const
160 if (mnError)
161 @@ -537,6 +570,7 @@ inline void ScFormulaResult::SetHybridDouble( double f )
163 mfValue = f;
164 mbToken = false;
165 + meMultiline = MULTILINE_FALSE;
169 diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
170 index 232a2ae..f26401e 100644
171 --- sc/source/core/data/cell.cxx
172 +++ sc/source/core/data/cell.cxx
173 @@ -1938,6 +1938,13 @@ void ScFormulaCell::GetURLResult( String& rURL, String& rCellText )
177 +bool ScFormulaCell::IsMultilineResult()
179 + if (!IsValue())
180 + return aResult.IsMultiline();
181 + return false;
184 EditTextObject* ScFormulaCell::CreateURLObject()
186 String aCellText;
187 diff --git sc/source/core/data/cell2.cxx sc/source/core/data/cell2.cxx
188 index 5014e6b..4c38b39 100644
189 --- sc/source/core/data/cell2.cxx
190 +++ sc/source/core/data/cell2.cxx
191 @@ -131,7 +131,7 @@ void ScEditCell::GetString( String& rString ) const
192 // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
193 EditEngine& rEngine = pDoc->GetEditEngine();
194 rEngine.SetText( *pData );
195 - rString = ScEditUtil::GetSpaceDelimitedString(rEngine); // space between paragraphs
196 + rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs
197 // kurze Strings fuer Formeln merken
198 if ( rString.Len() < MAXSTRLEN )
199 ((ScEditCell*)this)->pString = new String( rString ); //! non-const
200 diff --git sc/source/core/data/column.cxx sc/source/core/data/column.cxx
201 index 48bad18..9e03b31 100644
202 --- sc/source/core/data/column.cxx
203 +++ sc/source/core/data/column.cxx
204 @@ -2174,8 +2174,10 @@ BOOL ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
205 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
207 ScBaseCell* pCell = pItems[nIndex].pCell;
208 - if ( pCell->GetCellType() == CELLTYPE_EDIT ||
209 - IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) )
210 + CellType eCellType = pCell->GetCellType();
211 + if ( eCellType == CELLTYPE_EDIT ||
212 + IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ||
213 + ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) )
215 rFirst = nRow;
216 return TRUE;
217 diff --git sc/source/core/data/column2.cxx sc/source/core/data/column2.cxx
218 index 9e129e2..cc8e369 100644
219 --- sc/source/core/data/column2.cxx
220 +++ sc/source/core/data/column2.cxx
221 @@ -319,9 +319,12 @@ long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev,
224 BOOL bAddMargin = TRUE;
225 - BOOL bEditEngine = ( pCell->GetCellType() == CELLTYPE_EDIT ||
226 + CellType eCellType = pCell->GetCellType();
228 + BOOL bEditEngine = ( eCellType == CELLTYPE_EDIT ||
229 eOrient == SVX_ORIENTATION_STACKED ||
230 - IsAmbiguousScript( nScript ) );
231 + IsAmbiguousScript( nScript ) ||
232 + ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) );
234 if (!bEditEngine) // direkte Ausgabe
236 diff --git sc/source/core/data/column3.cxx sc/source/core/data/column3.cxx
237 index 621c19f..ba6a42f 100644
238 --- sc/source/core/data/column3.cxx
239 +++ sc/source/core/data/column3.cxx
240 @@ -854,7 +854,16 @@ ScBaseCell* ScColumn::CloneCell(SCSIZE nIndex, USHORT nFlags, ScDocument& rDestD
241 rForm.GetString( aString );
242 // #33224# do not clone empty string
243 if (aString.Len() > 0)
244 - pNew = new ScStringCell( aString );
246 + if ( rForm.IsMultilineResult() )
248 + pNew = new ScEditCell(aString, &rDestDoc);
250 + else
252 + pNew = new ScStringCell(aString);
257 break;
258 diff --git sc/source/core/tool/editutil.cxx sc/source/core/tool/editutil.cxx
259 index 5c771a1..8199a21 100644
260 --- sc/source/core/tool/editutil.cxx
261 +++ sc/source/core/tool/editutil.cxx
262 @@ -84,19 +84,29 @@ String ScEditUtil::ModifyDelimiters( const String& rOld )
263 return aRet;
266 -String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine )
267 +static String lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c )
269 String aRet;
270 USHORT nParCount = rEngine.GetParagraphCount();
271 for (USHORT nPar=0; nPar<nParCount; nPar++)
273 if (nPar > 0)
274 - aRet += ' ';
275 + aRet += c;
276 aRet += rEngine.GetText( nPar );
278 return aRet;
281 +String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine )
283 + return lcl_GetDelimitedString(rEngine, ' ');
286 +String ScEditUtil::GetMultilineString( const EditEngine& rEngine )
288 + return lcl_GetDelimitedString(rEngine, '\n');
291 //------------------------------------------------------------------------
293 Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, BOOL bForceToTop )
294 diff --git sc/source/filter/dif/difimp.cxx sc/source/filter/dif/difimp.cxx
295 index 99651ea..9e4a65c 100644
296 --- sc/source/filter/dif/difimp.cxx
297 +++ sc/source/filter/dif/difimp.cxx
298 @@ -338,7 +338,7 @@ TOPIC DifParser::GetNextTopic( void )
300 while( eS != S_END )
302 - if( !rIn.ReadUniOrByteStringLine( aLine ) )
303 + if( !ReadNextLine( aLine ) )
305 eS = S_END;
306 eRet = T_END;
307 @@ -406,10 +406,10 @@ TOPIC DifParser::GetNextTopic( void )
308 break;
309 case S_UNKNOWN:
310 // 2 Zeilen ueberlesen
311 - rIn.ReadUniOrByteStringLine( aLine );
312 + ReadNextLine( aLine );
313 case S_ERROR_L2: // Fehler in Line 2 aufgetreten
314 // eine Zeile ueberlesen
315 - rIn.ReadUniOrByteStringLine( aLine );
316 + ReadNextLine( aLine );
317 eS = S_END;
318 break;
319 default:
320 @@ -421,7 +421,7 @@ TOPIC DifParser::GetNextTopic( void )
324 -void lcl_DeEscapeQuotesDif( String& rString )
325 +static void lcl_DeEscapeQuotesDif( String& rString )
327 // Special handling for DIF import: Escaped (duplicated) quotes are resolved.
328 // Single quote characters are left in place because older versions didn't
329 @@ -437,25 +437,107 @@ void lcl_DeEscapeQuotesDif( String& rString )
333 +// Determine if passed in string is numeric data and set fVal/nNumFormat if so
334 +DATASET DifParser::GetNumberDataset( const sal_Unicode* pPossibleNumericData )
336 + DATASET eRet = D_SYNT_ERROR;
337 + if( bPlain )
339 + if( ScanFloatVal( pPossibleNumericData ) )
340 + eRet = D_NUMERIC;
341 + else
342 + eRet = D_SYNT_ERROR;
344 + else
345 + { // ...und zur Strafe mit'm Numberformatter...
346 + DBG_ASSERT( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" );
347 + String aTestVal( pPossibleNumericData );
348 + sal_uInt32 nFormat = 0;
349 + double fTmpVal;
350 + if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) )
352 + fVal = fTmpVal;
353 + nNumFormat = nFormat;
354 + eRet = D_NUMERIC;
356 + else
357 + eRet = D_SYNT_ERROR;
359 + return eRet;
362 +bool DifParser::ReadNextLine( String& rStr )
364 + if( aLookAheadLine.Len() == 0 )
366 + return rIn.ReadUniOrByteStringLine( rStr );
368 + else
370 + rStr = aLookAheadLine;
371 + aLookAheadLine.Erase();
372 + return true;
376 +// Look ahead in the stream to determine if the next line is the first line of
377 +// a valid data record structure
378 +bool DifParser::LookAhead()
380 + const sal_Unicode* pAktBuffer;
381 + bool bValidStructure = false;
383 + DBG_ASSERT( aLookAheadLine.Len() == 0, "*DifParser::LookAhead(): LookAhead called twice in a row" );
384 + rIn.ReadUniOrByteStringLine( aLookAheadLine );
386 + pAktBuffer = aLookAheadLine.GetBuffer();
388 + switch( *pAktBuffer )
390 + case '-': // Special Datatype
391 + pAktBuffer++;
393 + if( Is1_0( pAktBuffer ) )
395 + bValidStructure = true;
397 + break;
398 + case '0': // Numeric Data
399 + pAktBuffer++;
400 + if( *pAktBuffer == ',' )
402 + pAktBuffer++;
403 + bValidStructure = ( GetNumberDataset(pAktBuffer) != D_SYNT_ERROR );
405 + break;
406 + case '1': // String Data
407 + if( Is1_0( aLookAheadLine.GetBuffer() ) )
409 + bValidStructure = true;
411 + break;
413 + return bValidStructure;
416 DATASET DifParser::GetNextDataset( void )
418 DATASET eRet = D_UNKNOWN;
419 String aLine;
420 - const sal_Unicode* pAkt;
421 + const sal_Unicode* pAktBuffer;
423 - rIn.ReadUniOrByteStringLine( aLine );
424 + ReadNextLine( aLine );
426 - pAkt = aLine.GetBuffer();
427 + pAktBuffer = aLine.GetBuffer();
429 - switch( *pAkt )
430 + switch( *pAktBuffer )
432 case '-': // Special Datatype
433 - pAkt++;
434 + pAktBuffer++;
436 - if( Is1_0( pAkt ) )
437 + if( Is1_0( pAktBuffer ) )
439 - rIn.ReadUniOrByteStringLine( aLine );
440 + ReadNextLine( aLine );
441 if( IsBOT( aLine.GetBuffer() ) )
442 eRet = D_BOT;
443 else if( IsEOD( aLine.GetBuffer() ) )
444 @@ -463,37 +545,16 @@ DATASET DifParser::GetNextDataset( void )
446 break;
447 case '0': // Numeric Data
448 - pAkt++; // Wert in fVal, 2. Zeile in aData
449 - if( *pAkt == ',' )
450 + pAktBuffer++; // Wert in fVal, 2. Zeile in aData
451 + if( *pAktBuffer == ',' )
453 - pAkt++;
454 - if( bPlain )
456 - if( ScanFloatVal( pAkt ) )
457 - eRet = D_NUMERIC;
458 - else
459 - eRet = D_SYNT_ERROR;
461 - else
462 - { // ...und zur Strafe mit'm Numberformatter...
463 - DBG_ASSERT( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" );
464 - String aTestVal( pAkt );
465 - sal_uInt32 nFormat = 0;
466 - double fTmpVal;
467 - if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) )
469 - fVal = fTmpVal;
470 - nNumFormat = nFormat;
471 - eRet = D_NUMERIC;
473 - else
474 - eRet = D_SYNT_ERROR;
476 - rIn.ReadUniOrByteStringLine( aData );
477 + pAktBuffer++;
478 + eRet = GetNumberDataset(pAktBuffer);
479 + ReadNextLine( aData );
480 if ( eRet == D_SYNT_ERROR )
481 { // for broken records write "#ERR: data" to cell
482 String aTmp( RTL_CONSTASCII_USTRINGPARAM( "#ERR: " ));
483 - aTmp += pAkt;
484 + aTmp += pAktBuffer;
485 aTmp.AppendAscii( " (" );
486 aTmp += aData;
487 aTmp += sal_Unicode(')');
488 @@ -505,18 +566,62 @@ DATASET DifParser::GetNextDataset( void )
489 case '1': // String Data
490 if( Is1_0( aLine.GetBuffer() ) )
492 - rIn.ReadUniOrByteStringLine( aLine );
493 - DBG_ASSERT( aLine.Len() >= 2,
494 - "*DifParser::GetNextTopic(): Text ist zu kurz (mind. \"\")!" );
495 - aData = aLine.Copy( 1, aLine.Len() - 2 );
496 - lcl_DeEscapeQuotesDif( aData );
497 - eRet = D_STRING;
498 + ReadNextLine( aLine );
499 + xub_StrLen nLineLength = aLine.Len();
500 + const sal_Unicode* pLine = aLine.GetBuffer();
502 + if( nLineLength >= 1 && *pLine == '"' )
504 + // Quotes are not always escaped (duplicated), see lcl_DeEscapeQuotesDif
505 + // A look ahead into the next line is needed in order to deal with
506 + // multiline strings containing quotes
507 + if( LookAhead() )
509 + // Single line string
510 + if( nLineLength >= 2 && pLine[nLineLength - 1] == '"' )
512 + aData = aLine.Copy( 1, nLineLength - 2 );
513 + lcl_DeEscapeQuotesDif( aData );
514 + eRet = D_STRING;
517 + else
519 + // Multiline string
520 + aData = aLine.Copy( 1 );
521 + bool bContinue = true;
522 + while ( bContinue )
524 + aData.Append( '\n' );
525 + bContinue = !rIn.IsEof() && ReadNextLine( aLine );
526 + if( bContinue )
528 + nLineLength = aLine.Len();
529 + if( nLineLength >= 1 )
531 + pLine = aLine.GetBuffer();
532 + bContinue = !LookAhead();
533 + if( bContinue )
535 + aData.Append( aLine );
537 + else if( pLine[nLineLength - 1] == '"' )
539 + aData.Append( pLine, nLineLength - 1 );
540 + lcl_DeEscapeQuotesDif( aData );
541 + eRet = D_STRING;
545 + };
549 break;
552 if( eRet == D_UNKNOWN )
553 - rIn.ReadUniOrByteStringLine( aLine );
554 + ReadNextLine( aLine );
556 if( rIn.IsEof() )
557 eRet = D_EOD;
558 diff --git sc/source/filter/excel/xestyle.cxx sc/source/filter/excel/xestyle.cxx
559 index 71abe16..de32a64 100644
560 --- sc/source/filter/excel/xestyle.cxx
561 +++ sc/source/filter/excel/xestyle.cxx
562 @@ -2320,9 +2320,9 @@ sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_In
563 return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
566 -sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, ULONG nForceScNumFmt )
567 +sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, ULONG nForceScNumFmt, bool bForceLineBreak )
569 - return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, false );
570 + return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
573 sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
574 diff --git sc/source/filter/excel/xetable.cxx sc/source/filter/excel/xetable.cxx
575 index 1c7c945..8d27d2d 100644
576 --- sc/source/filter/excel/xetable.cxx
577 +++ sc/source/filter/excel/xetable.cxx
578 @@ -839,13 +839,15 @@ XclExpFormulaCell::XclExpFormulaCell(
580 // #i41420# find script type according to result type (always latin for numeric results)
581 sal_Int16 nScript = ApiScriptType::LATIN;
582 + bool bForceLineBreak = false;
583 if( nFormatType == NUMBERFORMAT_TEXT )
585 String aResult;
586 mrScFmlaCell.GetString( aResult );
587 + bForceLineBreak = mrScFmlaCell.IsMultilineResult();
588 nScript = XclExpStringHelper::GetLeadingScriptType( rRoot, aResult );
590 - SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt ) );
591 + SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt, bForceLineBreak ) );
594 // *** Convert the formula token array *** --------------------------------
595 diff --git sc/source/filter/html/htmlexp.cxx sc/source/filter/html/htmlexp.cxx
596 index 20fbd39..75f1515 100644
597 --- sc/source/filter/html/htmlexp.cxx
598 +++ sc/source/filter/html/htmlexp.cxx
599 @@ -1154,9 +1154,31 @@ void ScHTMLExport::WriteCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
600 if ( !bFieldText )
602 if ( !aStrOut.Len() )
604 TAG_ON( sHTML_linebreak ); // #42573# keine komplett leere Zelle
606 else
607 - OUT_STR( aStrOut );
609 + xub_StrLen nPos = aStrOut.Search( _LF );
610 + if ( nPos == STRING_NOTFOUND )
612 + OUT_STR( aStrOut );
614 + else
616 + xub_StrLen nStartPos = 0;
617 + do
619 + String aSingleLine( aStrOut, nStartPos, nPos - nStartPos );
620 + OUT_STR( aSingleLine );
621 + TAG_ON( sHTML_linebreak );
622 + nStartPos = nPos + 1;
623 + }
624 + while( ( nPos = aStrOut.Search( _LF, nStartPos ) ) != STRING_NOTFOUND );
625 + String aSingleLine( aStrOut, nStartPos, aStrOut.Len() - nStartPos );
626 + OUT_STR( aSingleLine );
630 if ( pGraphEntry )
631 WriteGraphEntry( pGraphEntry );
632 @@ -1194,7 +1216,7 @@ BOOL ScHTMLExport::WriteFieldText( const ScEditCell* pCell )
633 for ( USHORT nPar=0; nPar < nParas; nPar++ )
635 if ( nPar > 0 )
636 - rStrm << ' '; // blank between paragraphs
637 + TAG_ON( sHTML_linebreak );
638 SvUShorts aPortions;
639 rEngine.GetPortions( nPar, aPortions );
640 USHORT nCnt = aPortions.Count();
641 diff --git sc/source/filter/inc/dif.hxx sc/source/filter/inc/dif.hxx
642 index 602a356..3e9d3bc 100644
643 --- sc/source/filter/inc/dif.hxx
644 +++ sc/source/filter/inc/dif.hxx
645 @@ -82,7 +82,11 @@ private:
646 SvNumberFormatter* pNumFormatter;
647 SvStream& rIn;
648 BOOL bPlain;
649 + String aLookAheadLine;
651 + bool ReadNextLine( String& rStr );
652 + bool LookAhead();
653 + DATASET GetNumberDataset( const sal_Unicode* pPossibleNumericData );
654 static inline BOOL IsBOT( const sal_Unicode* pRef );
655 static inline BOOL IsEOD( const sal_Unicode* pRef );
656 static inline BOOL Is1_0( const sal_Unicode* pRef );
657 diff --git sc/source/filter/inc/xestyle.hxx sc/source/filter/inc/xestyle.hxx
658 index f3b3c4f..9508c8b 100644
659 --- sc/source/filter/inc/xestyle.hxx
660 +++ sc/source/filter/inc/xestyle.hxx
661 @@ -644,10 +644,13 @@ public:
662 @param nXFFlags Additional flags allowing to control the creation of an XF.
663 @param nForceScNumFmt The number format to be exported, e.g. formula
664 result type. This format will always overwrite the cell's number format.
665 + @param bForceLineBreak true = Set line break flag unconditionally.
666 + This is required for cells that contain multi-line text.
667 @return A unique XF record ID. */
668 sal_uInt32 InsertWithNumFmt(
669 const ScPatternAttr* pPattern, sal_Int16 nScript,
670 - ULONG nForceScNumFmt );
671 + ULONG nForceScNumFmt,
672 + bool bForceLineBreak );
673 /** Inserts the passed cell style. Creates a style XF record and a STYLE record.
674 @return A unique XF record ID. */
675 sal_uInt32 InsertStyle( const SfxStyleSheetBase* pStyleSheet );
676 diff --git sc/source/filter/qpro/qpro.cxx sc/source/filter/qpro/qpro.cxx
677 index 3d5ea26..9bac593 100644
678 --- sc/source/filter/qpro/qpro.cxx
679 +++ sc/source/filter/qpro/qpro.cxx
680 @@ -71,7 +71,7 @@ FltError ScQProReader::readSheet( SCTAB nTab, ScDocument* pDoc, ScQProStyle *pSt
681 readString( aLabel, getLength() - 7 );
682 nStyle = nStyle >> 3;
683 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
684 - pDoc->PutCell( nCol, nRow, nTab, new ScStringCell( aLabel ), (BOOL) TRUE );
685 + pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( aLabel, pDoc ), (BOOL) TRUE );
687 break;
689 diff --git sc/source/filter/xml/XMLExportIterator.cxx sc/source/filter/xml/XMLExportIterator.cxx
690 index 768c926..29a2e2c 100644
691 --- sc/source/filter/xml/XMLExportIterator.cxx
692 +++ sc/source/filter/xml/XMLExportIterator.cxx
693 @@ -568,6 +568,7 @@ ScMyCell::ScMyCell() :
694 aShapeList(),
695 aDetectiveObjVec(),
696 nValidationIndex(-1),
697 + pBaseCell(NULL),
698 bIsAutoStyle( sal_False ),
699 bHasShape( sal_False ),
700 bIsMergedBase( sal_False ),
701 diff --git sc/source/filter/xml/XMLExportIterator.hxx sc/source/filter/xml/XMLExportIterator.hxx
702 index a55f746..9d1834c 100644
703 --- sc/source/filter/xml/XMLExportIterator.hxx
704 +++ sc/source/filter/xml/XMLExportIterator.hxx
705 @@ -48,6 +48,7 @@ class ScHorizontalCellIterator;
706 struct ScMyCell;
707 class ScXMLExport;
708 class ScFormatRangeStyles;
709 +class ScBaseCell;
711 //==============================================================================
713 @@ -313,6 +314,8 @@ struct ScMyCell
714 sal_Int32 nNumberFormat;
715 com::sun::star::table::CellContentType nType;
717 + ScBaseCell* pBaseCell;
719 sal_Bool bIsAutoStyle;
721 sal_Bool bHasShape;
722 diff --git sc/source/filter/xml/xmlexprt.cxx sc/source/filter/xml/xmlexprt.cxx
723 index 0a03262..97916e2 100644
724 --- sc/source/filter/xml/xmlexprt.cxx
725 +++ sc/source/filter/xml/xmlexprt.cxx
726 @@ -2452,7 +2452,8 @@ void ScXMLExport::WriteCell (ScMyCell& aCell)
728 if (!bIsEmpty)
730 - if ((aCell.nType == table::CellContentType_TEXT) && IsEditCell(aCell))
731 + if ((aCell.nType == table::CellContentType_TEXT && IsEditCell(aCell)) ||
732 + (aCell.nType == table::CellContentType_FORMULA && IsMultiLineFormulaCell(aCell)))
734 bEditCell = sal_True;
735 uno::Reference<text::XText> xText(xCurrentTableCellRange->getCellByPosition(aCell.aCellAddress.Column, aCell.aCellAddress.Row), uno::UNO_QUERY);
736 @@ -2901,12 +2902,15 @@ sal_Bool ScXMLExport::IsCellTypeEqual (const ScMyCell& aCell1, const ScMyCell& a
737 return (aCell1.nType == aCell2.nType);
740 -sal_Bool ScXMLExport::IsEditCell(const com::sun::star::table::CellAddress& aAddress) const
741 +sal_Bool ScXMLExport::IsEditCell(const com::sun::star::table::CellAddress& aAddress, ScMyCell* pMyCell) const
743 ScAddress aCoreAddress(static_cast<SCCOL>(aAddress.Column),
744 static_cast<SCROW>(aAddress.Row),
745 static_cast<SCTAB>(aAddress.Sheet));
746 ScBaseCell* pBaseCell = GetDocument() ? GetDocument()->GetCell(aCoreAddress) : NULL;
747 + if (pMyCell)
748 + pMyCell->pBaseCell = pBaseCell;
750 if (pBaseCell)
751 return (pBaseCell->GetCellType() == CELLTYPE_EDIT);
752 return sal_False;
753 @@ -2926,12 +2930,36 @@ sal_Bool ScXMLExport::IsEditCell(ScMyCell& rCell) const
754 return rCell.bIsEditCell;
755 else
757 - rCell.bIsEditCell = IsEditCell(rCell.aCellAddress);
758 + rCell.bIsEditCell = IsEditCell(rCell.aCellAddress, &rCell);
759 rCell.bKnowWhetherIsEditCell = sal_True;
760 return rCell.bIsEditCell;
764 +sal_Bool ScXMLExport::IsMultiLineFormulaCell(ScMyCell& rCell)
766 + if (rCell.pBaseCell)
768 + if (rCell.pBaseCell->GetCellType() != CELLTYPE_FORMULA)
769 + return false;
771 + return static_cast<ScFormulaCell*>(rCell.pBaseCell)->IsMultilineResult();
774 + ScAddress aAddr(static_cast<SCCOL>(rCell.aCellAddress.Column),
775 + static_cast<SCROW>(rCell.aCellAddress.Row),
776 + static_cast<SCTAB>(rCell.aCellAddress.Sheet));
777 + ScBaseCell* pBaseCell = pDoc ? pDoc->GetCell(aAddr) : NULL;
778 + if (!pBaseCell)
779 + return false;
781 + rCell.pBaseCell = pBaseCell;
782 + if (rCell.pBaseCell->GetCellType() != CELLTYPE_FORMULA)
783 + return false;
785 + return static_cast<ScFormulaCell*>(rCell.pBaseCell)->IsMultilineResult();
788 //UNUSED2008-05 sal_Bool ScXMLExport::IsAnnotationEqual(const uno::Reference<table::XCell>& /* xCell1 */,
789 //UNUSED2008-05 const uno::Reference<table::XCell>& /* xCell2 */)
790 //UNUSED2008-05 {
791 diff --git sc/source/filter/xml/xmlexprt.hxx sc/source/filter/xml/xmlexprt.hxx
792 index 7f99237..d98151c 100644
793 --- sc/source/filter/xml/xmlexprt.hxx
794 +++ sc/source/filter/xml/xmlexprt.hxx
795 @@ -62,6 +62,7 @@ class XMLNumberFormatAttributesExportHelper;
796 class ScChartListener;
797 class SfxItemPool;
798 class ScAddress;
799 +class ScBaseCell;
801 typedef std::vector< com::sun::star::uno::Reference < com::sun::star::drawing::XShapes > > ScMyXShapesVec;
803 @@ -193,9 +194,10 @@ class ScXMLExport : public SvXMLExport
804 void SetRepeatAttribute (const sal_Int32 nEqualCellCount);
806 sal_Bool IsCellTypeEqual (const ScMyCell& aCell1, const ScMyCell& aCell2) const;
807 - sal_Bool IsEditCell(const com::sun::star::table::CellAddress& aAddress) const;
808 + sal_Bool IsEditCell(const com::sun::star::table::CellAddress& aAddress, ScMyCell* pMyCell = NULL) const;
809 //UNUSED2008-05 sal_Bool IsEditCell(const com::sun::star::uno::Reference <com::sun::star::table::XCell>& xCell) const;
810 sal_Bool IsEditCell(ScMyCell& rCell) const;
811 + sal_Bool IsMultiLineFormulaCell(ScMyCell& rCell);
812 //UNUSED2008-05 sal_Bool IsAnnotationEqual(const com::sun::star::uno::Reference<com::sun::star::table::XCell>& xCell1,
813 //UNUSED2008-05 const com::sun::star::uno::Reference<com::sun::star::table::XCell>& xCell2);
814 sal_Bool IsCellEqual (ScMyCell& aCell1, ScMyCell& aCell2);
815 diff --git sc/source/ui/app/transobj.cxx sc/source/ui/app/transobj.cxx
816 index 69fd72a..1620f95 100644
817 --- sc/source/ui/app/transobj.cxx
818 +++ sc/source/ui/app/transobj.cxx
819 @@ -312,6 +312,8 @@ sal_Bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor )
820 BOOL bIncludeFiltered = pDoc->IsCutMode() || bUsedForLink;
822 ScImportExport aObj( pDoc, aBlock );
823 + if ( bUsedForLink )
824 + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) );
825 aObj.SetFormulas( pDoc->GetViewOptions().GetOption( VOPT_FORMULAS ) );
826 aObj.SetIncludeFiltered( bIncludeFiltered );
828 @@ -816,7 +818,10 @@ void ScTransferObj::StripRefs( ScDocument* pDoc,
830 String aStr;
831 pFCell->GetString(aStr);
832 - pNew = new ScStringCell( aStr );
833 + if ( pFCell->IsMultilineResult() )
834 + pNew = new ScEditCell( aStr, pDestDoc );
835 + else
836 + pNew = new ScStringCell( aStr );
838 pDestDoc->PutCell( nCol,nRow,nDestTab, pNew );
840 diff --git sc/source/ui/docshell/docsh.cxx sc/source/ui/docshell/docsh.cxx
841 index 8526d08..ec2bc6d 100644
842 --- sc/source/ui/docshell/docsh.cxx
843 +++ sc/source/ui/docshell/docsh.cxx
844 @@ -1179,6 +1179,7 @@ BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium )
846 bSetColWidths = TRUE;
847 bSetSimpleTextColWidths = TRUE;
848 + bSetRowHeights = TRUE;
850 else if (aFltName.EqualsAscii(pFilterSylk))
852 @@ -1206,6 +1207,7 @@ BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium )
853 SetError(eError);
854 bSetColWidths = TRUE;
855 bSetSimpleTextColWidths = TRUE;
856 + bSetRowHeights = TRUE;
858 else if (aFltName.EqualsAscii(pFilterQPro6))
860 diff --git sc/source/ui/docshell/docsh4.cxx sc/source/ui/docshell/docsh4.cxx
861 index 78269ba..8921396 100644
862 --- sc/source/ui/docshell/docsh4.cxx
863 +++ sc/source/ui/docshell/docsh4.cxx
864 @@ -2406,10 +2406,12 @@ long __EXPORT ScDocShell::DdeGetData( const String& rItem,
865 if( aDdeTextFmt.EqualsAscii( "CSV" ) ||
866 aDdeTextFmt.EqualsAscii( "FCSV" ) )
867 aObj.SetSeparator( ',' );
868 + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, NULL, false ) );
869 return aObj.ExportData( rMimeType, rValue ) ? 1 : 0;
872 ScImportExport aObj( &aDocument, rItem );
873 + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, NULL, false ) );
874 if( aObj.IsRef() )
875 return aObj.ExportData( rMimeType, rValue ) ? 1 : 0;
876 return 0;
877 diff --git sc/source/ui/docshell/impex.cxx sc/source/ui/docshell/impex.cxx
878 index c1bc6bb..cc51d67 100644
879 --- sc/source/ui/docshell/impex.cxx
880 +++ sc/source/ui/docshell/impex.cxx
881 @@ -93,6 +93,12 @@ class StarBASIC;
883 //========================================================================
885 +namespace
887 + const String SYLK_LF = String::CreateFromAscii("\x1b :");
888 + const String SEMICOLON = String::CreateFromAscii(";");
889 + const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;");
892 // Gesamtdokument ohne Undo
894 @@ -102,7 +108,7 @@ ScImportExport::ScImportExport( ScDocument* p )
895 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
896 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
897 bAll( TRUE ), bSingle( TRUE ), bUndo( FALSE ),
898 - bOverflow( FALSE ), mbApi( true )
899 + bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
901 pUndoDoc = NULL;
902 pExtOptions = NULL;
903 @@ -117,7 +123,7 @@ ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
904 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
905 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
906 bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ),
907 - bOverflow( FALSE ), mbApi( true )
908 + bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
910 pUndoDoc = NULL;
911 pExtOptions = NULL;
912 @@ -133,7 +139,7 @@ ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
913 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
914 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
915 bAll( FALSE ), bSingle( FALSE ), bUndo( BOOL( pDocSh != NULL ) ),
916 - bOverflow( FALSE ), mbApi( true )
917 + bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
919 pUndoDoc = NULL;
920 pExtOptions = NULL;
921 @@ -150,7 +156,7 @@ ScImportExport::ScImportExport( ScDocument* p, const String& rPos )
922 nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
923 bFormulas( FALSE ), bIncludeFiltered( TRUE ),
924 bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ),
925 - bOverflow( FALSE ), mbApi( true )
926 + bOverflow( FALSE ), mbApi( true ), mExportTextOptions()
928 pUndoDoc = NULL;
929 pExtOptions = NULL;
930 @@ -575,6 +581,7 @@ void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rS
934 +// This function could be replaced by endlub()
935 // static
936 void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
938 @@ -605,7 +612,7 @@ enum DoubledQuoteMode
939 DQM_SEPARATE // end one string and begin next
942 -const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
943 +static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
944 sal_Unicode cStr, DoubledQuoteMode eMode )
946 p++; //! jump over opening quote
947 @@ -653,8 +660,26 @@ const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
948 return p;
951 +static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p, String& rString )
953 + const sal_Unicode* pStartQuote = p;
954 + const sal_Unicode* pEndQuote = 0;
955 + while( *(++p) )
957 + if( *p == '"' )
958 + pEndQuote = p;
960 + if( pEndQuote )
962 + p = pEndQuote;
963 + rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) );
964 + rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' );
965 + rString.SearchAndReplaceAll( SYLK_LF, _LF );
967 + return p;
970 -void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cStr )
971 +static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr )
973 xub_StrLen n = 0;
974 while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND )
975 @@ -662,6 +687,11 @@ void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cStr )
976 rString.Insert( cStr, n );
977 n += 2;
981 +static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cStr )
983 + lcl_DoubleEscapeChar( rString, cStr );
985 rString.Insert( cStr, 0 );
986 rString.Append( cStr );
987 @@ -1285,6 +1315,7 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm )
988 SCCOL nEndCol = aRange.aEnd.Col();
989 SCROW nEndRow = aRange.aEnd.Row();
990 String aCell;
991 + bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
993 for (nRow = nStartRow; nRow <= nEndRow; nRow++)
995 @@ -1308,11 +1339,24 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm )
997 else
999 - pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1000 - if( aCell.Search( cSep ) != STRING_NOTFOUND )
1001 - lcl_WriteString( rStrm, aCell, cStr );
1002 - else
1003 - lcl_WriteSimpleString( rStrm, aCell );
1004 + pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1006 + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1007 + if( bMultiLineText )
1009 + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1010 + aCell.SearchAndReplaceAll( _LF, ' ' );
1011 + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1012 + aCell.ConvertLineEnd();
1015 + if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1016 + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1018 + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1019 + lcl_WriteString( rStrm, aCell, cStr );
1020 + else
1021 + lcl_WriteSimpleString( rStrm, aCell );
1024 break;
1025 @@ -1328,10 +1372,23 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm )
1026 default:
1028 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell );
1029 - if( aCell.Search( cSep ) != STRING_NOTFOUND )
1030 - lcl_WriteString( rStrm, aCell, cStr );
1031 - else
1032 - lcl_WriteSimpleString( rStrm, aCell );
1034 + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1035 + if( bMultiLineText )
1037 + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1038 + aCell.SearchAndReplaceAll( _LF, ' ' );
1039 + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1040 + aCell.ConvertLineEnd();
1043 + if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1044 + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1046 + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
1047 + lcl_WriteString( rStrm, aCell, cStr );
1048 + else
1049 + lcl_WriteSimpleString( rStrm, aCell );
1052 if( nCol < nEndCol )
1053 @@ -1430,8 +1487,8 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm )
1054 if( *p == '"' )
1056 bText = TRUE;
1057 - aText = '\''; // force string cell
1058 - p = lcl_ScanString( p, aText, '"', DQM_ESCAPE );
1059 + aText.Erase();
1060 + p = lcl_ScanSylkString( p, aText );
1062 else
1063 bText = FALSE;
1064 @@ -1441,7 +1498,9 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm )
1065 if ( !(*q == ';' && *(q+1) == 'I') )
1066 { // don't ignore value
1067 if( bText )
1068 - pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aText );
1070 + pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(), ScBaseCell::CreateTextCell( aText, pDoc ), (BOOL) TRUE );
1072 else
1074 double fVal = rtl_math_uStringToDouble( p,
1075 @@ -1473,7 +1532,9 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm )
1076 break;
1077 aText = '=';
1078 if( *p == '"' )
1079 - p = lcl_ScanString( p, aText, '"', DQM_ESCAPE );
1081 + p = lcl_ScanSylkString( p, aText );
1083 else
1085 const sal_Unicode* q = p;
1086 @@ -1667,14 +1728,19 @@ BOOL ScImportExport::Doc2Sylk( SvStream& rStrm )
1087 case CELLTYPE_EDIT:
1088 hasstring:
1089 pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
1090 + aCellStr.SearchAndReplaceAll( _LF, SYLK_LF );
1092 aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1093 aBufStr += String::CreateFromInt32( c );
1094 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1095 aBufStr += String::CreateFromInt32( r );
1096 aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1097 + aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "\"" ));
1098 lcl_WriteSimpleString( rStrm, aBufStr );
1099 - lcl_WriteString( rStrm, aCellStr, '"' );
1100 + lcl_DoubleEscapeChar( aCellStr, ';' );
1101 + lcl_WriteSimpleString( rStrm, aCellStr );
1102 + aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "\"" ));
1103 + lcl_WriteSimpleString( rStrm, aBufStr );
1105 checkformula:
1106 if( bForm )
1107 diff --git sc/source/ui/docshell/servobj.cxx sc/source/ui/docshell/servobj.cxx
1108 index 51e2ec6..1d07f29 100644
1109 --- sc/source/ui/docshell/servobj.cxx
1110 +++ sc/source/ui/docshell/servobj.cxx
1111 @@ -200,10 +200,12 @@ BOOL __EXPORT ScServerObject::GetData(
1112 if( aDdeTextFmt.EqualsAscii( "CSV" ) ||
1113 aDdeTextFmt.EqualsAscii( "FCSV" ) )
1114 aObj.SetSeparator( ',' );
1115 + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) );
1116 return aObj.ExportData( rMimeType, rData ) ? 1 : 0;
1119 ScImportExport aObj( pDoc, aRange );
1120 + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) );
1121 if( aObj.IsRef() )
1122 return aObj.ExportData( rMimeType, rData ) ? 1 : 0;
1123 return 0;
1124 diff --git sc/source/ui/inc/impex.hxx sc/source/ui/inc/impex.hxx
1125 index aaddeeb..d2fe3a3 100644
1126 --- sc/source/ui/inc/impex.hxx
1127 +++ sc/source/ui/inc/impex.hxx
1128 @@ -42,6 +42,17 @@ class SvStream;
1129 class SfxMedium;
1130 class ScAsciiOptions;
1132 +struct ScExportTextOptions
1134 + enum NewlineConversion { ToSystem, ToSpace, None };
1135 + ScExportTextOptions( NewlineConversion eNewlineConversion = ToSystem, sal_Unicode cSeparatorConvertTo = NULL, bool bAddQuotes = false ) :
1136 + meNewlineConversion( eNewlineConversion ), mcSeparatorConvertTo( cSeparatorConvertTo ), mbAddQuotes( bAddQuotes ) {}
1138 + NewlineConversion meNewlineConversion;
1139 + sal_Unicode mcSeparatorConvertTo; // Convert separator to this character
1140 + bool mbAddQuotes;
1143 class ScImportExport
1145 ScDocShell* pDocSh;
1146 @@ -60,6 +71,7 @@ class ScImportExport
1147 BOOL bUndo; // Mit Undo?
1148 BOOL bOverflow; // zuviele Zeilen/Spalten
1149 bool mbApi;
1150 + ScExportTextOptions mExportTextOptions;
1152 ScAsciiOptions* pExtOptions; // erweiterte Optionen
1154 @@ -138,6 +150,8 @@ public:
1156 bool IsApi() const { return mbApi; }
1157 void SetApi( bool bApi ) { mbApi = bApi; }
1158 + const ScExportTextOptions& GetExportTextOptions() { return mExportTextOptions; }
1159 + void SetExportTextOptions( const ScExportTextOptions& options ) { mExportTextOptions = options; }
1163 diff --git sc/source/ui/view/cellsh2.cxx sc/source/ui/view/cellsh2.cxx
1164 index 3e17451..365a2c7 100644
1165 --- sc/source/ui/view/cellsh2.cxx
1166 +++ sc/source/ui/view/cellsh2.cxx
1167 @@ -1064,6 +1064,7 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq )
1168 DBG_ASSERT( pDoc, "ScCellShell::ExecuteDB: SID_TEXT_TO_COLUMNS - pDoc is null!" );
1170 ScImportExport aExport( pDoc, aRange );
1171 + aExport.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::None, NULL, false ) );
1173 // #i87703# text to columns fails with tab separator
1174 aExport.SetDelimiter( static_cast< sal_Unicode >( 0 ) );
1175 diff --git sc/source/ui/view/output2.cxx sc/source/ui/view/output2.cxx
1176 index cb1aff9..d01a843 100644
1177 --- sc/source/ui/view/output2.cxx
1178 +++ sc/source/ui/view/output2.cxx
1179 @@ -1358,11 +1358,13 @@ void ScOutputData::DrawStrings( BOOL bPixelToLogic )
1181 if (bDoCell && !bNeedEdit)
1183 - if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1184 + BOOL bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA);
1185 + if ( bFormulaCell )
1186 lcl_CreateInterpretProgress( bProgress, pDoc, (ScFormulaCell*)pCell );
1187 if ( aVars.SetText(pCell) )
1188 pOldPattern = NULL;
1189 - bNeedEdit = aVars.HasEditCharacters();
1190 + bNeedEdit = aVars.HasEditCharacters() ||
1191 + (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult());
1193 if (bDoCell && !bNeedEdit)