diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2009-05-18 15:28:50 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2009-05-18 15:28:50 +0000 |
commit | 28ba39eaf96c2c4d2c0233a0cfdd18c1573bd2e6 (patch) | |
tree | 5a4c6357b61dd09b837efe1a6f79c5b7bf25c535 /sc | |
parent | d89a147ffff3d999f5b378c27a02a5fb7e77fdd2 (diff) |
CWS-TOOLING: integrate CWS calcmultiline
2009-05-13 18:05:10 +0200 nn r271868 : CWS-TOOLING: rebase CWS calcmultiline to trunk@271830 (milestone: DEV300:m48)
2009-03-15 00:59:24 +0100 erack r269502 : #i100205# SYLK import/export: treat embedded double quotes and semicolons correctly; changes ID;PSCALC3 to ID;PCALCOOO32 due to incompatibility
2009-03-10 17:54:33 +0100 er r269286 : #i35913# multiline (newlines) as formula results; contributed by William S Fulton <wsfulton>
Diffstat (limited to 'sc')
28 files changed, 541 insertions, 104 deletions
diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx index b8a228ddfd09..2d4bba295547 100644 --- a/sc/inc/cell.hxx +++ b/sc/inc/cell.hxx @@ -485,6 +485,9 @@ public: inline BOOL IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); } EditTextObject* CreateURLObject() ; void GetURLResult( String& rURL, String& rCellText ); + + /** Determines whether or not the result string contains more than one paragraph */ + bool IsMultilineResult(); }; // Iterator fuer Referenzen in einer Formelzelle diff --git a/sc/inc/editutil.hxx b/sc/inc/editutil.hxx index 3e1573ac7c89..b61bdf72ef7b 100644 --- a/sc/inc/editutil.hxx +++ b/sc/inc/editutil.hxx @@ -63,8 +63,13 @@ class ScEditUtil public: static String ModifyDelimiters( const String& rOld ); + + /// Retrieves string with paragraphs delimited by spaces static String GetSpaceDelimitedString( const EditEngine& rEngine ); + /// Retrieves string with paragraphs delimited by new lines ('\n'). + static String GetMultilineString( const EditEngine& rEngine ); + public: ScEditUtil( ScDocument* pDocument, SCCOL nX, SCROW nY, SCTAB nZ, const Point& rScrPosPixel, diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx index e227dd1b7995..c8f50a92cd0b 100644 --- a/sc/inc/formularesult.hxx +++ b/sc/inc/formularesult.hxx @@ -38,6 +38,11 @@ and memory consumption. */ class ScFormulaResult { + typedef unsigned char Multiline; + static const Multiline MULTILINE_UNKNOWN = 0; + static const Multiline MULTILINE_FALSE = 1; + static const Multiline MULTILINE_TRUE = 2; + union { double mfValue; // double result direct for performance and memory consumption @@ -47,6 +52,7 @@ class ScFormulaResult bool mbToken :1; // whether content of union is a token bool mbEmpty :1; // empty cell result bool mbEmptyDisplayedAsString :1; // only if mbEmpty + Multiline meMultiline :2; // result is multiline /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults prior to assigning other types */ @@ -69,12 +75,14 @@ public: /** Effectively type svUnknown. */ ScFormulaResult() : mpToken(NULL), mnError(0), mbToken(true), - mbEmpty(false), mbEmptyDisplayedAsString(false) {} + mbEmpty(false), mbEmptyDisplayedAsString(false), + meMultiline(MULTILINE_UNKNOWN) {} ScFormulaResult( const ScFormulaResult & r ) : mnError( r.mnError), mbToken( r.mbToken), mbEmpty( r.mbEmpty), - mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString) + mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString), + meMultiline( r.meMultiline) { if (mbToken) { @@ -99,7 +107,8 @@ public: /** Same comments as for SetToken() apply! */ explicit ScFormulaResult( const formula::FormulaToken* p ) : mnError(0), mbToken(false), - mbEmpty(false), mbEmptyDisplayedAsString(false) + mbEmpty(false), mbEmptyDisplayedAsString(false), + meMultiline(MULTILINE_UNKNOWN) { SetToken( p); } @@ -153,6 +162,10 @@ public: details instead. */ inline bool IsValue() const; + /** Determines whether or not the result is a string containing more than + one paragraph */ + inline bool IsMultiline() const; + /** Get error code if set or GetCellResultType() is formula::svError or svUnknown, else 0. */ inline USHORT GetResultError() const; @@ -211,6 +224,7 @@ inline void ScFormulaResult::ResetToDefaults() mnError = 0; mbEmpty = false; mbEmptyDisplayedAsString = false; + meMultiline = MULTILINE_UNKNOWN; } @@ -232,17 +246,20 @@ inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p ) mbToken = false; // set in case mnError is 0 now, which shouldn't happen but ... mfValue = 0.0; + meMultiline = MULTILINE_FALSE; break; case formula::svEmptyCell: mbEmpty = true; mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString(); p->DecRef(); mbToken = false; + meMultiline = MULTILINE_FALSE; break; case formula::svDouble: mfValue = p->GetDouble(); p->DecRef(); mbToken = false; + meMultiline = MULTILINE_FALSE; break; default: mpToken = p; @@ -270,6 +287,7 @@ inline void ScFormulaResult::Assign( const ScFormulaResult & r ) mbToken = false; mbEmpty = true; mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString; + meMultiline = r.meMultiline; } else if (r.mbToken) { @@ -352,6 +370,7 @@ inline void ScFormulaResult::SetDouble( double f ) mpToken->DecRef(); mfValue = f; mbToken = false; + meMultiline = MULTILINE_FALSE; } } @@ -404,6 +423,19 @@ inline bool ScFormulaResult::IsValue() const return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell; } +inline bool ScFormulaResult::IsMultiline() const +{ + if (meMultiline == MULTILINE_UNKNOWN) + { + const String& rStr = GetString(); + if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND) + const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE; + else + const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE; + } + return meMultiline == MULTILINE_TRUE; +} + inline USHORT ScFormulaResult::GetResultError() const { @@ -537,6 +569,7 @@ inline void ScFormulaResult::SetHybridDouble( double f ) { mfValue = f; mbToken = false; + meMultiline = MULTILINE_FALSE; } } diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx index 0d71db3427b0..c43e1eebc6cd 100644 --- a/sc/source/core/data/cell.cxx +++ b/sc/source/core/data/cell.cxx @@ -1919,6 +1919,13 @@ void ScFormulaCell::GetURLResult( String& rURL, String& rCellText ) } } +bool ScFormulaCell::IsMultilineResult() +{ + if (!IsValue()) + return aResult.IsMultiline(); + return false; +} + EditTextObject* ScFormulaCell::CreateURLObject() { String aCellText; diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index 0dffbdefa0b7..86c87c0445d8 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -129,7 +129,7 @@ void ScEditCell::GetString( String& rString ) const // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine EditEngine& rEngine = pDoc->GetEditEngine(); rEngine.SetText( *pData ); - rString = ScEditUtil::GetSpaceDelimitedString(rEngine); // space between paragraphs + rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs // kurze Strings fuer Formeln merken if ( rString.Len() < MAXSTRLEN ) ((ScEditCell*)this)->pString = new String( rString ); //! non-const diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 68d378994c14..4c3c86c51971 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -2139,8 +2139,10 @@ BOOL ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE ) { ScBaseCell* pCell = pItems[nIndex].pCell; - if ( pCell->GetCellType() == CELLTYPE_EDIT || - IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ) + CellType eCellType = pCell->GetCellType(); + if ( eCellType == CELLTYPE_EDIT || + IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) || + ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) ) { rFirst = nRow; return TRUE; diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 97de46655741..a7a5ba39fc6a 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -319,9 +319,12 @@ long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev, } BOOL bAddMargin = TRUE; - BOOL bEditEngine = ( pCell->GetCellType() == CELLTYPE_EDIT || + CellType eCellType = pCell->GetCellType(); + + BOOL bEditEngine = ( eCellType == CELLTYPE_EDIT || eOrient == SVX_ORIENTATION_STACKED || - IsAmbiguousScript( nScript ) ); + IsAmbiguousScript( nScript ) || + ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) ); if (!bEditEngine) // direkte Ausgabe { diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 793229116fe2..bfb1890d70b0 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -846,7 +846,16 @@ ScBaseCell* ScColumn::CloneCell(SCSIZE nIndex, USHORT nFlags, ScDocument& rDestD rForm.GetString( aString ); // #33224# do not clone empty string if (aString.Len() > 0) - pNew = new ScStringCell( aString ); + { + if ( rForm.IsMultilineResult() ) + { + pNew = new ScEditCell( aString, &rDestDoc ); + } + else + { + pNew = new ScStringCell( aString ); + } + } } } break; diff --git a/sc/source/core/tool/editutil.cxx b/sc/source/core/tool/editutil.cxx index 0e9477f9015a..d08f593aaf21 100644 --- a/sc/source/core/tool/editutil.cxx +++ b/sc/source/core/tool/editutil.cxx @@ -82,19 +82,29 @@ String ScEditUtil::ModifyDelimiters( const String& rOld ) return aRet; } -String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine ) +static String lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c ) { String aRet; USHORT nParCount = rEngine.GetParagraphCount(); for (USHORT nPar=0; nPar<nParCount; nPar++) { if (nPar > 0) - aRet += ' '; + aRet += c; aRet += rEngine.GetText( nPar ); } return aRet; } +String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine ) +{ + return lcl_GetDelimitedString(rEngine, ' '); +} + +String ScEditUtil::GetMultilineString( const EditEngine& rEngine ) +{ + return lcl_GetDelimitedString(rEngine, '\n'); +} + //------------------------------------------------------------------------ Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, BOOL bForceToTop ) diff --git a/sc/source/filter/dif/difimp.cxx b/sc/source/filter/dif/difimp.cxx index 31fce4357007..cf0ccf5447a3 100644 --- a/sc/source/filter/dif/difimp.cxx +++ b/sc/source/filter/dif/difimp.cxx @@ -338,7 +338,7 @@ TOPIC DifParser::GetNextTopic( void ) while( eS != S_END ) { - if( !rIn.ReadUniOrByteStringLine( aLine ) ) + if( !ReadNextLine( aLine ) ) { eS = S_END; eRet = T_END; @@ -406,10 +406,10 @@ TOPIC DifParser::GetNextTopic( void ) break; case S_UNKNOWN: // 2 Zeilen ueberlesen - rIn.ReadUniOrByteStringLine( aLine ); + ReadNextLine( aLine ); case S_ERROR_L2: // Fehler in Line 2 aufgetreten // eine Zeile ueberlesen - rIn.ReadUniOrByteStringLine( aLine ); + ReadNextLine( aLine ); eS = S_END; break; default: @@ -421,7 +421,7 @@ TOPIC DifParser::GetNextTopic( void ) } -void lcl_DeEscapeQuotesDif( String& rString ) +static void lcl_DeEscapeQuotesDif( String& rString ) { // Special handling for DIF import: Escaped (duplicated) quotes are resolved. // Single quote characters are left in place because older versions didn't @@ -437,25 +437,107 @@ void lcl_DeEscapeQuotesDif( String& rString ) } } +// Determine if passed in string is numeric data and set fVal/nNumFormat if so +DATASET DifParser::GetNumberDataset( const sal_Unicode* pPossibleNumericData ) +{ + DATASET eRet = D_SYNT_ERROR; + if( bPlain ) + { + if( ScanFloatVal( pPossibleNumericData ) ) + eRet = D_NUMERIC; + else + eRet = D_SYNT_ERROR; + } + else + { // ...und zur Strafe mit'm Numberformatter... + DBG_ASSERT( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" ); + String aTestVal( pPossibleNumericData ); + sal_uInt32 nFormat = 0; + double fTmpVal; + if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) ) + { + fVal = fTmpVal; + nNumFormat = nFormat; + eRet = D_NUMERIC; + } + else + eRet = D_SYNT_ERROR; + } + return eRet; +} + +bool DifParser::ReadNextLine( String& rStr ) +{ + if( aLookAheadLine.Len() == 0 ) + { + return rIn.ReadUniOrByteStringLine( rStr ); + } + else + { + rStr = aLookAheadLine; + aLookAheadLine.Erase(); + return true; + } +} + +// Look ahead in the stream to determine if the next line is the first line of +// a valid data record structure +bool DifParser::LookAhead() +{ + const sal_Unicode* pAktBuffer; + bool bValidStructure = false; + + DBG_ASSERT( aLookAheadLine.Len() == 0, "*DifParser::LookAhead(): LookAhead called twice in a row" ); + rIn.ReadUniOrByteStringLine( aLookAheadLine ); + + pAktBuffer = aLookAheadLine.GetBuffer(); + + switch( *pAktBuffer ) + { + case '-': // Special Datatype + pAktBuffer++; + + if( Is1_0( pAktBuffer ) ) + { + bValidStructure = true; + } + break; + case '0': // Numeric Data + pAktBuffer++; + if( *pAktBuffer == ',' ) + { + pAktBuffer++; + bValidStructure = ( GetNumberDataset(pAktBuffer) != D_SYNT_ERROR ); + } + break; + case '1': // String Data + if( Is1_0( aLookAheadLine.GetBuffer() ) ) + { + bValidStructure = true; + } + break; + } + return bValidStructure; +} DATASET DifParser::GetNextDataset( void ) { DATASET eRet = D_UNKNOWN; String aLine; - const sal_Unicode* pAkt; + const sal_Unicode* pAktBuffer; - rIn.ReadUniOrByteStringLine( aLine ); + ReadNextLine( aLine ); - pAkt = aLine.GetBuffer(); + pAktBuffer = aLine.GetBuffer(); - switch( *pAkt ) + switch( *pAktBuffer ) { case '-': // Special Datatype - pAkt++; + pAktBuffer++; - if( Is1_0( pAkt ) ) + if( Is1_0( pAktBuffer ) ) { - rIn.ReadUniOrByteStringLine( aLine ); + ReadNextLine( aLine ); if( IsBOT( aLine.GetBuffer() ) ) eRet = D_BOT; else if( IsEOD( aLine.GetBuffer() ) ) @@ -463,37 +545,16 @@ DATASET DifParser::GetNextDataset( void ) } break; case '0': // Numeric Data - pAkt++; // Wert in fVal, 2. Zeile in aData - if( *pAkt == ',' ) + pAktBuffer++; // Wert in fVal, 2. Zeile in aData + if( *pAktBuffer == ',' ) { - pAkt++; - if( bPlain ) - { - if( ScanFloatVal( pAkt ) ) - eRet = D_NUMERIC; - else - eRet = D_SYNT_ERROR; - } - else - { // ...und zur Strafe mit'm Numberformatter... - DBG_ASSERT( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" ); - String aTestVal( pAkt ); - sal_uInt32 nFormat = 0; - double fTmpVal; - if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) ) - { - fVal = fTmpVal; - nNumFormat = nFormat; - eRet = D_NUMERIC; - } - else - eRet = D_SYNT_ERROR; - } - rIn.ReadUniOrByteStringLine( aData ); + pAktBuffer++; + eRet = GetNumberDataset(pAktBuffer); + ReadNextLine( aData ); if ( eRet == D_SYNT_ERROR ) { // for broken records write "#ERR: data" to cell String aTmp( RTL_CONSTASCII_USTRINGPARAM( "#ERR: " )); - aTmp += pAkt; + aTmp += pAktBuffer; aTmp.AppendAscii( " (" ); aTmp += aData; aTmp += sal_Unicode(')'); @@ -505,18 +566,62 @@ DATASET DifParser::GetNextDataset( void ) case '1': // String Data if( Is1_0( aLine.GetBuffer() ) ) { - rIn.ReadUniOrByteStringLine( aLine ); - DBG_ASSERT( aLine.Len() >= 2, - "*DifParser::GetNextTopic(): Text ist zu kurz (mind. \"\")!" ); - aData = aLine.Copy( 1, aLine.Len() - 2 ); - lcl_DeEscapeQuotesDif( aData ); - eRet = D_STRING; + ReadNextLine( aLine ); + xub_StrLen nLineLength = aLine.Len(); + const sal_Unicode* pLine = aLine.GetBuffer(); + + if( nLineLength >= 1 && *pLine == '"' ) + { + // Quotes are not always escaped (duplicated), see lcl_DeEscapeQuotesDif + // A look ahead into the next line is needed in order to deal with + // multiline strings containing quotes + if( LookAhead() ) + { + // Single line string + if( nLineLength >= 2 && pLine[nLineLength - 1] == '"' ) + { + aData = aLine.Copy( 1, nLineLength - 2 ); + lcl_DeEscapeQuotesDif( aData ); + eRet = D_STRING; + } + } + else + { + // Multiline string + aData = aLine.Copy( 1 ); + bool bContinue = true; + while ( bContinue ) + { + aData.Append( '\n' ); + bContinue = !rIn.IsEof() && ReadNextLine( aLine ); + if( bContinue ) + { + nLineLength = aLine.Len(); + if( nLineLength >= 1 ) + { + pLine = aLine.GetBuffer(); + bContinue = !LookAhead(); + if( bContinue ) + { + aData.Append( aLine ); + } + else if( pLine[nLineLength - 1] == '"' ) + { + aData.Append( pLine, nLineLength - 1 ); + lcl_DeEscapeQuotesDif( aData ); + eRet = D_STRING; + } + } + } + }; + } + } } break; } if( eRet == D_UNKNOWN ) - rIn.ReadUniOrByteStringLine( aLine ); + ReadNextLine( aLine ); if( rIn.IsEof() ) eRet = D_EOD; diff --git a/sc/source/filter/excel/xestyle.cxx b/sc/source/filter/excel/xestyle.cxx index a9da62f838cc..2172a7678763 100644 --- a/sc/source/filter/excel/xestyle.cxx +++ b/sc/source/filter/excel/xestyle.cxx @@ -2319,9 +2319,9 @@ sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_In return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak ); } -sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, ULONG nForceScNumFmt ) +sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, ULONG nForceScNumFmt, bool bForceLineBreak ) { - return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, false ); + return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak ); } sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet ) diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx index 5aa515b64578..fadc916d7b86 100644 --- a/sc/source/filter/excel/xetable.cxx +++ b/sc/source/filter/excel/xetable.cxx @@ -839,13 +839,15 @@ XclExpFormulaCell::XclExpFormulaCell( // #i41420# find script type according to result type (always latin for numeric results) sal_Int16 nScript = ApiScriptType::LATIN; + bool bForceLineBreak = false; if( nFormatType == NUMBERFORMAT_TEXT ) { String aResult; mrScFmlaCell.GetString( aResult ); + bForceLineBreak = mrScFmlaCell.IsMultilineResult(); nScript = XclExpStringHelper::GetLeadingScriptType( rRoot, aResult ); } - SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt ) ); + SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt, bForceLineBreak ) ); } // *** Convert the formula token array *** -------------------------------- diff --git a/sc/source/filter/html/htmlexp.cxx b/sc/source/filter/html/htmlexp.cxx index 69770c5ac6b1..ac6a5ac5705f 100644 --- a/sc/source/filter/html/htmlexp.cxx +++ b/sc/source/filter/html/htmlexp.cxx @@ -1154,9 +1154,31 @@ void ScHTMLExport::WriteCell( SCCOL nCol, SCROW nRow, SCTAB nTab ) if ( !bFieldText ) { if ( !aStrOut.Len() ) + { TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); // #42573# keine komplett leere Zelle + } else - OUT_STR( aStrOut ); + { + xub_StrLen nPos = aStrOut.Search( _LF ); + if ( nPos == STRING_NOTFOUND ) + { + OUT_STR( aStrOut ); + } + else + { + xub_StrLen nStartPos = 0; + do + { + String aSingleLine( aStrOut, nStartPos, nPos - nStartPos ); + OUT_STR( aSingleLine ); + TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); + nStartPos = nPos + 1; + } + while( ( nPos = aStrOut.Search( _LF, nStartPos ) ) != STRING_NOTFOUND ); + String aSingleLine( aStrOut, nStartPos, aStrOut.Len() - nStartPos ); + OUT_STR( aSingleLine ); + } + } } if ( pGraphEntry ) WriteGraphEntry( pGraphEntry ); @@ -1194,7 +1216,7 @@ BOOL ScHTMLExport::WriteFieldText( const ScEditCell* pCell ) for ( USHORT nPar=0; nPar < nParas; nPar++ ) { if ( nPar > 0 ) - rStrm << ' '; // blank between paragraphs + TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); SvUShorts aPortions; rEngine.GetPortions( nPar, aPortions ); USHORT nCnt = aPortions.Count(); diff --git a/sc/source/filter/inc/dif.hxx b/sc/source/filter/inc/dif.hxx index ed7b810b231a..9fc63f72f72b 100644 --- a/sc/source/filter/inc/dif.hxx +++ b/sc/source/filter/inc/dif.hxx @@ -82,7 +82,11 @@ private: SvNumberFormatter* pNumFormatter; SvStream& rIn; BOOL bPlain; + String aLookAheadLine; + bool ReadNextLine( String& rStr ); + bool LookAhead(); + DATASET GetNumberDataset( const sal_Unicode* pPossibleNumericData ); static inline BOOL IsBOT( const sal_Unicode* pRef ); static inline BOOL IsEOD( const sal_Unicode* pRef ); static inline BOOL Is1_0( const sal_Unicode* pRef ); diff --git a/sc/source/filter/inc/xestyle.hxx b/sc/source/filter/inc/xestyle.hxx index 2e1f89641b77..fb2ea876c279 100644 --- a/sc/source/filter/inc/xestyle.hxx +++ b/sc/source/filter/inc/xestyle.hxx @@ -643,10 +643,13 @@ public: @param nXFFlags Additional flags allowing to control the creation of an XF. @param nForceScNumFmt The number format to be exported, e.g. formula result type. This format will always overwrite the cell's number format. + @param bForceLineBreak true = Set line break flag unconditionally. + This is required for cells that contain multi-line text. @return A unique XF record ID. */ sal_uInt32 InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, - ULONG nForceScNumFmt ); + ULONG nForceScNumFmt, + bool bForceLineBreak ); /** Inserts the passed cell style. Creates a style XF record and a STYLE record. @return A unique XF record ID. */ sal_uInt32 InsertStyle( const SfxStyleSheetBase* pStyleSheet ); diff --git a/sc/source/filter/qpro/qpro.cxx b/sc/source/filter/qpro/qpro.cxx index cc31fcbede8b..52627c7848e4 100644 --- a/sc/source/filter/qpro/qpro.cxx +++ b/sc/source/filter/qpro/qpro.cxx @@ -71,7 +71,7 @@ FltError ScQProReader::readSheet( SCTAB nTab, ScDocument* pDoc, ScQProStyle *pSt readString( aLabel, getLength() - 7 ); nStyle = nStyle >> 3; pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle ); - pDoc->PutCell( nCol, nRow, nTab, new ScStringCell( aLabel ), (BOOL) TRUE ); + pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( aLabel, pDoc ), (BOOL) TRUE ); } break; diff --git a/sc/source/filter/xml/XMLExportIterator.cxx b/sc/source/filter/xml/XMLExportIterator.cxx index 761e34ab6ced..c4d585740339 100644 --- a/sc/source/filter/xml/XMLExportIterator.cxx +++ b/sc/source/filter/xml/XMLExportIterator.cxx @@ -568,6 +568,7 @@ ScMyCell::ScMyCell() : aShapeList(), aDetectiveObjVec(), nValidationIndex(-1), + pBaseCell(NULL), bIsAutoStyle( sal_False ), bHasShape( sal_False ), bIsMergedBase( sal_False ), diff --git a/sc/source/filter/xml/XMLExportIterator.hxx b/sc/source/filter/xml/XMLExportIterator.hxx index bcd6b4e5ae6b..d15ef94f99e6 100644 --- a/sc/source/filter/xml/XMLExportIterator.hxx +++ b/sc/source/filter/xml/XMLExportIterator.hxx @@ -48,6 +48,7 @@ class ScHorizontalCellIterator; struct ScMyCell; class ScXMLExport; class ScFormatRangeStyles; +class ScBaseCell; //============================================================================== @@ -312,6 +313,8 @@ struct ScMyCell sal_Int32 nNumberFormat; com::sun::star::table::CellContentType nType; + ScBaseCell* pBaseCell; + sal_Bool bIsAutoStyle; sal_Bool bHasShape; diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index 8dda5e3c0eec..c84d4a905283 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -2427,7 +2427,8 @@ void ScXMLExport::WriteCell (ScMyCell& aCell) if (!bIsEmpty) { - if ((aCell.nType == table::CellContentType_TEXT) && IsEditCell(aCell)) + if ((aCell.nType == table::CellContentType_TEXT && IsEditCell(aCell)) || + (aCell.nType == table::CellContentType_FORMULA && IsMultiLineFormulaCell(aCell))) { bEditCell = sal_True; uno::Reference<text::XText> xText(xCurrentTableCellRange->getCellByPosition(aCell.aCellAddress.Column, aCell.aCellAddress.Row), uno::UNO_QUERY); @@ -2842,12 +2843,15 @@ sal_Bool ScXMLExport::IsCellTypeEqual (const ScMyCell& aCell1, const ScMyCell& a return (aCell1.nType == aCell2.nType); } -sal_Bool ScXMLExport::IsEditCell(const com::sun::star::table::CellAddress& aAddress) const +sal_Bool ScXMLExport::IsEditCell(const com::sun::star::table::CellAddress& aAddress, ScMyCell* pMyCell) const { ScAddress aCoreAddress(static_cast<SCCOL>(aAddress.Column), static_cast<SCROW>(aAddress.Row), static_cast<SCTAB>(aAddress.Sheet)); ScBaseCell* pBaseCell = GetDocument() ? GetDocument()->GetCell(aCoreAddress) : NULL; + if (pMyCell) + pMyCell->pBaseCell = pBaseCell; + if (pBaseCell) return (pBaseCell->GetCellType() == CELLTYPE_EDIT); return sal_False; @@ -2867,12 +2871,36 @@ sal_Bool ScXMLExport::IsEditCell(ScMyCell& rCell) const return rCell.bIsEditCell; else { - rCell.bIsEditCell = IsEditCell(rCell.aCellAddress); + rCell.bIsEditCell = IsEditCell(rCell.aCellAddress, &rCell); rCell.bKnowWhetherIsEditCell = sal_True; return rCell.bIsEditCell; } } +sal_Bool ScXMLExport::IsMultiLineFormulaCell(ScMyCell& rCell) const +{ + if (rCell.pBaseCell) + { + if (rCell.pBaseCell->GetCellType() != CELLTYPE_FORMULA) + return false; + + return static_cast<ScFormulaCell*>(rCell.pBaseCell)->IsMultilineResult(); + } + + ScAddress aAddr(static_cast<SCCOL>(rCell.aCellAddress.Column), + static_cast<SCROW>(rCell.aCellAddress.Row), + static_cast<SCTAB>(rCell.aCellAddress.Sheet)); + ScBaseCell* pBaseCell = pDoc ? pDoc->GetCell(aAddr) : NULL; + if (!pBaseCell) + return false; + + rCell.pBaseCell = pBaseCell; + if (rCell.pBaseCell->GetCellType() != CELLTYPE_FORMULA) + return false; + + return static_cast<ScFormulaCell*>(rCell.pBaseCell)->IsMultilineResult(); +} + //UNUSED2008-05 sal_Bool ScXMLExport::IsAnnotationEqual(const uno::Reference<table::XCell>& /* xCell1 */, //UNUSED2008-05 const uno::Reference<table::XCell>& /* xCell2 */) //UNUSED2008-05 { diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx index 0ed10a5ae476..d38bd7b23970 100644 --- a/sc/source/filter/xml/xmlexprt.hxx +++ b/sc/source/filter/xml/xmlexprt.hxx @@ -62,6 +62,7 @@ class XMLNumberFormatAttributesExportHelper; class ScChartListener; class SfxItemPool; class ScAddress; +class ScBaseCell; typedef std::vector< com::sun::star::uno::Reference < com::sun::star::drawing::XShapes > > ScMyXShapesVec; @@ -187,9 +188,10 @@ class ScXMLExport : public SvXMLExport void SetRepeatAttribute (const sal_Int32 nEqualCellCount); sal_Bool IsCellTypeEqual (const ScMyCell& aCell1, const ScMyCell& aCell2) const; - sal_Bool IsEditCell(const com::sun::star::table::CellAddress& aAddress) const; + sal_Bool IsEditCell(const com::sun::star::table::CellAddress& aAddress, ScMyCell* pMyCell = NULL) const; //UNUSED2008-05 sal_Bool IsEditCell(const com::sun::star::uno::Reference <com::sun::star::table::XCell>& xCell) const; sal_Bool IsEditCell(ScMyCell& rCell) const; + sal_Bool IsMultiLineFormulaCell(ScMyCell& rCell) const; //UNUSED2008-05 sal_Bool IsAnnotationEqual(const com::sun::star::uno::Reference<com::sun::star::table::XCell>& xCell1, //UNUSED2008-05 const com::sun::star::uno::Reference<com::sun::star::table::XCell>& xCell2); sal_Bool IsCellEqual (ScMyCell& aCell1, ScMyCell& aCell2); diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx index 9e8d280403a9..076cd3581d26 100644 --- a/sc/source/ui/app/transobj.cxx +++ b/sc/source/ui/app/transobj.cxx @@ -313,6 +313,8 @@ sal_Bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor ) BOOL bIncludeFiltered = pDoc->IsCutMode() || bUsedForLink; ScImportExport aObj( pDoc, aBlock ); + if ( bUsedForLink ) + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); aObj.SetFormulas( pDoc->GetViewOptions().GetOption( VOPT_FORMULAS ) ); aObj.SetIncludeFiltered( bIncludeFiltered ); @@ -817,7 +819,10 @@ void ScTransferObj::StripRefs( ScDocument* pDoc, { String aStr; pFCell->GetString(aStr); - pNew = new ScStringCell( aStr ); + if ( pFCell->IsMultilineResult() ) + pNew = new ScEditCell( aStr, pDestDoc ); + else + pNew = new ScStringCell( aStr ); } pDestDoc->PutCell( nCol,nRow,nDestTab, pNew ); diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 4545406ac3c9..a702e6763374 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -1076,6 +1076,7 @@ BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium ) } bSetColWidths = TRUE; bSetSimpleTextColWidths = TRUE; + bSetRowHeights = TRUE; } else if (aFltName.EqualsAscii(pFilterSylk)) { @@ -1103,6 +1104,7 @@ BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium ) SetError(eError); bSetColWidths = TRUE; bSetSimpleTextColWidths = TRUE; + bSetRowHeights = TRUE; } else if (aFltName.EqualsAscii(pFilterQPro6)) { diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index 3fc430b45baa..036efee976f7 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -2424,10 +2424,12 @@ long __EXPORT ScDocShell::DdeGetData( const String& rItem, if( aDdeTextFmt.EqualsAscii( "CSV" ) || aDdeTextFmt.EqualsAscii( "FCSV" ) ) aObj.SetSeparator( ',' ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) ); return aObj.ExportData( rMimeType, rValue ) ? 1 : 0; } ScImportExport aObj( &aDocument, rItem ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) ); if( aObj.IsRef() ) return aObj.ExportData( rMimeType, rValue ) ? 1 : 0; return 0; diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx index ee1d3f676167..67186f84a84a 100644 --- a/sc/source/ui/docshell/impex.cxx +++ b/sc/source/ui/docshell/impex.cxx @@ -93,6 +93,21 @@ class StarBASIC; //======================================================================== +namespace +{ + const String SYLK_LF = String::CreateFromAscii("\x1b :"); + const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;"); + const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\""); +} + +enum SylkVersion +{ + SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons. + SYLK_OOO32, // Correct strings, plus multiline content. + SYLK_OWN, // Place our new versions, if any, before this value. + SYLK_OTHER // Assume that aliens wrote correct strings. +}; + // Gesamtdokument ohne Undo @@ -102,7 +117,7 @@ ScImportExport::ScImportExport( ScDocument* p ) nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), bFormulas( FALSE ), bIncludeFiltered( TRUE ), bAll( TRUE ), bSingle( TRUE ), bUndo( FALSE ), - bOverflow( FALSE ), mbApi( true ) + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() { pUndoDoc = NULL; pExtOptions = NULL; @@ -117,7 +132,7 @@ ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt ) nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), bFormulas( FALSE ), bIncludeFiltered( TRUE ), bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ), - bOverflow( FALSE ), mbApi( true ) + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() { pUndoDoc = NULL; pExtOptions = NULL; @@ -133,7 +148,7 @@ ScImportExport::ScImportExport( ScDocument* p, const ScRange& r ) nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), bFormulas( FALSE ), bIncludeFiltered( TRUE ), bAll( FALSE ), bSingle( FALSE ), bUndo( BOOL( pDocSh != NULL ) ), - bOverflow( FALSE ), mbApi( true ) + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() { pUndoDoc = NULL; pExtOptions = NULL; @@ -150,7 +165,7 @@ ScImportExport::ScImportExport( ScDocument* p, const String& rPos ) nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), bFormulas( FALSE ), bIncludeFiltered( TRUE ), bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ), - bOverflow( FALSE ), mbApi( true ) + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() { pUndoDoc = NULL; pExtOptions = NULL; @@ -575,6 +590,7 @@ void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rS } +// This function could be replaced by endlub() // static void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm ) { @@ -605,7 +621,7 @@ enum DoubledQuoteMode DQM_SEPARATE // end one string and begin next }; -const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString, +static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString, sal_Unicode cStr, DoubledQuoteMode eMode ) { p++; //! jump over opening quote @@ -653,8 +669,126 @@ const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString, return p; } +void lcl_UnescapeSylk( String & rString, SylkVersion eVersion ) +{ + // Older versions didn't escape the semicolon. + // Older versions quoted the string and doubled embedded quotes, but not + // the semicolons, which was plain wrong. + if (eVersion >= SYLK_OOO32) + rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' ); + else + rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' ); + + rString.SearchAndReplaceAll( SYLK_LF, _LF ); +} + +static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p, + String& rString, SylkVersion eVersion ) +{ + const sal_Unicode* pStartQuote = p; + const sal_Unicode* pEndQuote = 0; + while( *(++p) ) + { + if( *p == '"' ) + { + pEndQuote = p; + if (eVersion >= SYLK_OOO32) + { + if (*(p+1) == ';') + { + if (*(p+2) == ';') + { + p += 2; // escaped ';' + pEndQuote = 0; + } + else + break; // end field + } + } + else + { + if (*(p+1) == '"') + { + ++p; // escaped '"' + pEndQuote = 0; + } + else if (*(p+1) == ';') + break; // end field + } + } + } + if (!pEndQuote) + pEndQuote = p; // Take all data as string. + rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) ); + lcl_UnescapeSylk( rString, eVersion); + return p; +} + +static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p, + String& rString, SylkVersion eVersion ) +{ + const sal_Unicode* pStart = p; + if (eVersion >= SYLK_OOO32) + { + while (*p) + { + if (*p == ';') + { + if (*(p+1) == ';') + ++p; // escaped ';' + else + break; // end field + } + ++p; + } + rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); + lcl_UnescapeSylk( rString, eVersion); + } + else + { + // Nasty. If in old versions the formula contained a semicolon, it was + // quoted and embedded quotes were doubled, but semicolons were not. If + // there was no semicolon, it could still contain quotes and doubled + // embedded quotes if it was something like ="a""b", which was saved as + // E"a""b" as is and has to be preserved, even if older versions + // couldn't even load it correctly. However, theoretically another + // field might follow and thus the line contain a semicolon again, such + // as ...;E"a""b";... + bool bQuoted = false; + if (*p == '"') + { + // May be a quoted expression or just a string constant expression + // with quotes. + while (*(++p)) + { + if (*p == '"') + { + if (*(p+1) == '"') + ++p; // escaped '"' + else + break; // closing '"', had no ';' yet + } + else if (*p == ';') + { + bQuoted = true; // ';' within quoted expression + break; + } + } + p = pStart; + } + if (bQuoted) + p = lcl_ScanSylkString( p, rString, eVersion); + else + { + while (*p && *p != ';') + ++p; + rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); + } + } + return p; +} -void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cStr ) +static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr ) { xub_StrLen n = 0; while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND ) @@ -662,9 +796,18 @@ void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cStr ) rString.Insert( cStr, n ); n += 2; } +} - rString.Insert( cStr, 0 ); - rString.Append( cStr ); +static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc ) +{ + if (cEsc) + lcl_DoubleEscapeChar( rString, cEsc ); + + if (cQuote) + { + rString.Insert( cQuote, 0 ); + rString.Append( cQuote ); + } ScImportExport::WriteUnicodeOrByteString( rStrm, rString ); } @@ -1279,6 +1422,7 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm ) SCCOL nEndCol = aRange.aEnd.Col(); SCROW nEndRow = aRange.aEnd.Row(); String aCell; + bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF); for (nRow = nStartRow; nRow <= nEndRow; nRow++) { @@ -1296,15 +1440,28 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm ) { pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, TRUE ); if( aCell.Search( cSep ) != STRING_NOTFOUND ) - lcl_WriteString( rStrm, aCell, cStr ); + lcl_WriteString( rStrm, aCell, cStr, cStr ); else lcl_WriteSimpleString( rStrm, aCell ); } else { pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); - if( aCell.Search( cSep ) != STRING_NOTFOUND ) - lcl_WriteString( rStrm, aCell, cStr ); + + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); + if( bMultiLineText ) + { + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) + aCell.SearchAndReplaceAll( _LF, ' ' ); + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) + aCell.ConvertLineEnd(); + } + + if( mExportTextOptions.mcSeparatorConvertTo && cSep ) + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); + + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) + lcl_WriteString( rStrm, aCell, cStr, cStr ); else lcl_WriteSimpleString( rStrm, aCell ); } @@ -1322,8 +1479,21 @@ BOOL ScImportExport::Doc2Text( SvStream& rStrm ) default: { pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); - if( aCell.Search( cSep ) != STRING_NOTFOUND ) - lcl_WriteString( rStrm, aCell, cStr ); + + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); + if( bMultiLineText ) + { + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) + aCell.SearchAndReplaceAll( _LF, ' ' ); + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) + aCell.ConvertLineEnd(); + } + + if( mExportTextOptions.mcSeparatorConvertTo && cSep ) + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); + + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) + lcl_WriteString( rStrm, aCell, cStr, cStr ); else lcl_WriteSimpleString( rStrm, aCell ); } @@ -1348,6 +1518,7 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) { BOOL bOk = TRUE; BOOL bMyDoc = FALSE; + SylkVersion eVersion = SYLK_OTHER; // US-English separators for StringToDouble sal_Unicode cDecSep = '.'; @@ -1424,8 +1595,8 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) if( *p == '"' ) { bText = TRUE; - aText = '\''; // force string cell - p = lcl_ScanString( p, aText, '"', DQM_ESCAPE ); + aText.Erase(); + p = lcl_ScanSylkString( p, aText, eVersion); } else bText = FALSE; @@ -1435,7 +1606,11 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) if ( !(*q == ';' && *(q+1) == 'I') ) { // don't ignore value if( bText ) - pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aText ); + { + pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(), + ScBaseCell::CreateTextCell( aText, pDoc), + (BOOL) TRUE); + } else { double fVal = rtl_math_uStringToDouble( p, @@ -1466,15 +1641,7 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) if( !bMyDoc || !bData ) break; aText = '='; - if( *p == '"' ) - p = lcl_ScanString( p, aText, '"', DQM_ESCAPE ); - else - { - const sal_Unicode* q = p; - while( *p && *p != ';' ) - p++; - aText.Append( q, sal::static_int_cast<xub_StrLen>( p-q ) ); - } + p = lcl_ScanSylkFormula( p, aText, eVersion); ScAddress aPos( nCol, nRow, aRange.aStart.Tab() ); /* FIXME: do we want GRAM_ODFF_A1 instead? At the * end it probably should be GRAM_ODFF_R1C1, since @@ -1584,7 +1751,11 @@ BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) else if( cTag == 'I' && *p == 'D' ) { aLine.Erase( 0, 4 ); - bMyDoc = aLine.EqualsAscii( "SCALC3" ); + if (aLine.EqualsAscii( "CALCOOO32" )) + eVersion = SYLK_OOO32; + else if (aLine.EqualsAscii( "SCALC3" )) + eVersion = SYLK_SCALC3; + bMyDoc = (eVersion <= SYLK_OWN); } else if( cTag == 'E' ) // Ende break; @@ -1616,7 +1787,7 @@ BOOL ScImportExport::Doc2Sylk( SvStream& rStrm ) String aCellStr; String aValStr; lcl_WriteSimpleString( rStrm, - String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( "ID;PSCALC3" )) ); + String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32"))); WriteUnicodeOrByteEndl( rStrm ); for (nRow = nStartRow; nRow <= nEndRow; nRow++) @@ -1661,6 +1832,7 @@ BOOL ScImportExport::Doc2Sylk( SvStream& rStrm ) case CELLTYPE_EDIT: hasstring: pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr ); + aCellStr.SearchAndReplaceAll( _LF, SYLK_LF ); aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); aBufStr += String::CreateFromInt32( c ); @@ -1668,7 +1840,7 @@ BOOL ScImportExport::Doc2Sylk( SvStream& rStrm ) aBufStr += String::CreateFromInt32( r ); aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); lcl_WriteSimpleString( rStrm, aBufStr ); - lcl_WriteString( rStrm, aCellStr, '"' ); + lcl_WriteString( rStrm, aCellStr, '"', ';' ); checkformula: if( bForm ) @@ -1730,12 +1902,7 @@ BOOL ScImportExport::Doc2Sylk( SvStream& rStrm ) } lcl_WriteSimpleString( rStrm, aPrefix ); if ( aCellStr.Len() ) - { - if( aCellStr.Search( ';' ) != STRING_NOTFOUND ) - lcl_WriteString( rStrm, aCellStr, '"' ); - else - lcl_WriteSimpleString( rStrm, aCellStr ); - } + lcl_WriteString( rStrm, aCellStr, 0, ';' ); } WriteUnicodeOrByteEndl( rStrm ); break; diff --git a/sc/source/ui/docshell/servobj.cxx b/sc/source/ui/docshell/servobj.cxx index dafb3077bf27..aeb4b6604e67 100644 --- a/sc/source/ui/docshell/servobj.cxx +++ b/sc/source/ui/docshell/servobj.cxx @@ -200,10 +200,12 @@ BOOL __EXPORT ScServerObject::GetData( if( aDdeTextFmt.EqualsAscii( "CSV" ) || aDdeTextFmt.EqualsAscii( "FCSV" ) ) aObj.SetSeparator( ',' ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); return aObj.ExportData( rMimeType, rData ) ? 1 : 0; } ScImportExport aObj( pDoc, aRange ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); if( aObj.IsRef() ) return aObj.ExportData( rMimeType, rData ) ? 1 : 0; return 0; diff --git a/sc/source/ui/inc/impex.hxx b/sc/source/ui/inc/impex.hxx index 3c20903ddbb2..fb4dcaa83958 100644 --- a/sc/source/ui/inc/impex.hxx +++ b/sc/source/ui/inc/impex.hxx @@ -42,6 +42,17 @@ class SvStream; class SfxMedium; class ScAsciiOptions; +struct ScExportTextOptions +{ + enum NewlineConversion { ToSystem, ToSpace, None }; + ScExportTextOptions( NewlineConversion eNewlineConversion = ToSystem, sal_Unicode cSeparatorConvertTo = 0, bool bAddQuotes = false ) : + meNewlineConversion( eNewlineConversion ), mcSeparatorConvertTo( cSeparatorConvertTo ), mbAddQuotes( bAddQuotes ) {} + + NewlineConversion meNewlineConversion; + sal_Unicode mcSeparatorConvertTo; // Convert separator to this character + bool mbAddQuotes; +}; + class ScImportExport { ScDocShell* pDocSh; @@ -60,6 +71,7 @@ class ScImportExport BOOL bUndo; // Mit Undo? BOOL bOverflow; // zuviele Zeilen/Spalten bool mbApi; + ScExportTextOptions mExportTextOptions; ScAsciiOptions* pExtOptions; // erweiterte Optionen @@ -138,6 +150,8 @@ public: bool IsApi() const { return mbApi; } void SetApi( bool bApi ) { mbApi = bApi; } + const ScExportTextOptions& GetExportTextOptions() { return mExportTextOptions; } + void SetExportTextOptions( const ScExportTextOptions& options ) { mExportTextOptions = options; } }; diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index e4e9af72f271..564053a937ef 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -1067,6 +1067,7 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq ) DBG_ASSERT( pDoc, "ScCellShell::ExecuteDB: SID_TEXT_TO_COLUMNS - pDoc is null!" ); ScImportExport aExport( pDoc, aRange ); + aExport.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::None, 0, false ) ); // #i87703# text to columns fails with tab separator aExport.SetDelimiter( static_cast< sal_Unicode >( 0 ) ); diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index e41bd4941d9c..dd76058756a1 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -1358,11 +1358,13 @@ void ScOutputData::DrawStrings( BOOL bPixelToLogic ) } if (bDoCell && !bNeedEdit) { - if ( pCell->GetCellType() == CELLTYPE_FORMULA ) + BOOL bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA ); + if ( bFormulaCell ) lcl_CreateInterpretProgress( bProgress, pDoc, (ScFormulaCell*)pCell ); if ( aVars.SetText(pCell) ) pOldPattern = NULL; - bNeedEdit = aVars.HasEditCharacters(); + bNeedEdit = aVars.HasEditCharacters() || + (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult()); } if (bDoCell && !bNeedEdit) { |