xref: /trunk/main/sc/source/filter/excel/xihelper.cxx (revision b77af630)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scfilt.hxx"
26 #include "xihelper.hxx"
27 #include <svl/itemset.hxx>
28 #include <editeng/editobj.hxx>
29 #include <tools/urlobj.hxx>
30 #include "scitems.hxx"
31 #include <editeng/eeitem.hxx>
32 #include <editeng/flditem.hxx>
33 #include "document.hxx"
34 #include "cell.hxx"
35 #include "rangelst.hxx"
36 #include "editutil.hxx"
37 #include "attrib.hxx"
38 #include "xltracer.hxx"
39 #include "xistream.hxx"
40 #include "xistyle.hxx"
41 
42 #include "excform.hxx"
43 
44 // Excel->Calc cell address/range conversion ==================================
45 
46 namespace {
47 
48 /** Fills the passed Calc address with the passed Excel cell coordinates without checking any limits. */
lclFillAddress(ScAddress & rScPos,sal_uInt16 nXclCol,sal_uInt16 nXclRow,SCTAB nScTab)49 inline void lclFillAddress( ScAddress& rScPos, sal_uInt16 nXclCol, sal_uInt16 nXclRow, SCTAB nScTab )
50 {
51     rScPos.SetCol( static_cast< SCCOL >( nXclCol ) );
52     rScPos.SetRow( static_cast< SCROW >( nXclRow ) );
53     rScPos.SetTab( nScTab );
54 }
55 
56 } // namespace
57 
58 // ----------------------------------------------------------------------------
59 
XclImpAddressConverter(const XclImpRoot & rRoot)60 XclImpAddressConverter::XclImpAddressConverter( const XclImpRoot& rRoot ) :
61     XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetScMaxPos() )
62 {
63 }
64 
65 // cell address ---------------------------------------------------------------
66 
CheckAddress(const XclAddress & rXclPos,bool bWarn)67 bool XclImpAddressConverter::CheckAddress( const XclAddress& rXclPos, bool bWarn )
68 {
69     bool bValidCol = rXclPos.mnCol <= mnMaxCol;
70     bool bValidRow = rXclPos.mnRow <= mnMaxRow;
71     bool bValid = bValidCol && bValidRow;
72     if( !bValid && bWarn )
73     {
74         mbColTrunc |= !bValidCol;
75         mbRowTrunc |= !bValidRow;
76         mrTracer.TraceInvalidAddress( ScAddress(
77             static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), 0 ), maMaxPos );
78     }
79     return bValid;
80 }
81 
ConvertAddress(ScAddress & rScPos,const XclAddress & rXclPos,SCTAB nScTab,bool bWarn)82 bool XclImpAddressConverter::ConvertAddress( ScAddress& rScPos,
83         const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
84 {
85     bool bValid = CheckAddress( rXclPos, bWarn );
86     if( bValid )
87         lclFillAddress( rScPos, rXclPos.mnCol, rXclPos.mnRow, nScTab );
88     return bValid;
89 }
90 
CreateValidAddress(const XclAddress & rXclPos,SCTAB nScTab,bool bWarn)91 ScAddress XclImpAddressConverter::CreateValidAddress(
92         const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
93 {
94     ScAddress aScPos( ScAddress::UNINITIALIZED );
95     if( !ConvertAddress( aScPos, rXclPos, nScTab, bWarn ) )
96     {
97         aScPos.SetCol( static_cast< SCCOL >( ::std::min( rXclPos.mnCol, mnMaxCol ) ) );
98         aScPos.SetRow( static_cast< SCROW >( ::std::min( rXclPos.mnRow, mnMaxRow ) ) );
99         aScPos.SetTab( limit_cast< SCTAB >( nScTab, 0, maMaxPos.Tab() ) );
100     }
101     return aScPos;
102 }
103 
104 // cell range -----------------------------------------------------------------
105 
CheckRange(const XclRange & rXclRange,bool bWarn)106 bool XclImpAddressConverter::CheckRange( const XclRange& rXclRange, bool bWarn )
107 {
108     return CheckAddress( rXclRange.maFirst, bWarn ) && CheckAddress( rXclRange.maLast, bWarn );
109 }
110 
ConvertRange(ScRange & rScRange,const XclRange & rXclRange,SCTAB nScTab1,SCTAB nScTab2,bool bWarn)111 bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
112         const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
113 {
114     // check start position
115     bool bValidStart = CheckAddress( rXclRange.maFirst, bWarn );
116     if( bValidStart )
117     {
118         lclFillAddress( rScRange.aStart, rXclRange.maFirst.mnCol, rXclRange.maFirst.mnRow, nScTab1 );
119 
120         // check & correct end position
121         sal_uInt16 nXclCol2 = rXclRange.maLast.mnCol;
122         sal_uInt16 nXclRow2 = rXclRange.maLast.mnRow;
123         if( !CheckAddress( rXclRange.maLast, bWarn ) )
124         {
125             nXclCol2 = ::std::min( nXclCol2, mnMaxCol );
126             nXclRow2 = ::std::min( nXclRow2, mnMaxRow );
127         }
128         lclFillAddress( rScRange.aEnd, nXclCol2, nXclRow2, nScTab2 );
129     }
130     return bValidStart;
131 }
132 
133 //UNUSED2009-05 ScRange XclImpAddressConverter::CreateValidRange(
134 //UNUSED2009-05         const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
135 //UNUSED2009-05 {
136 //UNUSED2009-05     return ScRange(
137 //UNUSED2009-05         CreateValidAddress( rXclRange.maFirst, nScTab1, bWarn ),
138 //UNUSED2009-05         CreateValidAddress( rXclRange.maLast,  nScTab2, bWarn ) );
139 //UNUSED2009-05 }
140 
141 // cell range list ------------------------------------------------------------
142 
143 //UNUSED2009-05 bool XclImpAddressConverter::CheckRangeList( const XclRangeList& rXclRanges, bool bWarn )
144 //UNUSED2009-05 {
145 //UNUSED2009-05     for( XclRangeList::const_iterator aIt = rXclRanges.begin(), aEnd = rXclRanges.end(); aIt != aEnd; ++aIt )
146 //UNUSED2009-05         if( !CheckRange( *aIt, bWarn ) )
147 //UNUSED2009-05             return false;
148 //UNUSED2009-05     return true;
149 //UNUSED2009-05 }
150 
ConvertRangeList(ScRangeList & rScRanges,const XclRangeList & rXclRanges,SCTAB nScTab,bool bWarn)151 void XclImpAddressConverter::ConvertRangeList( ScRangeList& rScRanges,
152         const XclRangeList& rXclRanges, SCTAB nScTab, bool bWarn )
153 {
154     rScRanges.RemoveAll();
155     for( XclRangeList::const_iterator aIt = rXclRanges.begin(), aEnd = rXclRanges.end(); aIt != aEnd; ++aIt )
156     {
157         ScRange aScRange( ScAddress::UNINITIALIZED );
158         if( ConvertRange( aScRange, *aIt, nScTab, nScTab, bWarn ) )
159             rScRanges.Append( aScRange );
160     }
161 }
162 
163 // String->EditEngine conversion ==============================================
164 
165 namespace {
166 
lclCreateTextObject(const XclImpRoot & rRoot,const XclImpString & rString,XclFontItemType eType,sal_uInt16 nXFIndex)167 EditTextObject* lclCreateTextObject( const XclImpRoot& rRoot,
168         const XclImpString& rString, XclFontItemType eType, sal_uInt16 nXFIndex )
169 {
170     EditTextObject* pTextObj = 0;
171 
172     const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
173     const XclImpFont* pFirstFont = rXFBuffer.GetFont( nXFIndex );
174     bool bFirstEscaped = pFirstFont && pFirstFont->HasEscapement();
175 
176     if( rString.IsRich() || bFirstEscaped )
177     {
178         const XclImpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
179         const XclFormatRunVec& rFormats = rString.GetFormats();
180 
181         ScEditEngineDefaulter& rEE = (eType == EXC_FONTITEM_NOTE) ?
182             static_cast< ScEditEngineDefaulter& >( rRoot.GetDoc().GetNoteEngine() ) : rRoot.GetEditEngine();
183         rEE.SetText( rString.GetText() );
184 
185         SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
186         if( bFirstEscaped )
187             rFontBuffer.FillToItemSet( aItemSet, eType, rXFBuffer.GetFontIndex( nXFIndex ) );
188         ESelection aSelection;
189 
190         XclFormatRun aNextRun;
191         XclFormatRunVec::const_iterator aIt = rFormats.begin();
192         XclFormatRunVec::const_iterator aEnd = rFormats.end();
193 
194         if( aIt != aEnd )
195             aNextRun = *aIt++;
196         else
197             aNextRun.mnChar = 0xFFFF;
198 
199         xub_StrLen nLen = rString.GetText().Len();
200         for( sal_uInt16 nChar = 0; nChar < nLen; ++nChar )
201         {
202             // reached new different formatted text portion
203             if( nChar >= aNextRun.mnChar )
204             {
205                 // send items to edit engine
206                 rEE.QuickSetAttribs( aItemSet, aSelection );
207 
208                 // start new item set
209                 aItemSet.ClearItem();
210                 rFontBuffer.FillToItemSet( aItemSet, eType, aNextRun.mnFontIdx );
211 
212                 // read new formatting information
213                 if( aIt != aEnd )
214                     aNextRun = *aIt++;
215                 else
216                     aNextRun.mnChar = 0xFFFF;
217 
218                 // reset selection start to current position
219                 aSelection.nStartPara = aSelection.nEndPara;
220                 aSelection.nStartPos = aSelection.nEndPos;
221             }
222 
223             // set end of selection to current position
224             if( rString.GetText().GetChar( nChar ) == '\n' )
225             {
226                 ++aSelection.nEndPara;
227                 aSelection.nEndPos = 0;
228             }
229             else
230                 ++aSelection.nEndPos;
231         }
232 
233         // send items of last text portion to edit engine
234         rEE.QuickSetAttribs( aItemSet, aSelection );
235 
236         pTextObj = rEE.CreateTextObject();
237     }
238 
239     return pTextObj;
240 }
241 
242 } // namespace
243 
CreateTextObject(const XclImpRoot & rRoot,const XclImpString & rString)244 EditTextObject* XclImpStringHelper::CreateTextObject(
245         const XclImpRoot& rRoot, const XclImpString& rString )
246 {
247     return lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, 0 );
248 }
249 
250 //UNUSED2009-05 EditTextObject* XclImpStringHelper::CreateNoteObject(
251 //UNUSED2009-05         const XclImpRoot& rRoot, const XclImpString& rString )
252 //UNUSED2009-05 {
253 //UNUSED2009-05     return lclCreateTextObject( rRoot, rString, EXC_FONTITEM_NOTE, 0 );
254 //UNUSED2009-05 }
255 
CreateCell(const XclImpRoot & rRoot,const XclImpString & rString,sal_uInt16 nXFIndex)256 ScBaseCell* XclImpStringHelper::CreateCell(
257         const XclImpRoot& rRoot, const XclImpString& rString, sal_uInt16 nXFIndex )
258 {
259     ScBaseCell* pCell = 0;
260 
261     if( rString.GetText().Len() )
262     {
263         ::std::auto_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, nXFIndex ) );
264         ScDocument& rDoc = rRoot.GetDoc();
265 
266         if( pTextObj.get() )
267             // ScEditCell creates own copy of text object
268             pCell = new ScEditCell( pTextObj.get(), &rDoc, rRoot.GetEditEngine().GetEditTextObjectPool() );
269         else
270             pCell = ScBaseCell::CreateTextCell( rString.GetText(), &rDoc );
271     }
272 
273     return pCell;
274 }
275 
276 // Header/footer conversion ===================================================
277 
XclImpHFPortionInfo()278 XclImpHFConverter::XclImpHFPortionInfo::XclImpHFPortionInfo() :
279     mnHeight( 0 ),
280     mnMaxLineHt( 0 )
281 {
282     maSel.nStartPara = maSel.nEndPara = 0;
283     maSel.nStartPos = maSel.nEndPos = 0;
284 }
285 
286 // ----------------------------------------------------------------------------
287 
XclImpHFConverter(const XclImpRoot & rRoot)288 XclImpHFConverter::XclImpHFConverter( const XclImpRoot& rRoot ) :
289     XclImpRoot( rRoot ),
290     mrEE( rRoot.GetHFEditEngine() ),
291     mxFontData( new XclFontData ),
292     meCurrObj( EXC_HF_CENTER )
293 {
294 }
295 
~XclImpHFConverter()296 XclImpHFConverter::~XclImpHFConverter()
297 {
298 }
299 
ParseString(const String & rHFString)300 void XclImpHFConverter::ParseString( const String& rHFString )
301 {
302     // edit engine objects
303     mrEE.SetText( EMPTY_STRING );
304     maInfos.clear();
305     maInfos.resize( EXC_HF_PORTION_COUNT );
306     meCurrObj = EXC_HF_CENTER;
307 
308     // parser temporaries
309     maCurrText.Erase();
310     String aReadFont;           // current font name
311     String aReadStyle;          // current font style
312     sal_uInt16 nReadHeight = 0; // current font height
313     ResetFontData();
314 
315     /** State of the parser. */
316     enum XclHFParserState
317     {
318         xlPSText,           /// Read text, search for functions.
319         xlPSFunc,           /// Read function (token following a '&').
320         xlPSFont,           /// Read font name ('&' is followed by '"', reads until next '"' or ',').
321         xlPSFontStyle,      /// Read font style name (font part after ',', reads until next '"').
322         xlPSHeight          /// Read font height ('&' is followed by num. digits, reads until non-digit).
323     } eState = xlPSText;
324 
325     const sal_Unicode* pChar = rHFString.GetBuffer();
326     const sal_Unicode* pNull = pChar + rHFString.Len(); // pointer to teminating null char
327     while( *pChar )
328     {
329         switch( eState )
330         {
331 
332 // --- read text character ---
333 
334             case xlPSText:
335             {
336                 switch( *pChar )
337                 {
338                     case '&':           // new command
339                         InsertText();
340                         eState = xlPSFunc;
341                     break;
342                     case '\n':          // line break
343                         InsertText();
344                         InsertLineBreak();
345                     break;
346                     default:
347                         maCurrText += *pChar;
348                 }
349             }
350             break;
351 
352 // --- read control sequence ---
353 
354             case xlPSFunc:
355             {
356                 eState = xlPSText;
357                 switch( *pChar )
358                 {
359                     case '&':   maCurrText += '&';  break;  // the '&' character
360 
361                     case 'L':   SetNewPortion( EXC_HF_LEFT );   break;  // Left portion
362                     case 'C':   SetNewPortion( EXC_HF_CENTER ); break;  // Center portion
363                     case 'R':   SetNewPortion( EXC_HF_RIGHT );  break;  // Right portion
364 
365                     case 'P':   InsertField( SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ) );      break;  // page
366                     case 'N':   InsertField( SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ) );     break;  // page count
367                     case 'D':   InsertField( SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ) );      break;  // date
368                     case 'T':   InsertField( SvxFieldItem( SvxTimeField(), EE_FEATURE_FIELD ) );      break;  // time
369                     case 'A':   InsertField( SvxFieldItem( SvxTableField(), EE_FEATURE_FIELD ) );     break;  // table name
370 
371                     case 'Z':           // file path
372                         InsertField( SvxFieldItem( SvxExtFileField(), EE_FEATURE_FIELD ) );   // convert to full name
373                         if( (pNull - pChar >= 2) && (*(pChar + 1) == '&') && (*(pChar + 2) == 'F') )
374                         {
375                             // &Z&F found - ignore the &F part
376                             pChar += 2;
377                         }
378                     break;
379                     case 'F':           // file name
380                         InsertField( SvxFieldItem( SvxExtFileField( EMPTY_STRING, SVXFILETYPE_VAR, SVXFILEFORMAT_NAME_EXT ), EE_FEATURE_FIELD ) );
381                     break;
382 
383                     case 'U':           // underline
384                         SetAttribs();
385                         mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_SINGLE) ?
386                             EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_SINGLE;
387                     break;
388                     case 'E':           // double underline
389                         SetAttribs();
390                         mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_DOUBLE) ?
391                             EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_DOUBLE;
392                     break;
393                     case 'S':           // strikeout
394                         SetAttribs();
395                         mxFontData->mbStrikeout = !mxFontData->mbStrikeout;
396                     break;
397                     case 'X':           // superscript
398                         SetAttribs();
399                         mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUPER) ?
400                             EXC_FONTESC_NONE : EXC_FONTESC_SUPER;
401                     break;
402                     case 'Y':           // subsrcipt
403                         SetAttribs();
404                         mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUB) ?
405                             EXC_FONTESC_NONE : EXC_FONTESC_SUB;
406                     break;
407 
408                     case '\"':          // font name
409                         aReadFont.Erase();
410                         aReadStyle.Erase();
411                         eState = xlPSFont;
412                     break;
413                     default:
414                         if( ('0' <= *pChar) && (*pChar <= '9') )    // font size
415                         {
416                             nReadHeight = *pChar - '0';
417                             eState = xlPSHeight;
418                         }
419                 }
420             }
421             break;
422 
423 // --- read font name ---
424 
425             case xlPSFont:
426             {
427                 switch( *pChar )
428                 {
429                     case '\"':
430                         --pChar;
431                         // run through
432                     case ',':
433                         eState = xlPSFontStyle;
434                     break;
435                     default:
436                         aReadFont += *pChar;
437                 }
438             }
439             break;
440 
441 // --- read font style ---
442 
443             case xlPSFontStyle:
444             {
445                 switch( *pChar )
446                 {
447                     case '\"':
448                         SetAttribs();
449                         if( aReadFont.Len() )
450                             mxFontData->maName = aReadFont;
451                         mxFontData->maStyle = aReadStyle;
452                         eState = xlPSText;
453                     break;
454                     default:
455                         aReadStyle += *pChar;
456                 }
457             }
458             break;
459 
460 // --- read font height ---
461 
462             case xlPSHeight:
463             {
464                 if( ('0' <= *pChar) && (*pChar <= '9') )
465                 {
466                     if( nReadHeight != 0xFFFF )
467                     {
468                         nReadHeight *= 10;
469                         nReadHeight += (*pChar - '0');
470                         if( nReadHeight > 1600 )    // max 1600pt = 32000twips
471                             nReadHeight = 0xFFFF;
472                     }
473                 }
474                 else
475                 {
476                     if( (nReadHeight != 0) && (nReadHeight != 0xFFFF) )
477                     {
478                         SetAttribs();
479                         mxFontData->mnHeight = nReadHeight * 20;
480                     }
481                     --pChar;
482                     eState = xlPSText;
483                 }
484             }
485             break;
486         }
487         ++pChar;
488     }
489 
490     // finalize
491     CreateCurrObject();
492     maInfos[ EXC_HF_LEFT   ].mnHeight += GetMaxLineHeight( EXC_HF_LEFT );
493     maInfos[ EXC_HF_CENTER ].mnHeight += GetMaxLineHeight( EXC_HF_CENTER );
494     maInfos[ EXC_HF_RIGHT  ].mnHeight += GetMaxLineHeight( EXC_HF_RIGHT );
495 }
496 
FillToItemSet(SfxItemSet & rItemSet,sal_uInt16 nWhichId) const497 void XclImpHFConverter::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nWhichId ) const
498 {
499     ScPageHFItem aHFItem( nWhichId );
500     if( maInfos[ EXC_HF_LEFT ].mxObj.get() )
501         aHFItem.SetLeftArea( *maInfos[ EXC_HF_LEFT ].mxObj );
502     if( maInfos[ EXC_HF_CENTER ].mxObj.get() )
503         aHFItem.SetCenterArea( *maInfos[ EXC_HF_CENTER ].mxObj );
504     if( maInfos[ EXC_HF_RIGHT ].mxObj.get() )
505         aHFItem.SetRightArea( *maInfos[ EXC_HF_RIGHT ].mxObj );
506     rItemSet.Put( aHFItem );
507 }
508 
GetTotalHeight() const509 sal_Int32 XclImpHFConverter::GetTotalHeight() const
510 {
511     return ::std::max( maInfos[ EXC_HF_LEFT ].mnHeight,
512         ::std::max( maInfos[ EXC_HF_CENTER ].mnHeight, maInfos[ EXC_HF_RIGHT ].mnHeight ) );
513 }
514 
515 // private --------------------------------------------------------------------
516 
GetMaxLineHeight(XclImpHFPortion ePortion) const517 sal_uInt16 XclImpHFConverter::GetMaxLineHeight( XclImpHFPortion ePortion ) const
518 {
519     sal_uInt16 nMaxHt = maInfos[ ePortion ].mnMaxLineHt;
520     return (nMaxHt == 0) ? mxFontData->mnHeight : nMaxHt;
521 }
522 
GetCurrMaxLineHeight() const523 sal_uInt16 XclImpHFConverter::GetCurrMaxLineHeight() const
524 {
525     return GetMaxLineHeight( meCurrObj );
526 }
527 
UpdateMaxLineHeight(XclImpHFPortion ePortion)528 void XclImpHFConverter::UpdateMaxLineHeight( XclImpHFPortion ePortion )
529 {
530     sal_uInt16& rnMaxHt = maInfos[ ePortion ].mnMaxLineHt;
531     rnMaxHt = ::std::max( rnMaxHt, mxFontData->mnHeight );
532 }
533 
UpdateCurrMaxLineHeight()534 void XclImpHFConverter::UpdateCurrMaxLineHeight()
535 {
536     UpdateMaxLineHeight( meCurrObj );
537 }
538 
SetAttribs()539 void XclImpHFConverter::SetAttribs()
540 {
541     ESelection& rSel = GetCurrSel();
542     if( (rSel.nStartPara != rSel.nEndPara) || (rSel.nStartPos != rSel.nEndPos) )
543     {
544         SfxItemSet aItemSet( mrEE.GetEmptyItemSet() );
545         XclImpFont aFont( GetRoot(), *mxFontData );
546         aFont.FillToItemSet( aItemSet, EXC_FONTITEM_HF );
547         mrEE.QuickSetAttribs( aItemSet, rSel );
548         rSel.nStartPara = rSel.nEndPara;
549         rSel.nStartPos = rSel.nEndPos;
550     }
551 }
552 
ResetFontData()553 void XclImpHFConverter::ResetFontData()
554 {
555     if( const XclImpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
556         *mxFontData = pFirstFont->GetFontData();
557     else
558     {
559         mxFontData->Clear();
560         mxFontData->mnHeight = 200;
561     }
562 }
563 
InsertText()564 void XclImpHFConverter::InsertText()
565 {
566     if( maCurrText.Len() )
567     {
568         ESelection& rSel = GetCurrSel();
569         mrEE.QuickInsertText( maCurrText, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
570         rSel.nEndPos = rSel.nEndPos + maCurrText.Len();
571         maCurrText.Erase();
572         UpdateCurrMaxLineHeight();
573     }
574 }
575 
InsertField(const SvxFieldItem & rFieldItem)576 void XclImpHFConverter::InsertField( const SvxFieldItem& rFieldItem )
577 {
578     ESelection& rSel = GetCurrSel();
579     mrEE.QuickInsertField( rFieldItem, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
580     ++rSel.nEndPos;
581     UpdateCurrMaxLineHeight();
582 }
583 
InsertLineBreak()584 void XclImpHFConverter::InsertLineBreak()
585 {
586     ESelection& rSel = GetCurrSel();
587     mrEE.QuickInsertText( String( '\n' ), ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
588     ++rSel.nEndPara;
589     rSel.nEndPos = 0;
590     GetCurrInfo().mnHeight += GetCurrMaxLineHeight();
591     GetCurrInfo().mnMaxLineHt = 0;
592 }
593 
CreateCurrObject()594 void XclImpHFConverter::CreateCurrObject()
595 {
596     InsertText();
597     SetAttribs();
598     GetCurrObj().reset( mrEE.CreateTextObject() );
599 }
600 
SetNewPortion(XclImpHFPortion eNew)601 void XclImpHFConverter::SetNewPortion( XclImpHFPortion eNew )
602 {
603     if( eNew != meCurrObj )
604     {
605         CreateCurrObject();
606         meCurrObj = eNew;
607         if( GetCurrObj().get() )
608             mrEE.SetText( *GetCurrObj() );
609         else
610             mrEE.SetText( EMPTY_STRING );
611         ResetFontData();
612     }
613 }
614 
615 // URL conversion =============================================================
616 
617 namespace {
618 
lclAppendUrlChar(String & rUrl,sal_Unicode cChar)619 void lclAppendUrlChar( String& rUrl, sal_Unicode cChar )
620 {
621     // #126855# encode special characters
622     switch( cChar )
623     {
624         case '#':   rUrl.AppendAscii( "%23" );  break;
625         case '%':   rUrl.AppendAscii( "%25" );  break;
626         default:    rUrl.Append( cChar );
627     }
628 }
629 
630 } // namespace
631 
DecodeUrl(String & rUrl,String & rTabName,bool & rbSameWb,const XclImpRoot & rRoot,const String & rEncodedUrl)632 void XclImpUrlHelper::DecodeUrl(
633         String& rUrl, String& rTabName, bool& rbSameWb,
634         const XclImpRoot& rRoot, const String& rEncodedUrl )
635 {
636     enum
637     {
638         xlUrlInit,              /// Initial state, read string mode character.
639         xlUrlPath,              /// Read URL path.
640         xlUrlFileName,          /// Read file name.
641         xlUrlSheetName,         /// Read sheet name.
642         xlUrlRaw                /// Raw mode. No control characters will occur.
643     } eState = xlUrlInit;
644 
645     bool bEncoded = true;
646     rbSameWb = false;
647 
648     sal_Unicode cCurrDrive = 0;
649     String aDosBase( INetURLObject( rRoot.GetBasePath() ).getFSysPath( INetURLObject::FSYS_DOS ) );
650     if( (aDosBase.Len() > 2) && aDosBase.EqualsAscii( ":\\", 1, 2 ) )
651         cCurrDrive = aDosBase.GetChar( 0 );
652 
653     const sal_Unicode* pChar = rEncodedUrl.GetBuffer();
654     while( *pChar )
655     {
656         switch( eState )
657         {
658 
659 // --- first character ---
660 
661             case xlUrlInit:
662             {
663                 switch( *pChar )
664                 {
665                     case EXC_URLSTART_ENCODED:
666                         eState = xlUrlPath;
667                     break;
668                     case EXC_URLSTART_SELF:
669                     case EXC_URLSTART_SELFENCODED:
670                         rbSameWb = true;
671                         eState = xlUrlSheetName;
672                     break;
673                     case '[':
674                         bEncoded = false;
675                         eState = xlUrlFileName;
676                     break;
677                     default:
678                         bEncoded = false;
679                         lclAppendUrlChar( rUrl, *pChar );
680                         eState = xlUrlPath;
681                 }
682             }
683             break;
684 
685 // --- URL path ---
686 
687             case xlUrlPath:
688             {
689                 switch( *pChar )
690                 {
691                     case EXC_URL_DOSDRIVE:
692                     {
693                         if( *(pChar + 1) )
694                         {
695                             ++pChar;
696                             if( *pChar == '@' )
697                                 rUrl.AppendAscii( "\\\\" );
698                             else
699                             {
700                                 lclAppendUrlChar( rUrl, *pChar );
701                                 rUrl.AppendAscii( ":\\" );
702                             }
703                         }
704                         else
705                             rUrl.AppendAscii( "<NULL-DRIVE!>" );
706                     }
707                     break;
708                     case EXC_URL_DRIVEROOT:
709                         if( cCurrDrive )
710                         {
711                             lclAppendUrlChar( rUrl, cCurrDrive );
712                             rUrl.Append( ':' );
713                         }
714                         // run through
715                     case EXC_URL_SUBDIR:
716                         if( bEncoded )
717                             rUrl.Append( '\\' );
718                         else    // control character in raw name -> DDE link
719                         {
720                             rUrl.Append( EXC_DDE_DELIM );
721                             eState = xlUrlRaw;
722                         }
723                     break;
724                     case EXC_URL_PARENTDIR:
725                         rUrl.AppendAscii( "..\\" );
726                     break;
727                     case EXC_URL_RAW:
728                     {
729                         if( *(pChar + 1) )
730                         {
731                             xub_StrLen nLen = *++pChar;
732                             for( xub_StrLen nChar = 0; (nChar < nLen) && *(pChar + 1); ++nChar )
733                                 lclAppendUrlChar( rUrl, *++pChar );
734 //                            rUrl.Append( ':' );
735                         }
736                     }
737                     break;
738                     case '[':
739                         eState = xlUrlFileName;
740                     break;
741                     default:
742                         lclAppendUrlChar( rUrl, *pChar );
743                 }
744             }
745             break;
746 
747 // --- file name ---
748 
749             case xlUrlFileName:
750             {
751                 switch( *pChar )
752                 {
753                     case ']':   eState = xlUrlSheetName;    break;
754                     default:    lclAppendUrlChar( rUrl, *pChar );
755                 }
756             }
757             break;
758 
759 // --- sheet name ---
760 
761             case xlUrlSheetName:
762                 rTabName.Append( *pChar );
763             break;
764 
765 // --- raw read mode ---
766 
767             case xlUrlRaw:
768                 lclAppendUrlChar( rUrl, *pChar );
769             break;
770         }
771 
772         ++pChar;
773     }
774 }
775 
DecodeUrl(String & rUrl,bool & rbSameWb,const XclImpRoot & rRoot,const String & rEncodedUrl)776 void XclImpUrlHelper::DecodeUrl(
777         String& rUrl, bool& rbSameWb, const XclImpRoot& rRoot, const String& rEncodedUrl )
778 {
779     String aTabName;
780     DecodeUrl( rUrl, aTabName, rbSameWb, rRoot, rEncodedUrl );
781     DBG_ASSERT( !aTabName.Len(), "XclImpUrlHelper::DecodeUrl - sheet name ignored" );
782 }
783 
DecodeLink(String & rApplic,String & rTopic,const String rEncUrl)784 bool XclImpUrlHelper::DecodeLink( String& rApplic, String& rTopic, const String rEncUrl )
785 {
786     xub_StrLen nPos = rEncUrl.Search( EXC_DDE_DELIM );
787     if( (nPos != STRING_NOTFOUND) && (0 < nPos) && (nPos + 1 < rEncUrl.Len()) )
788     {
789         rApplic = rEncUrl.Copy( 0, nPos );
790         rTopic = rEncUrl.Copy( nPos + 1 );
791         return true;
792     }
793     return false;
794 }
795 
796 // Cached Values ==============================================================
797 
XclImpCachedValue(XclImpStream & rStrm)798 XclImpCachedValue::XclImpCachedValue( XclImpStream& rStrm ) :
799     mfValue( 0.0 ),
800     mnBoolErr( 0 )
801 {
802     rStrm >> mnType;
803     switch( mnType )
804     {
805         case EXC_CACHEDVAL_EMPTY:
806             rStrm.Ignore( 8 );
807         break;
808         case EXC_CACHEDVAL_DOUBLE:
809             rStrm >> mfValue;
810         break;
811         case EXC_CACHEDVAL_STRING:
812             mxStr.reset( new String( rStrm.ReadUniString() ) );
813         break;
814         case EXC_CACHEDVAL_BOOL:
815         case EXC_CACHEDVAL_ERROR:
816         {
817             double fVal;
818             rStrm >> mnBoolErr;
819             rStrm.Ignore( 7 );
820 
821             const ScTokenArray* pScTokArr = rStrm.GetRoot().GetOldFmlaConverter().GetBoolErr(
822                 XclTools::ErrorToEnum( fVal, mnType == EXC_CACHEDVAL_ERROR, mnBoolErr ) );
823             if( pScTokArr )
824                 mxTokArr.reset( pScTokArr->Clone() );
825         }
826         break;
827         default:
828             DBG_ERRORFILE( "XclImpCachedValue::XclImpCachedValue - unknown data type" );
829     }
830 }
831 
~XclImpCachedValue()832 XclImpCachedValue::~XclImpCachedValue()
833 {
834 }
835 
GetScError() const836 sal_uInt16 XclImpCachedValue::GetScError() const
837 {
838     return (mnType == EXC_CACHEDVAL_ERROR) ? XclTools::GetScErrorCode( mnBoolErr ) : 0;
839 }
840 
841 // Matrix Cached Values ==============================================================
842 
XclImpCachedMatrix(XclImpStream & rStrm)843 XclImpCachedMatrix::XclImpCachedMatrix( XclImpStream& rStrm ) :
844     mnScCols( 0 ),
845     mnScRows( 0 )
846 {
847     mnScCols = rStrm.ReaduInt8();
848     mnScRows = rStrm.ReaduInt16();
849 
850     if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
851     {
852         // in BIFF2-BIFF7: 256 columns represented by 0 columns
853         if( mnScCols == 0 )
854             mnScCols = 256;
855     }
856     else
857     {
858         // in BIFF8: columns and rows decreaed by 1
859         ++mnScCols;
860         ++mnScRows;
861     }
862 
863     for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
864         for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
865             maValueList.Append( new XclImpCachedValue( rStrm ) );
866 }
867 
~XclImpCachedMatrix()868 XclImpCachedMatrix::~XclImpCachedMatrix()
869 {
870 }
871 
CreateScMatrix() const872 ScMatrixRef XclImpCachedMatrix::CreateScMatrix() const
873 {
874     ScMatrixRef xScMatrix;
875     DBG_ASSERT( mnScCols * mnScRows == maValueList.Count(), "XclImpCachedMatrix::CreateScMatrix - element count mismatch" );
876     if( mnScCols && mnScRows && static_cast< sal_uLong >( mnScCols * mnScRows ) <= maValueList.Count() )
877     {
878         xScMatrix = new ScMatrix( mnScCols, mnScRows );
879         const XclImpCachedValue* pValue = maValueList.First();
880         for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
881         {
882             for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
883             {
884                 switch( pValue->GetType() )
885                 {
886                     case EXC_CACHEDVAL_EMPTY:
887                         // Excel shows 0.0 here, not an empty cell
888                         xScMatrix->PutEmpty( nScCol, nScRow );
889                     break;
890                     case EXC_CACHEDVAL_DOUBLE:
891                         xScMatrix->PutDouble( pValue->GetValue(), nScCol, nScRow );
892                     break;
893                     case EXC_CACHEDVAL_STRING:
894                         xScMatrix->PutString( pValue->GetString(), nScCol, nScRow );
895                     break;
896                     case EXC_CACHEDVAL_BOOL:
897                         xScMatrix->PutBoolean( pValue->GetBool(), nScCol, nScRow );
898                     break;
899                     case EXC_CACHEDVAL_ERROR:
900                         xScMatrix->PutError( pValue->GetScError(), nScCol, nScRow );
901                     break;
902                     default:
903                         DBG_ERRORFILE( "XclImpCachedMatrix::CreateScMatrix - unknown value type" );
904                         xScMatrix->PutEmpty( nScCol, nScRow );
905                 }
906                 pValue = maValueList.Next();
907             }
908         }
909     }
910     return xScMatrix;
911 }
912 
913 // ============================================================================
914 
915