merge the formfield patch from ooo-build
[ooovba.git] / sc / source / filter / excel / xicontent.cxx
bloba38bbe645dc4e0da09f5cbf1c1c45ec9d87d8d7a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xicontent.cxx,v $
10 * $Revision: 1.31.88.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 #include "xicontent.hxx"
34 #include <sfx2/objsh.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <tools/urlobj.hxx>
37 #include <svx/editeng.hxx>
38 #include <svx/editobj.hxx>
39 #include <svx/linkmgr.hxx>
40 #include <svtools/itemset.hxx>
41 #include "scitems.hxx"
42 #include <svx/eeitem.hxx>
43 #include <svtools/intitem.hxx>
44 #include <svtools/stritem.hxx>
45 #include <svx/flditem.hxx>
46 #include <svx/fhgtitem.hxx>
47 #include <svx/wghtitem.hxx>
48 #include <svx/udlnitem.hxx>
49 #include <svx/postitem.hxx>
50 #include <svx/colritem.hxx>
51 #include <svx/crsditem.hxx>
52 #include "document.hxx"
53 #include "editutil.hxx"
54 #include "cell.hxx"
55 #include "validat.hxx"
56 #include "patattr.hxx"
57 #include "docpool.hxx"
58 #include "rangenam.hxx"
59 #include "arealink.hxx"
60 #include "stlsheet.hxx"
61 #include "scextopt.hxx"
62 #include "xlformula.hxx"
63 #include "xltracer.hxx"
64 #include "xistream.hxx"
65 #include "xihelper.hxx"
66 #include "xistyle.hxx"
67 #include "xiescher.hxx"
68 #include "xiname.hxx"
70 #include "excform.hxx"
71 #include "tabprotection.hxx"
73 #include <memory>
75 using ::com::sun::star::uno::Sequence;
76 using ::std::auto_ptr;
78 // Shared string table ========================================================
80 XclImpSst::XclImpSst( const XclImpRoot& rRoot ) :
81 XclImpRoot( rRoot )
85 void XclImpSst::ReadSst( XclImpStream& rStrm )
87 sal_uInt32 nStrCount;
88 rStrm.Ignore( 4 );
89 rStrm >> nStrCount;
90 maStrings.clear();
91 maStrings.reserve( static_cast< size_t >( nStrCount ) );
92 while( (nStrCount > 0) && rStrm.IsValid() )
94 XclImpString aString;
95 aString.Read( rStrm );
96 maStrings.push_back( aString );
97 --nStrCount;
101 const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
103 return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
106 ScBaseCell* XclImpSst::CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex ) const
108 ScBaseCell* pCell = 0;
109 if( const XclImpString* pString = GetString( nSstIndex ) )
110 pCell = XclImpStringHelper::CreateCell( *this, *pString, nXFIndex );
111 return pCell;
114 // Hyperlinks =================================================================
116 namespace {
118 /** Reads character array and stores it into rString.
119 @param nChars Number of following characters (not byte count!).
120 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
121 void lclAppendString32( String& rString, XclImpStream& rStrm, sal_uInt32 nChars, bool b16Bit )
123 sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
124 rString.Append( rStrm.ReadRawUniString( nReadChars, b16Bit ) );
125 // ignore remaining chars
126 sal_Size nIgnore = nChars - nReadChars;
127 if( b16Bit )
128 nIgnore *= 2;
129 rStrm.Ignore( nIgnore );
132 /** Reads 32-bit string length and the character array and stores it into rString.
133 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
134 void lclAppendString32( String& rString, XclImpStream& rStrm, bool b16Bit )
136 lclAppendString32( rString, rStrm, rStrm.ReaduInt32(), b16Bit );
139 /** Reads 32-bit string length and ignores following character array.
140 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
141 void lclIgnoreString32( XclImpStream& rStrm, bool b16Bit )
143 sal_uInt32 nChars;
144 rStrm >> nChars;
145 if( b16Bit )
146 nChars *= 2;
147 rStrm.Ignore( nChars );
150 /** Converts a path to an absolute path.
151 @param rPath The source path. The resulting path is returned here.
152 @param nLevel Number of parent directories to add in front of the path. */
153 void lclGetAbsPath( String& rPath, sal_uInt16 nLevel, SfxObjectShell* pDocShell )
155 String aTmpStr;
156 while( nLevel )
158 aTmpStr.AppendAscii( "../" );
159 --nLevel;
161 aTmpStr += rPath;
163 if( pDocShell )
165 bool bWasAbs = false;
166 rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr, bWasAbs ).GetMainURL( INetURLObject::NO_DECODE );
167 // full path as stored in SvxURLField must be encoded
169 else
170 rPath = aTmpStr;
173 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
174 void lclInsertUrl( const XclImpRoot& rRoot, const String& rUrl, SCCOL nScCol, SCROW nScRow, SCTAB nScTab )
176 ScDocument& rDoc = rRoot.GetDoc();
177 ScAddress aScPos( nScCol, nScRow, nScTab );
178 CellType eCellType = rDoc.GetCellType( aScPos );
179 switch( eCellType )
181 // #i54261# hyperlinks in string cells
182 case CELLTYPE_STRING:
183 case CELLTYPE_EDIT:
185 String aDisplText;
186 rDoc.GetString( nScCol, nScRow, nScTab, aDisplText );
187 if( !aDisplText.Len() )
188 aDisplText = rUrl;
190 ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
191 SvxURLField aUrlField( rUrl, aDisplText, SVXURLFORMAT_APPDEFAULT );
193 const ScEditCell* pEditCell = (eCellType == CELLTYPE_EDIT) ? static_cast< const ScEditCell* >( rDoc.GetCell( aScPos ) ) : 0;
194 const EditTextObject* pEditObj = pEditCell ? pEditCell->GetData() : 0;
195 if( pEditObj )
197 rEE.SetText( *pEditObj );
198 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0, 0, 0xFFFF, 0 ) );
200 else
202 rEE.SetText( EMPTY_STRING );
203 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection() );
204 if( const ScPatternAttr* pPattern = rDoc.GetPattern( aScPos.Col(), aScPos.Row(), nScTab ) )
206 SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
207 pPattern->FillEditItemSet( &aItemSet );
208 rEE.QuickSetAttribs( aItemSet, ESelection( 0, 0, 0xFFFF, 0 ) );
211 ::std::auto_ptr< EditTextObject > xTextObj( rEE.CreateTextObject() );
213 ScEditCell* pCell = new ScEditCell( xTextObj.get(), &rDoc, rEE.GetEditTextObjectPool() );
214 rDoc.PutCell( aScPos, pCell );
216 break;
218 // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
219 #if 0
220 case CELLTYPE_VALUE:
222 // #i31050# replace number with HYPERLINK function
223 ScTokenArray aTokenArray;
224 aTokenArray.AddOpCode( ocHyperLink );
225 aTokenArray.AddOpCode( ocOpen );
226 aTokenArray.AddString( rUrl );
227 aTokenArray.AddOpCode( ocSep );
228 aTokenArray.AddDouble( rDoc.GetValue( aScPos ) );
229 aTokenArray.AddOpCode( ocClose );
230 rDoc.PutCell( aScPos, new ScFormulaCell( &rDoc, aScPos, &aTokenArray ) );
232 break;
233 #endif
235 default:;
239 } // namespace
241 // ----------------------------------------------------------------------------
243 void XclImpHyperlink::ReadHlink( XclImpStream& rStrm )
245 XclRange aXclRange( ScAddress::UNINITIALIZED );
246 rStrm >> aXclRange;
247 // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
248 aXclRange.maFirst.mnCol &= 0xFF;
249 aXclRange.maLast.mnCol &= 0xFF;
250 String aString = ReadEmbeddedData( rStrm );
251 if ( aString.Len() > 0 )
252 rStrm.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange, aString );
255 String XclImpHyperlink::ReadEmbeddedData( XclImpStream& rStrm )
257 const XclImpRoot& rRoot = rStrm.GetRoot();
258 SfxObjectShell* pDocShell = rRoot.GetDocShell();
260 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
262 sal_uInt32 nFlags;
263 XclGuid aGuid;
264 rStrm >> aGuid;
265 rStrm.Ignore( 4 );
266 rStrm >> nFlags;
268 DBG_ASSERT( aGuid == XclTools::maGuidStdLink, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
270 sal_uInt16 nLevel = 0; // counter for level to climb down in path
271 ::std::auto_ptr< String > xLongName; // link / file name
272 ::std::auto_ptr< String > xShortName; // 8.3-representation of file name
273 ::std::auto_ptr< String > xTextMark; // text mark
275 // description (ignore)
276 if( ::get_flag( nFlags, EXC_HLINK_DESCR ) )
277 lclIgnoreString32( rStrm, true );
278 // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
279 if( ::get_flag( nFlags, EXC_HLINK_FRAME ) )
280 lclIgnoreString32( rStrm, true );
282 // URL fields are zero-terminated - do not let the stream replace them
283 // in the lclAppendString32() with the '?' character.
284 rStrm.SetNulSubstChar( '\0' );
286 // UNC path
287 if( ::get_flag( nFlags, EXC_HLINK_UNC ) )
289 xLongName.reset( new String );
290 lclAppendString32( *xLongName, rStrm, true );
291 lclGetAbsPath( *xLongName, 0, pDocShell );
293 // file link or URL
294 else if( ::get_flag( nFlags, EXC_HLINK_BODY ) )
296 rStrm >> aGuid;
298 if( aGuid == XclTools::maGuidFileMoniker )
300 rStrm >> nLevel;
301 xShortName.reset( new String );
302 lclAppendString32( *xShortName, rStrm, false );
303 rStrm.Ignore( 24 );
305 sal_uInt32 nStrLen;
306 rStrm >> nStrLen;
307 if( nStrLen )
309 rStrm >> nStrLen;
310 nStrLen /= 2; // it's byte count here...
311 rStrm.Ignore( 2 );
312 xLongName.reset( new String );
313 lclAppendString32( *xLongName, rStrm, nStrLen, true );
314 lclGetAbsPath( *xLongName, nLevel, pDocShell );
316 else
317 lclGetAbsPath( *xShortName, nLevel, pDocShell );
319 else if( aGuid == XclTools::maGuidUrlMoniker )
321 sal_uInt32 nStrLen;
322 rStrm >> nStrLen;
323 nStrLen /= 2; // it's byte count here...
324 xLongName.reset( new String );
325 lclAppendString32( *xLongName, rStrm, nStrLen, true );
326 if( !::get_flag( nFlags, EXC_HLINK_ABS ) )
327 lclGetAbsPath( *xLongName, 0, pDocShell );
329 else
331 DBG_ERRORFILE( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
335 // text mark
336 if( ::get_flag( nFlags, EXC_HLINK_MARK ) )
338 xTextMark.reset( new String );
339 lclAppendString32( *xTextMark, rStrm, true );
342 rStrm.SetNulSubstChar(); // back to default
344 DBG_ASSERT( rStrm.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
346 if( !xLongName.get() && xShortName.get() )
347 xLongName = xShortName;
348 else if( !xLongName.get() && xTextMark.get() )
349 xLongName.reset( new String );
351 if( xLongName.get() )
353 if( xTextMark.get() )
355 if( xLongName->Len() == 0 )
356 xTextMark->SearchAndReplaceAll( '!', '.' );
357 xLongName->Append( '#' );
358 xLongName->Append( *xTextMark );
360 return *xLongName;
362 return String::EmptyString();
365 void XclImpHyperlink::ConvertToValidTabName(String& rUrl)
367 xub_StrLen n = rUrl.Len();
368 if (n < 4)
369 // Needs at least 4 characters.
370 return;
372 sal_Unicode c = rUrl.GetChar(0);
373 if (c != sal_Unicode('#'))
374 // the 1st character must be '#'.
375 return;
377 String aNewUrl(sal_Unicode('#')), aTabName;
379 bool bInQuote = false;
380 bool bQuoteTabName = false;
381 for (xub_StrLen i = 1; i < n; ++i)
383 c = rUrl.GetChar(i);
384 if (c == sal_Unicode('\''))
386 if (bInQuote && i+1 < n && rUrl.GetChar(i+1) == sal_Unicode('\''))
388 // Two consecutive single quotes ('') signify a single literal
389 // quite. When this occurs, the whole table name needs to be
390 // quoted.
391 bQuoteTabName = true;
392 aTabName.Append(c);
393 aTabName.Append(c);
394 ++i;
395 continue;
398 bInQuote = !bInQuote;
399 if (!bInQuote && aTabName.Len() > 0)
401 if (bQuoteTabName)
402 aNewUrl.Append(sal_Unicode('\''));
403 aNewUrl.Append(aTabName);
404 if (bQuoteTabName)
405 aNewUrl.Append(sal_Unicode('\''));
408 else if (bInQuote)
409 aTabName.Append(c);
410 else
411 aNewUrl.Append(c);
414 if (bInQuote)
415 // It should be outside the quotes!
416 return;
418 // All is good. Pass the new URL.
419 rUrl = aNewUrl;
422 void XclImpHyperlink::InsertUrl( const XclImpRoot& rRoot, const XclRange& rXclRange, const String& rUrl )
424 String aUrl(rUrl);
425 ConvertToValidTabName(aUrl);
427 SCTAB nScTab = rRoot.GetCurrScTab();
428 ScRange aScRange( ScAddress::UNINITIALIZED );
429 if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
431 SCCOL nScCol1, nScCol2;
432 SCROW nScRow1, nScRow2;
433 aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
434 for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
435 for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
436 lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
440 // Label ranges ===============================================================
442 void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
444 const XclImpRoot& rRoot = rStrm.GetRoot();
445 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
447 ScDocument& rDoc = rRoot.GetDoc();
448 SCTAB nScTab = rRoot.GetCurrScTab();
449 XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
450 ScRangePairListRef xLabelRangesRef;
451 const ScRange* pScRange = 0;
453 XclRangeList aRowXclRanges, aColXclRanges;
454 rStrm >> aRowXclRanges >> aColXclRanges;
456 // row label ranges
457 ScRangeList aRowScRanges;
458 rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
459 xLabelRangesRef = rDoc.GetRowNameRangesRef();
460 for( pScRange = aRowScRanges.First(); pScRange; pScRange = aRowScRanges.Next() )
462 ScRange aDataRange( *pScRange );
463 if( aDataRange.aEnd.Col() < MAXCOL )
465 aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
466 aDataRange.aEnd.SetCol( MAXCOL );
468 else if( aDataRange.aStart.Col() > 0 )
470 aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
471 aDataRange.aStart.SetCol( 0 );
473 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
476 // column label ranges
477 ScRangeList aColScRanges;
478 rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
479 xLabelRangesRef = rDoc.GetColNameRangesRef();
480 for( pScRange = aColScRanges.First(); pScRange; pScRange = aColScRanges.Next() )
482 ScRange aDataRange( *pScRange );
483 if( aDataRange.aEnd.Row() < MAXROW )
485 aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
486 aDataRange.aEnd.SetRow( MAXROW );
488 else if( aDataRange.aStart.Row() > 0 )
490 aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
491 aDataRange.aStart.SetRow( 0 );
493 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
497 // Conditional formatting =====================================================
499 XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
500 XclImpRoot( rRoot ),
501 mnFormatIndex( nFormatIndex ),
502 mnCondCount( 0 ),
503 mnCondIndex( 0 )
507 XclImpCondFormat::~XclImpCondFormat()
511 void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
513 DBG_ASSERT( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
514 XclRangeList aXclRanges;
515 rStrm >> mnCondCount;
516 rStrm.Ignore( 10 );
517 rStrm >> aXclRanges;
518 GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
521 void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
523 if( mnCondIndex >= mnCondCount )
525 DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
526 return;
529 // entire conditional format outside of valid range?
530 if( !maRanges.Count() )
531 return;
533 sal_uInt8 nType, nOperator;
534 sal_uInt16 nFmlaSize1, nFmlaSize2;
535 sal_uInt32 nFlags;
537 rStrm >> nType >> nOperator >> nFmlaSize1 >> nFmlaSize2 >> nFlags;
538 rStrm.Ignore( 2 );
540 // *** mode and comparison operator ***
542 ScConditionMode eMode = SC_COND_NONE;
543 switch( nType )
545 case EXC_CF_TYPE_CELL:
547 switch( nOperator )
549 case EXC_CF_CMP_BETWEEN: eMode = SC_COND_BETWEEN; break;
550 case EXC_CF_CMP_NOT_BETWEEN: eMode = SC_COND_NOTBETWEEN; break;
551 case EXC_CF_CMP_EQUAL: eMode = SC_COND_EQUAL; break;
552 case EXC_CF_CMP_NOT_EQUAL: eMode = SC_COND_NOTEQUAL; break;
553 case EXC_CF_CMP_GREATER: eMode = SC_COND_GREATER; break;
554 case EXC_CF_CMP_LESS: eMode = SC_COND_LESS; break;
555 case EXC_CF_CMP_GREATER_EQUAL: eMode = SC_COND_EQGREATER; break;
556 case EXC_CF_CMP_LESS_EQUAL: eMode = SC_COND_EQLESS; break;
557 default:
558 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator );
561 break;
563 case EXC_CF_TYPE_FMLA:
564 eMode = SC_COND_DIRECT;
565 break;
567 default:
568 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType );
569 return;
572 // *** create style sheet ***
574 String aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
575 SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
577 const XclImpPalette& rPalette = GetPalette();
579 // *** font block ***
581 if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
583 XclImpFont aFont( GetRoot() );
584 aFont.ReadCFFontBlock( rStrm );
585 aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
588 // *** border block ***
590 if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
592 sal_uInt16 nLineStyle;
593 sal_uInt32 nLineColor;
594 rStrm >> nLineStyle >> nLineColor;
595 rStrm.Ignore( 2 );
597 XclImpCellBorder aBorder;
598 aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
599 aBorder.FillToItemSet( rStyleItemSet, rPalette );
602 // *** pattern block ***
604 if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
606 sal_uInt16 nPattern, nColor;
607 rStrm >> nPattern >> nColor;
609 XclImpCellArea aArea;
610 aArea.FillFromCF8( nPattern, nColor, nFlags );
611 aArea.FillToItemSet( rStyleItemSet, rPalette );
614 // *** formulas ***
616 const ScAddress& rPos = maRanges.GetObject( 0 )->aStart; // assured above that maRanges is not empty
617 ExcelToSc& rFmlaConv = GetOldFmlaConverter();
619 ExcelConverterBase::ConvertParam aParam;
620 aParam.mbAllowArrays = false;
622 ::std::auto_ptr< ScTokenArray > xTokArr1;
623 if( nFmlaSize1 > 0 )
625 const ScTokenArray* pTokArr = 0;
626 rFmlaConv.Reset( rPos );
627 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, aParam, FT_RangeName );
628 // formula converter owns pTokArr -> create a copy of the token array
629 if( pTokArr )
630 xTokArr1.reset( pTokArr->Clone() );
633 ::std::auto_ptr< ScTokenArray > pTokArr2;
634 if( nFmlaSize2 > 0 )
636 const ScTokenArray* pTokArr = 0;
637 rFmlaConv.Reset( rPos );
638 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, aParam, FT_RangeName );
639 // formula converter owns pTokArr -> create a copy of the token array
640 if( pTokArr )
641 pTokArr2.reset( pTokArr->Clone() );
644 // *** create the Calc conditional formatting ***
646 if( !mxScCondFmt.get() )
648 ULONG nKey = 0;
649 mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
652 ScCondFormatEntry aEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
653 mxScCondFmt->AddEntry( aEntry );
654 ++mnCondIndex;
657 void XclImpCondFormat::Apply()
659 if( mxScCondFmt.get() )
661 ScDocument& rDoc = GetDoc();
663 ULONG nKey = rDoc.AddCondFormat( *mxScCondFmt );
664 ScPatternAttr aPattern( rDoc.GetPool() );
665 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL, nKey ) );
667 // maRanges contains only valid cell ranges
668 for( const ScRange* pScRange = maRanges.First(); pScRange; pScRange = maRanges.Next() )
670 rDoc.ApplyPatternAreaTab(
671 pScRange->aStart.Col(), pScRange->aStart.Row(),
672 pScRange->aEnd.Col(), pScRange->aEnd.Row(),
673 pScRange->aStart.Tab(), aPattern );
678 // ----------------------------------------------------------------------------
680 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
681 XclImpRoot( rRoot )
685 void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
687 XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.Count() );
688 pFmt->ReadCondfmt( rStrm );
689 maCondFmtList.Append( pFmt );
692 void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
694 DBG_ASSERT( !maCondFmtList.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
695 if( !maCondFmtList.Empty() )
696 maCondFmtList.GetObject( maCondFmtList.Count() - 1 )->ReadCF( rStrm );
699 void XclImpCondFormatManager::Apply()
701 for( XclImpCondFormat* pFmt = maCondFmtList.First(); pFmt; pFmt = maCondFmtList.Next() )
702 pFmt->Apply();
703 maCondFmtList.Clear();
706 // Data Validation ============================================================
708 void XclImpValidation::ReadDval( XclImpStream& rStrm )
710 const XclImpRoot& rRoot = rStrm.GetRoot();
711 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
713 sal_uInt32 nObjId;
714 rStrm.Ignore( 10 );
715 rStrm >> nObjId;
716 if( nObjId != EXC_DVAL_NOOBJ )
718 DBG_ASSERT( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
719 rRoot.GetObjectManager().SetSkipObj( rRoot.GetCurrScTab(), static_cast< sal_uInt16 >( nObjId ) );
723 void XclImpValidation::ReadDV( XclImpStream& rStrm )
725 const XclImpRoot& rRoot = rStrm.GetRoot();
726 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
728 ScDocument& rDoc = rRoot.GetDoc();
729 SCTAB nScTab = rRoot.GetCurrScTab();
730 ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
732 // flags
733 sal_uInt32 nFlags;
734 rStrm >> nFlags;
736 // message strings
737 /* Empty strings are single NUL characters in Excel (string length is 1).
738 -> Do not let the stream replace them with '?' characters. */
739 rStrm.SetNulSubstChar( '\0' );
740 String aPromptTitle( rStrm.ReadUniString() );
741 String aErrorTitle( rStrm.ReadUniString() );
742 String aPromptMessage( rStrm.ReadUniString() );
743 String aErrorMessage( rStrm.ReadUniString() );
744 rStrm.SetNulSubstChar(); // back to default
746 ExcelConverterBase::ConvertParam aParam;
747 aParam.mbAllowArrays = false;
749 // formula(s)
750 if( rStrm.GetRecLeft() > 8 )
752 sal_uInt16 nLen;
754 // first formula
755 // string list is single tStr token with NUL separators -> replace them with LF
756 rStrm.SetNulSubstChar( '\n' );
757 ::std::auto_ptr< ScTokenArray > xTokArr1;
758 rStrm >> nLen;
759 rStrm.Ignore( 2 );
760 if( nLen > 0 )
762 const ScTokenArray* pTokArr = 0;
763 rFmlaConv.Reset();
764 rFmlaConv.Convert( pTokArr, rStrm, nLen, aParam, FT_RangeName );
765 // formula converter owns pTokArr -> create a copy of the token array
766 if( pTokArr )
767 xTokArr1.reset( pTokArr->Clone() );
769 rStrm.SetNulSubstChar(); // back to default
771 // second formula
772 ::std::auto_ptr< ScTokenArray > xTokArr2;
773 rStrm >> nLen;
774 rStrm.Ignore( 2 );
775 if( nLen > 0 )
777 const ScTokenArray* pTokArr = 0;
778 rFmlaConv.Reset();
779 rFmlaConv.Convert( pTokArr, rStrm, nLen, aParam, FT_RangeName );
780 // formula converter owns pTokArr -> create a copy of the token array
781 if( pTokArr )
782 xTokArr2.reset( pTokArr->Clone() );
785 // read all cell ranges
786 XclRangeList aXclRanges;
787 rStrm >> aXclRanges;
789 // convert to Calc range list
790 ScRangeList aScRanges;
791 rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
793 // only continue if there are valid ranges
794 if( aScRanges.Count() )
796 bool bIsValid = true; // valid settings in flags field
798 ScValidationMode eValMode = SC_VALID_ANY;
799 switch( nFlags & EXC_DV_MODE_MASK )
801 case EXC_DV_MODE_ANY: eValMode = SC_VALID_ANY; break;
802 case EXC_DV_MODE_WHOLE: eValMode = SC_VALID_WHOLE; break;
803 case EXC_DV_MODE_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
804 case EXC_DV_MODE_LIST: eValMode = SC_VALID_LIST; break;
805 case EXC_DV_MODE_DATE: eValMode = SC_VALID_DATE; break;
806 case EXC_DV_MODE_TIME: eValMode = SC_VALID_TIME; break;
807 case EXC_DV_MODE_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
808 case EXC_DV_MODE_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
809 default: bIsValid = false;
811 rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
813 ScConditionMode eCondMode = SC_COND_BETWEEN;
814 switch( nFlags & EXC_DV_COND_MASK )
816 case EXC_DV_COND_BETWEEN: eCondMode = SC_COND_BETWEEN; break;
817 case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
818 case EXC_DV_COND_EQUAL: eCondMode = SC_COND_EQUAL; break;
819 case EXC_DV_COND_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break;
820 case EXC_DV_COND_GREATER: eCondMode = SC_COND_GREATER; break;
821 case EXC_DV_COND_LESS: eCondMode = SC_COND_LESS; break;
822 case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER; break;
823 case EXC_DV_COND_EQLESS: eCondMode = SC_COND_EQLESS; break;
824 default: bIsValid = false;
827 if( bIsValid )
829 // first range for base address for relative references
830 const ScRange& rScRange = *aScRanges.GetObject( 0 ); // aScRanges is not empty
832 // process string list of a list validity (convert to list of string tokens)
833 if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
834 XclTokenArrayHelper::ConvertStringToList( *xTokArr1, '\n', true );
836 ScValidationData aValidData( eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart );
838 aValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
839 aValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, ValidListType::INVISIBLE, ValidListType::UNSORTED ) );
841 // *** prompt box ***
842 if( aPromptTitle.Len() || aPromptMessage.Len() )
844 // set any text stored in the record
845 aValidData.SetInput( aPromptTitle, aPromptMessage );
846 if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
847 aValidData.ResetInput();
850 // *** error box ***
851 ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
852 switch( nFlags & EXC_DV_ERROR_MASK )
854 case EXC_DV_ERROR_WARNING: eErrStyle = SC_VALERR_WARNING; break;
855 case EXC_DV_ERROR_INFO: eErrStyle = SC_VALERR_INFO; break;
857 // set texts and error style
858 aValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
859 if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
860 aValidData.ResetError();
862 // set the handle ID
863 ULONG nHandle = rDoc.AddValidationEntry( aValidData );
864 ScPatternAttr aPattern( rDoc.GetPool() );
865 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
867 // apply all ranges
868 for( const ScRange* pScRange = aScRanges.First(); pScRange; pScRange = aScRanges.Next() )
869 rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
870 pScRange->aEnd.Col(), pScRange->aEnd.Row(), nScTab, aPattern );
876 // Web queries ================================================================
878 XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
879 maDestRange( rDestRange ),
880 meMode( xlWQUnknown ),
881 mnRefresh( 0 )
885 void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
887 sal_uInt16 nFlags = rStrm.ReaduInt16();
888 sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
889 if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
891 if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
893 meMode = xlWQAllTables;
894 maTables = ScfTools::GetHTMLTablesName();
896 else
898 meMode = xlWQDocument;
899 maTables = ScfTools::GetHTMLDocName();
904 void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
906 maURL = rStrm.ReadUniString();
909 void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
911 sal_uInt16 nFlags;
912 rStrm.Ignore( 10 );
913 rStrm >> nFlags;
914 rStrm.Ignore( 10 );
915 rStrm >> mnRefresh;
917 if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
918 meMode = xlWQSpecTables;
921 void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
923 if( meMode == xlWQSpecTables )
925 rStrm.Ignore( 4 );
926 String aTables( rStrm.ReadUniString() );
928 const sal_Unicode cSep = ';';
929 aTables.SearchAndReplaceAll( ',', cSep );
930 String aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
931 xub_StrLen nTokenCnt = aTables.GetQuotedTokenCount( aQuotedPairs, cSep );
932 maTables.Erase();
933 xub_StrLen nStringIx = 0;
934 for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
936 String aToken( aTables.GetQuotedToken( 0, aQuotedPairs, cSep, nStringIx ) );
937 sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.ToInt32() : 0;
938 if( nTabNum > 0 )
939 ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
940 else
942 ScGlobal::EraseQuotes( aToken, '"', false );
943 if( aToken.Len() )
944 ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
950 void XclImpWebQuery::Apply( ScDocument& rDoc, const String& rFilterName )
952 if( maURL.Len() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
954 ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
955 maURL, rFilterName, EMPTY_STRING, maTables, maDestRange, mnRefresh * 60UL );
956 rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
957 maURL, &rFilterName, &maTables );
961 // ----------------------------------------------------------------------------
963 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
964 XclImpRoot( rRoot )
968 void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
970 if( GetBiff() == EXC_BIFF8 )
972 rStrm.Ignore( 10 );
973 String aXclName( rStrm.ReadUniString() );
975 // #i64794# Excel replaces spaces with underscores
976 aXclName.SearchAndReplaceAll( ' ', '_' );
978 // #101529# find the defined name used in Calc
979 if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
981 if( const ScRangeData* pRangeData = pName->GetScRangeData() )
983 ScRange aRange;
984 if( pRangeData->IsReference( aRange ) )
985 maWQList.Append( new XclImpWebQuery( aRange ) );
989 else
991 DBG_ERROR_BIFF();
995 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
997 if( XclImpWebQuery* pQuery = maWQList.Last() )
998 pQuery->ReadParamqry( rStrm );
1001 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
1003 if( XclImpWebQuery* pQuery = maWQList.Last() )
1004 pQuery->ReadWqstring( rStrm );
1007 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
1009 if( XclImpWebQuery* pQuery = maWQList.Last() )
1010 pQuery->ReadWqsettings( rStrm );
1013 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
1015 if( XclImpWebQuery* pQuery = maWQList.Last() )
1016 pQuery->ReadWqtables( rStrm );
1019 void XclImpWebQueryBuffer::Apply()
1021 ScDocument& rDoc = GetDoc();
1022 String aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER ) );
1023 for( XclImpWebQuery* pQuery = maWQList.First(); pQuery; pQuery = maWQList.Next() )
1024 pQuery->Apply( rDoc, aFilterName );
1027 // Decryption =================================================================
1029 namespace {
1031 XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
1033 XclImpDecrypterRef xDecr;
1034 DBG_ASSERT( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1035 if( rStrm.GetRecLeft() == 4 )
1037 sal_uInt16 nKey, nHash;
1038 rStrm >> nKey >> nHash;
1039 xDecr.reset( new XclImpBiff5Decrypter( nKey, nHash ) );
1041 return xDecr;
1044 XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
1046 XclImpDecrypterRef xDecr;
1047 DBG_ASSERT( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1048 if( rStrm.GetRecLeft() == 48 )
1050 sal_uInt8 pnSalt[ 16 ];
1051 sal_uInt8 pnVerifier[ 16 ];
1052 sal_uInt8 pnVerifierHash[ 16 ];
1053 rStrm.Read( pnSalt, 16 );
1054 rStrm.Read( pnVerifier, 16 );
1055 rStrm.Read( pnVerifierHash, 16 );
1056 xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
1058 return xDecr;
1061 XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
1063 // not supported
1064 return XclImpDecrypterRef();
1067 XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
1069 XclImpDecrypterRef xDecr;
1071 sal_uInt16 nMode;
1072 rStrm >> nMode;
1073 switch( nMode )
1075 case EXC_FILEPASS_BIFF5:
1076 xDecr = lclReadFilepass5( rStrm );
1077 break;
1079 case EXC_FILEPASS_BIFF8:
1081 rStrm.Ignore( 2 );
1082 sal_uInt16 nSubMode;
1083 rStrm >> nSubMode;
1084 switch( nSubMode )
1086 case EXC_FILEPASS_BIFF8_STD:
1087 xDecr = lclReadFilepass8_Standard( rStrm );
1088 break;
1089 case EXC_FILEPASS_BIFF8_STRONG:
1090 xDecr = lclReadFilepass8_Strong( rStrm );
1091 break;
1092 default:
1093 DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1096 break;
1098 default:
1099 DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
1102 return xDecr;
1105 } // namespace
1107 // ----------------------------------------------------------------------------
1109 ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
1111 XclImpDecrypterRef xDecr;
1112 rStrm.DisableDecryption();
1114 // read the FILEPASS record and create a new decrypter object
1115 switch( rStrm.GetRoot().GetBiff() )
1117 case EXC_BIFF2:
1118 case EXC_BIFF3:
1119 case EXC_BIFF4:
1120 case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm ); break;
1121 case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm ); break;
1122 default: DBG_ERROR_BIFF();
1125 // set decrypter at import stream
1126 rStrm.SetDecrypter( xDecr );
1128 // request and verify a password (decrypter implements IDocPasswordVerifier)
1129 if( xDecr.is() )
1130 rStrm.GetRoot().RequestPassword( *xDecr );
1132 // return error code (success, wrong password, etc.)
1133 return xDecr.is() ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
1136 // Document protection ========================================================
1138 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
1139 XclImpRoot( rRoot ),
1140 mnPassHash(0x0000),
1141 mbDocProtect(false),
1142 mbWinProtect(false)
1146 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
1148 mbDocProtect = rStrm.ReaduInt16() ? true : false;
1151 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
1153 mbWinProtect = rStrm.ReaduInt16() ? true : false;
1156 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
1158 rStrm.EnableDecryption();
1159 mnPassHash = rStrm.ReaduInt16();
1162 void XclImpDocProtectBuffer::Apply() const
1164 if (!mbDocProtect && !mbWinProtect)
1165 // Excel requires either the structure or windows protection is set.
1166 // If neither is set then the document is not protected at all.
1167 return;
1169 auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
1170 pProtect->setProtected(true);
1172 #if ENABLE_SHEET_PROTECTION
1173 if (mnPassHash)
1175 // 16-bit password pash.
1176 Sequence<sal_Int8> aPass(2);
1177 aPass[0] = (mnPassHash >> 8) & 0xFF;
1178 aPass[1] = mnPassHash & 0xFF;
1179 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1181 #endif
1183 // document protection options
1184 pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
1185 pProtect->setOption(ScDocProtection::WINDOWS, mbWinProtect);
1187 GetDoc().SetDocProtection(pProtect.get());
1190 // Sheet Protection ===========================================================
1192 XclImpSheetProtectBuffer::Sheet::Sheet() :
1193 mbProtected(false),
1194 mnPasswordHash(0x0000),
1195 mnOptions(0x4400)
1199 // ----------------------------------------------------------------------------
1201 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
1202 mbProtected(r.mbProtected),
1203 mnPasswordHash(r.mnPasswordHash),
1204 mnOptions(r.mnOptions)
1208 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
1209 XclImpRoot( rRoot )
1213 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
1215 if ( rStrm.ReaduInt16() )
1217 Sheet* pSheet = GetSheetItem(nTab);
1218 if (pSheet)
1219 pSheet->mbProtected = true;
1223 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
1225 rStrm.Ignore(19);
1226 sal_uInt16 nOptions;
1227 rStrm >> nOptions;
1229 Sheet* pSheet = GetSheetItem(nTab);
1230 if (pSheet)
1231 pSheet->mnOptions = nOptions;
1234 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
1236 sal_uInt16 nHash;
1237 rStrm >> nHash;
1238 Sheet* pSheet = GetSheetItem(nTab);
1239 if (pSheet)
1240 pSheet->mnPasswordHash = nHash;
1243 void XclImpSheetProtectBuffer::Apply() const
1245 for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
1246 itr != itrEnd; ++itr)
1248 if (!itr->second.mbProtected)
1249 // This sheet is (for whatever reason) not protected.
1250 continue;
1252 auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
1253 pProtect->setProtected(true);
1255 #if ENABLE_SHEET_PROTECTION
1256 // 16-bit hash password
1257 const sal_uInt16 nHash = itr->second.mnPasswordHash;
1258 if (nHash)
1260 Sequence<sal_Int8> aPass(2);
1261 aPass[0] = (nHash >> 8) & 0xFF;
1262 aPass[1] = nHash & 0xFF;
1263 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1265 #endif
1267 // sheet protection options
1268 const sal_uInt16 nOptions = itr->second.mnOptions;
1269 pProtect->setOption( ScTableProtection::OBJECTS, (nOptions & 0x0001) );
1270 pProtect->setOption( ScTableProtection::SCENARIOS, (nOptions & 0x0002) );
1271 pProtect->setOption( ScTableProtection::FORMAT_CELLS, (nOptions & 0x0004) );
1272 pProtect->setOption( ScTableProtection::FORMAT_COLUMNS, (nOptions & 0x0008) );
1273 pProtect->setOption( ScTableProtection::FORMAT_ROWS, (nOptions & 0x0010) );
1274 pProtect->setOption( ScTableProtection::INSERT_COLUMNS, (nOptions & 0x0020) );
1275 pProtect->setOption( ScTableProtection::INSERT_ROWS, (nOptions & 0x0040) );
1276 pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS, (nOptions & 0x0080) );
1277 pProtect->setOption( ScTableProtection::DELETE_COLUMNS, (nOptions & 0x0100) );
1278 pProtect->setOption( ScTableProtection::DELETE_ROWS, (nOptions & 0x0200) );
1279 pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS, (nOptions & 0x0400) );
1280 pProtect->setOption( ScTableProtection::SORT, (nOptions & 0x0800) );
1281 pProtect->setOption( ScTableProtection::AUTOFILTER, (nOptions & 0x1000) );
1282 pProtect->setOption( ScTableProtection::PIVOT_TABLES, (nOptions & 0x2000) );
1283 pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
1285 // all done. now commit.
1286 GetDoc().SetTabProtection(itr->first, pProtect.get());
1290 XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
1292 ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
1293 if (itr == maProtectedSheets.end())
1295 // new sheet
1296 if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
1297 return NULL;
1299 itr = maProtectedSheets.find(nTab);
1302 return &itr->second;
1305 // ============================================================================