summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2009-05-18 15:28:50 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2009-05-18 15:28:50 +0000
commit28ba39eaf96c2c4d2c0233a0cfdd18c1573bd2e6 (patch)
tree5a4c6357b61dd09b837efe1a6f79c5b7bf25c535 /sc
parentd89a147ffff3d999f5b378c27a02a5fb7e77fdd2 (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')
-rw-r--r--sc/inc/cell.hxx3
-rw-r--r--sc/inc/editutil.hxx5
-rw-r--r--sc/inc/formularesult.hxx39
-rw-r--r--sc/source/core/data/cell.cxx7
-rw-r--r--sc/source/core/data/cell2.cxx2
-rw-r--r--sc/source/core/data/column.cxx6
-rw-r--r--sc/source/core/data/column2.cxx7
-rw-r--r--sc/source/core/data/column3.cxx11
-rw-r--r--sc/source/core/tool/editutil.cxx14
-rw-r--r--sc/source/filter/dif/difimp.cxx195
-rw-r--r--sc/source/filter/excel/xestyle.cxx4
-rw-r--r--sc/source/filter/excel/xetable.cxx4
-rw-r--r--sc/source/filter/html/htmlexp.cxx26
-rw-r--r--sc/source/filter/inc/dif.hxx4
-rw-r--r--sc/source/filter/inc/xestyle.hxx5
-rw-r--r--sc/source/filter/qpro/qpro.cxx2
-rw-r--r--sc/source/filter/xml/XMLExportIterator.cxx1
-rw-r--r--sc/source/filter/xml/XMLExportIterator.hxx3
-rw-r--r--sc/source/filter/xml/xmlexprt.cxx34
-rw-r--r--sc/source/filter/xml/xmlexprt.hxx4
-rw-r--r--sc/source/ui/app/transobj.cxx7
-rw-r--r--sc/source/ui/docshell/docsh.cxx2
-rw-r--r--sc/source/ui/docshell/docsh4.cxx2
-rw-r--r--sc/source/ui/docshell/impex.cxx235
-rw-r--r--sc/source/ui/docshell/servobj.cxx2
-rw-r--r--sc/source/ui/inc/impex.hxx14
-rw-r--r--sc/source/ui/view/cellsh2.cxx1
-rw-r--r--sc/source/ui/view/output2.cxx6
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)
{