update ooo310-m15
[ooovba.git] / sc / source / filter / excel / xicontent.cxx
blobc8ff7b92fb9e23ab92b8cbfd3b406a6b556f6e77
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 for (xub_StrLen i = 1; i < n; ++i)
382 c = rUrl.GetChar(i);
383 if (c == sal_Unicode('\''))
385 bInQuote = !bInQuote;
386 if (!bInQuote && aTabName.Len() > 0)
387 aNewUrl.Append(aTabName);
389 else if (bInQuote)
390 aTabName.Append(c);
391 else
392 aNewUrl.Append(c);
395 if (bInQuote)
396 // It should be outside the quotes!
397 return;
399 // All is good. Pass the new URL.
400 rUrl = aNewUrl;
403 void XclImpHyperlink::InsertUrl( const XclImpRoot& rRoot, const XclRange& rXclRange, const String& rUrl )
405 String aUrl(rUrl);
406 ConvertToValidTabName(aUrl);
408 SCTAB nScTab = rRoot.GetCurrScTab();
409 ScRange aScRange( ScAddress::UNINITIALIZED );
410 if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
412 SCCOL nScCol1, nScCol2;
413 SCROW nScRow1, nScRow2;
414 aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
415 for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
416 for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
417 lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
421 // Label ranges ===============================================================
423 void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
425 const XclImpRoot& rRoot = rStrm.GetRoot();
426 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
428 ScDocument& rDoc = rRoot.GetDoc();
429 SCTAB nScTab = rRoot.GetCurrScTab();
430 XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
431 ScRangePairListRef xLabelRangesRef;
432 const ScRange* pScRange = 0;
434 XclRangeList aRowXclRanges, aColXclRanges;
435 rStrm >> aRowXclRanges >> aColXclRanges;
437 // row label ranges
438 ScRangeList aRowScRanges;
439 rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
440 xLabelRangesRef = rDoc.GetRowNameRangesRef();
441 for( pScRange = aRowScRanges.First(); pScRange; pScRange = aRowScRanges.Next() )
443 ScRange aDataRange( *pScRange );
444 if( aDataRange.aEnd.Col() < MAXCOL )
446 aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
447 aDataRange.aEnd.SetCol( MAXCOL );
449 else if( aDataRange.aStart.Col() > 0 )
451 aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
452 aDataRange.aStart.SetCol( 0 );
454 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
457 // column label ranges
458 ScRangeList aColScRanges;
459 rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
460 xLabelRangesRef = rDoc.GetColNameRangesRef();
461 for( pScRange = aColScRanges.First(); pScRange; pScRange = aColScRanges.Next() )
463 ScRange aDataRange( *pScRange );
464 if( aDataRange.aEnd.Row() < MAXROW )
466 aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
467 aDataRange.aEnd.SetRow( MAXROW );
469 else if( aDataRange.aStart.Row() > 0 )
471 aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
472 aDataRange.aStart.SetRow( 0 );
474 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
478 // Conditional formatting =====================================================
480 XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
481 XclImpRoot( rRoot ),
482 mnFormatIndex( nFormatIndex ),
483 mnCondCount( 0 ),
484 mnCondIndex( 0 )
488 XclImpCondFormat::~XclImpCondFormat()
492 void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
494 DBG_ASSERT( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
495 XclRangeList aXclRanges;
496 rStrm >> mnCondCount;
497 rStrm.Ignore( 10 );
498 rStrm >> aXclRanges;
499 GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
502 void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
504 if( mnCondIndex >= mnCondCount )
506 DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
507 return;
510 // entire conditional format outside of valid range?
511 if( !maRanges.Count() )
512 return;
514 sal_uInt8 nType, nOperator;
515 sal_uInt16 nFmlaSize1, nFmlaSize2;
516 sal_uInt32 nFlags;
518 rStrm >> nType >> nOperator >> nFmlaSize1 >> nFmlaSize2 >> nFlags;
519 rStrm.Ignore( 2 );
521 // *** mode and comparison operator ***
523 ScConditionMode eMode = SC_COND_NONE;
524 switch( nType )
526 case EXC_CF_TYPE_CELL:
528 switch( nOperator )
530 case EXC_CF_CMP_BETWEEN: eMode = SC_COND_BETWEEN; break;
531 case EXC_CF_CMP_NOT_BETWEEN: eMode = SC_COND_NOTBETWEEN; break;
532 case EXC_CF_CMP_EQUAL: eMode = SC_COND_EQUAL; break;
533 case EXC_CF_CMP_NOT_EQUAL: eMode = SC_COND_NOTEQUAL; break;
534 case EXC_CF_CMP_GREATER: eMode = SC_COND_GREATER; break;
535 case EXC_CF_CMP_LESS: eMode = SC_COND_LESS; break;
536 case EXC_CF_CMP_GREATER_EQUAL: eMode = SC_COND_EQGREATER; break;
537 case EXC_CF_CMP_LESS_EQUAL: eMode = SC_COND_EQLESS; break;
538 default:
539 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator );
542 break;
544 case EXC_CF_TYPE_FMLA:
545 eMode = SC_COND_DIRECT;
546 break;
548 default:
549 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType );
550 return;
553 // *** create style sheet ***
555 String aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
556 SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
558 const XclImpPalette& rPalette = GetPalette();
560 // *** font block ***
562 if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
564 XclImpFont aFont( GetRoot() );
565 aFont.ReadCFFontBlock( rStrm );
566 aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
569 // *** border block ***
571 if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
573 sal_uInt16 nLineStyle;
574 sal_uInt32 nLineColor;
575 rStrm >> nLineStyle >> nLineColor;
576 rStrm.Ignore( 2 );
578 XclImpCellBorder aBorder;
579 aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
580 aBorder.FillToItemSet( rStyleItemSet, rPalette );
583 // *** pattern block ***
585 if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
587 sal_uInt16 nPattern, nColor;
588 rStrm >> nPattern >> nColor;
590 XclImpCellArea aArea;
591 aArea.FillFromCF8( nPattern, nColor, nFlags );
592 aArea.FillToItemSet( rStyleItemSet, rPalette );
595 // *** formulas ***
597 const ScAddress& rPos = maRanges.GetObject( 0 )->aStart; // assured above that maRanges is not empty
598 ExcelToSc& rFmlaConv = GetOldFmlaConverter();
600 ::std::auto_ptr< ScTokenArray > xTokArr1;
601 if( nFmlaSize1 > 0 )
603 const ScTokenArray* pTokArr = 0;
604 rFmlaConv.Reset( rPos );
605 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_RangeName );
606 // formula converter owns pTokArr -> create a copy of the token array
607 if( pTokArr )
608 xTokArr1.reset( pTokArr->Clone() );
611 ::std::auto_ptr< ScTokenArray > pTokArr2;
612 if( nFmlaSize2 > 0 )
614 const ScTokenArray* pTokArr = 0;
615 rFmlaConv.Reset( rPos );
616 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_RangeName );
617 // formula converter owns pTokArr -> create a copy of the token array
618 if( pTokArr )
619 pTokArr2.reset( pTokArr->Clone() );
622 // *** create the Calc conditional formatting ***
624 if( !mxScCondFmt.get() )
626 ULONG nKey = 0;
627 mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
630 ScCondFormatEntry aEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
631 mxScCondFmt->AddEntry( aEntry );
632 ++mnCondIndex;
635 void XclImpCondFormat::Apply()
637 if( mxScCondFmt.get() )
639 ScDocument& rDoc = GetDoc();
641 ULONG nKey = rDoc.AddCondFormat( *mxScCondFmt );
642 ScPatternAttr aPattern( rDoc.GetPool() );
643 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL, nKey ) );
645 // maRanges contains only valid cell ranges
646 for( const ScRange* pScRange = maRanges.First(); pScRange; pScRange = maRanges.Next() )
648 rDoc.ApplyPatternAreaTab(
649 pScRange->aStart.Col(), pScRange->aStart.Row(),
650 pScRange->aEnd.Col(), pScRange->aEnd.Row(),
651 pScRange->aStart.Tab(), aPattern );
656 // ----------------------------------------------------------------------------
658 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
659 XclImpRoot( rRoot )
663 void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
665 XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.Count() );
666 pFmt->ReadCondfmt( rStrm );
667 maCondFmtList.Append( pFmt );
670 void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
672 DBG_ASSERT( !maCondFmtList.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
673 if( !maCondFmtList.Empty() )
674 maCondFmtList.GetObject( maCondFmtList.Count() - 1 )->ReadCF( rStrm );
677 void XclImpCondFormatManager::Apply()
679 for( XclImpCondFormat* pFmt = maCondFmtList.First(); pFmt; pFmt = maCondFmtList.Next() )
680 pFmt->Apply();
681 maCondFmtList.Clear();
684 // Data Validation ============================================================
686 void XclImpValidation::ReadDval( XclImpStream& rStrm )
688 const XclImpRoot& rRoot = rStrm.GetRoot();
689 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
691 sal_uInt32 nObjId;
692 rStrm.Ignore( 10 );
693 rStrm >> nObjId;
694 if( nObjId != EXC_DVAL_NOOBJ )
696 DBG_ASSERT( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
697 rRoot.GetObjectManager().SetSkipObj( rRoot.GetCurrScTab(), static_cast< sal_uInt16 >( nObjId ) );
701 void XclImpValidation::ReadDV( XclImpStream& rStrm )
703 const XclImpRoot& rRoot = rStrm.GetRoot();
704 DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
706 ScDocument& rDoc = rRoot.GetDoc();
707 SCTAB nScTab = rRoot.GetCurrScTab();
708 ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
710 // flags
711 sal_uInt32 nFlags;
712 rStrm >> nFlags;
714 // message strings
715 /* Empty strings are single NUL characters in Excel (string length is 1).
716 -> Do not let the stream replace them with '?' characters. */
717 rStrm.SetNulSubstChar( '\0' );
718 String aPromptTitle( rStrm.ReadUniString() );
719 String aErrorTitle( rStrm.ReadUniString() );
720 String aPromptMessage( rStrm.ReadUniString() );
721 String aErrorMessage( rStrm.ReadUniString() );
722 rStrm.SetNulSubstChar(); // back to default
724 // formula(s)
725 if( rStrm.GetRecLeft() > 8 )
727 sal_uInt16 nLen;
729 // first formula
730 // string list is single tStr token with NUL separators -> replace them with LF
731 rStrm.SetNulSubstChar( '\n' );
732 ::std::auto_ptr< ScTokenArray > xTokArr1;
733 rStrm >> nLen;
734 rStrm.Ignore( 2 );
735 if( nLen > 0 )
737 const ScTokenArray* pTokArr = 0;
738 rFmlaConv.Reset();
739 rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
740 // formula converter owns pTokArr -> create a copy of the token array
741 if( pTokArr )
742 xTokArr1.reset( pTokArr->Clone() );
744 rStrm.SetNulSubstChar(); // back to default
746 // second formula
747 ::std::auto_ptr< ScTokenArray > xTokArr2;
748 rStrm >> nLen;
749 rStrm.Ignore( 2 );
750 if( nLen > 0 )
752 const ScTokenArray* pTokArr = 0;
753 rFmlaConv.Reset();
754 rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
755 // formula converter owns pTokArr -> create a copy of the token array
756 if( pTokArr )
757 xTokArr2.reset( pTokArr->Clone() );
760 // read all cell ranges
761 XclRangeList aXclRanges;
762 rStrm >> aXclRanges;
764 // convert to Calc range list
765 ScRangeList aScRanges;
766 rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
768 // only continue if there are valid ranges
769 if( aScRanges.Count() )
771 bool bIsValid = true; // valid settings in flags field
773 ScValidationMode eValMode = SC_VALID_ANY;
774 switch( nFlags & EXC_DV_MODE_MASK )
776 case EXC_DV_MODE_ANY: eValMode = SC_VALID_ANY; break;
777 case EXC_DV_MODE_WHOLE: eValMode = SC_VALID_WHOLE; break;
778 case EXC_DV_MODE_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
779 case EXC_DV_MODE_LIST: eValMode = SC_VALID_LIST; break;
780 case EXC_DV_MODE_DATE: eValMode = SC_VALID_DATE; break;
781 case EXC_DV_MODE_TIME: eValMode = SC_VALID_TIME; break;
782 case EXC_DV_MODE_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
783 case EXC_DV_MODE_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
784 default: bIsValid = false;
786 rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
788 ScConditionMode eCondMode = SC_COND_BETWEEN;
789 switch( nFlags & EXC_DV_COND_MASK )
791 case EXC_DV_COND_BETWEEN: eCondMode = SC_COND_BETWEEN; break;
792 case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
793 case EXC_DV_COND_EQUAL: eCondMode = SC_COND_EQUAL; break;
794 case EXC_DV_COND_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break;
795 case EXC_DV_COND_GREATER: eCondMode = SC_COND_GREATER; break;
796 case EXC_DV_COND_LESS: eCondMode = SC_COND_LESS; break;
797 case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER; break;
798 case EXC_DV_COND_EQLESS: eCondMode = SC_COND_EQLESS; break;
799 default: bIsValid = false;
802 if( bIsValid )
804 // first range for base address for relative references
805 const ScRange& rScRange = *aScRanges.GetObject( 0 ); // aScRanges is not empty
807 // process string list of a list validity (convert to list of string tokens)
808 if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
809 XclTokenArrayHelper::ConvertStringToList( *xTokArr1, '\n', true );
811 ScValidationData aValidData( eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart );
813 aValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
814 aValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, ValidListType::INVISIBLE, ValidListType::UNSORTED ) );
816 // *** prompt box ***
817 if( aPromptTitle.Len() || aPromptMessage.Len() )
819 // set any text stored in the record
820 aValidData.SetInput( aPromptTitle, aPromptMessage );
821 if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
822 aValidData.ResetInput();
825 // *** error box ***
826 ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
827 switch( nFlags & EXC_DV_ERROR_MASK )
829 case EXC_DV_ERROR_WARNING: eErrStyle = SC_VALERR_WARNING; break;
830 case EXC_DV_ERROR_INFO: eErrStyle = SC_VALERR_INFO; break;
832 // set texts and error style
833 aValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
834 if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
835 aValidData.ResetError();
837 // set the handle ID
838 ULONG nHandle = rDoc.AddValidationEntry( aValidData );
839 ScPatternAttr aPattern( rDoc.GetPool() );
840 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
842 // apply all ranges
843 for( const ScRange* pScRange = aScRanges.First(); pScRange; pScRange = aScRanges.Next() )
844 rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
845 pScRange->aEnd.Col(), pScRange->aEnd.Row(), nScTab, aPattern );
851 // Web queries ================================================================
853 XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
854 maDestRange( rDestRange ),
855 meMode( xlWQUnknown ),
856 mnRefresh( 0 )
860 void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
862 sal_uInt16 nFlags = rStrm.ReaduInt16();
863 sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
864 if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
866 if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
868 meMode = xlWQAllTables;
869 maTables = ScfTools::GetHTMLTablesName();
871 else
873 meMode = xlWQDocument;
874 maTables = ScfTools::GetHTMLDocName();
879 void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
881 maURL = rStrm.ReadUniString();
884 void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
886 sal_uInt16 nFlags;
887 rStrm.Ignore( 10 );
888 rStrm >> nFlags;
889 rStrm.Ignore( 10 );
890 rStrm >> mnRefresh;
892 if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
893 meMode = xlWQSpecTables;
896 void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
898 if( meMode == xlWQSpecTables )
900 rStrm.Ignore( 4 );
901 String aTables( rStrm.ReadUniString() );
903 const sal_Unicode cSep = ';';
904 aTables.SearchAndReplaceAll( ',', cSep );
905 String aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
906 xub_StrLen nTokenCnt = aTables.GetQuotedTokenCount( aQuotedPairs, cSep );
907 maTables.Erase();
908 xub_StrLen nStringIx = 0;
909 for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
911 String aToken( aTables.GetQuotedToken( 0, aQuotedPairs, cSep, nStringIx ) );
912 sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.ToInt32() : 0;
913 if( nTabNum > 0 )
914 ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
915 else
917 ScGlobal::EraseQuotes( aToken, '"', false );
918 if( aToken.Len() )
919 ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
925 void XclImpWebQuery::Apply( ScDocument& rDoc, const String& rFilterName )
927 if( maURL.Len() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
929 ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
930 maURL, rFilterName, EMPTY_STRING, maTables, maDestRange, mnRefresh * 60UL );
931 rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
932 maURL, &rFilterName, &maTables );
936 // ----------------------------------------------------------------------------
938 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
939 XclImpRoot( rRoot )
943 void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
945 if( GetBiff() == EXC_BIFF8 )
947 rStrm.Ignore( 10 );
948 String aXclName( rStrm.ReadUniString() );
950 // #i64794# Excel replaces spaces with underscores
951 aXclName.SearchAndReplaceAll( ' ', '_' );
953 // #101529# find the defined name used in Calc
954 if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
956 if( const ScRangeData* pRangeData = pName->GetScRangeData() )
958 ScRange aRange;
959 if( pRangeData->IsReference( aRange ) )
960 maWQList.Append( new XclImpWebQuery( aRange ) );
964 else
966 DBG_ERROR_BIFF();
970 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
972 if( XclImpWebQuery* pQuery = maWQList.Last() )
973 pQuery->ReadParamqry( rStrm );
976 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
978 if( XclImpWebQuery* pQuery = maWQList.Last() )
979 pQuery->ReadWqstring( rStrm );
982 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
984 if( XclImpWebQuery* pQuery = maWQList.Last() )
985 pQuery->ReadWqsettings( rStrm );
988 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
990 if( XclImpWebQuery* pQuery = maWQList.Last() )
991 pQuery->ReadWqtables( rStrm );
994 void XclImpWebQueryBuffer::Apply()
996 ScDocument& rDoc = GetDoc();
997 String aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER ) );
998 for( XclImpWebQuery* pQuery = maWQList.First(); pQuery; pQuery = maWQList.Next() )
999 pQuery->Apply( rDoc, aFilterName );
1002 // Decryption =================================================================
1004 namespace {
1006 XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
1008 XclImpDecrypterRef xDecr;
1009 DBG_ASSERT( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1010 if( rStrm.GetRecLeft() == 4 )
1012 sal_uInt16 nKey, nHash;
1013 rStrm >> nKey >> nHash;
1014 xDecr.reset( new XclImpBiff5Decrypter( rStrm.GetRoot(), nKey, nHash ) );
1016 return xDecr;
1019 XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
1021 XclImpDecrypterRef xDecr;
1022 DBG_ASSERT( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1023 if( rStrm.GetRecLeft() == 48 )
1025 sal_uInt8 pnDocId[ 16 ];
1026 sal_uInt8 pnSaltData[ 16 ];
1027 sal_uInt8 pnSaltHash[ 16 ];
1028 rStrm.Read( pnDocId, 16 );
1029 rStrm.Read( pnSaltData, 16 );
1030 rStrm.Read( pnSaltHash, 16 );
1031 xDecr.reset( new XclImpBiff8Decrypter(
1032 rStrm.GetRoot(), pnDocId, pnSaltData, pnSaltHash ) );
1034 return xDecr;
1037 XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
1039 // not supported
1040 return XclImpDecrypterRef();
1043 XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
1045 XclImpDecrypterRef xDecr;
1047 sal_uInt16 nMode;
1048 rStrm >> nMode;
1049 switch( nMode )
1051 case EXC_FILEPASS_BIFF5:
1052 xDecr = lclReadFilepass5( rStrm );
1053 break;
1055 case EXC_FILEPASS_BIFF8:
1057 rStrm.Ignore( 2 );
1058 sal_uInt16 nSubMode;
1059 rStrm >> nSubMode;
1060 switch( nSubMode )
1062 case EXC_FILEPASS_BIFF8_STD:
1063 xDecr = lclReadFilepass8_Standard( rStrm );
1064 break;
1065 case EXC_FILEPASS_BIFF8_STRONG:
1066 xDecr = lclReadFilepass8_Strong( rStrm );
1067 break;
1068 default:
1069 DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1072 break;
1074 default:
1075 DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
1078 return xDecr;
1081 } // namespace
1083 // ----------------------------------------------------------------------------
1085 ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
1087 XclImpDecrypterRef xDecr;
1088 rStrm.DisableDecryption();
1090 switch( rStrm.GetRoot().GetBiff() )
1092 case EXC_BIFF2:
1093 case EXC_BIFF3:
1094 case EXC_BIFF4:
1095 case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm ); break;
1096 case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm ); break;
1097 default: DBG_ERROR_BIFF();
1100 if (!xDecr.is())
1101 return EXC_ENCR_ERROR_UNSUPP_CRYPT;
1103 // set decrypter at import stream
1104 rStrm.SetDecrypter( xDecr );
1106 // Store the document password for export.
1107 SfxItemSet* pSet = rStrm.GetRoot().GetDocShell()->GetMedium()->GetItemSet();
1108 if (pSet)
1110 String aPass = xDecr->GetPassword();
1111 pSet->Put( SfxStringItem(SID_PASSWORD, aPass) );
1114 return xDecr->GetError();
1117 // Document protection ========================================================
1119 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
1120 XclImpRoot( rRoot ),
1121 mnPassHash(0x0000),
1122 mbDocProtect(false),
1123 mbWinProtect(false)
1127 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
1129 mbDocProtect = rStrm.ReaduInt16() ? true : false;
1132 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
1134 mbWinProtect = rStrm.ReaduInt16() ? true : false;
1137 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
1139 rStrm.EnableDecryption();
1140 mnPassHash = rStrm.ReaduInt16();
1143 void XclImpDocProtectBuffer::Apply() const
1145 if (!mbDocProtect && !mbWinProtect)
1146 // Excel requires either the structure or windows protection is set.
1147 // If neither is set then the document is not protected at all.
1148 return;
1150 auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
1151 pProtect->setProtected(true);
1153 #if ENABLE_SHEET_PROTECTION
1154 if (mnPassHash)
1156 // 16-bit password pash.
1157 Sequence<sal_Int8> aPass(2);
1158 aPass[0] = (mnPassHash >> 8) & 0xFF;
1159 aPass[1] = mnPassHash & 0xFF;
1160 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1162 #endif
1164 // document protection options
1165 pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
1166 pProtect->setOption(ScDocProtection::WINDOWS, mbWinProtect);
1168 GetDoc().SetDocProtection(pProtect.get());
1171 // Sheet Protection ===========================================================
1173 XclImpSheetProtectBuffer::Sheet::Sheet() :
1174 mbProtected(false),
1175 mnPasswordHash(0x0000),
1176 mnOptions(0x4400)
1180 // ----------------------------------------------------------------------------
1182 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
1183 mbProtected(r.mbProtected),
1184 mnPasswordHash(r.mnPasswordHash),
1185 mnOptions(r.mnOptions)
1189 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
1190 XclImpRoot( rRoot )
1194 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
1196 if ( rStrm.ReaduInt16() )
1198 Sheet* pSheet = GetSheetItem(nTab);
1199 if (pSheet)
1200 pSheet->mbProtected = true;
1204 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
1206 rStrm.Ignore(19);
1207 sal_uInt16 nOptions;
1208 rStrm >> nOptions;
1210 Sheet* pSheet = GetSheetItem(nTab);
1211 if (pSheet)
1212 pSheet->mnOptions = nOptions;
1215 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
1217 sal_uInt16 nHash;
1218 rStrm >> nHash;
1219 Sheet* pSheet = GetSheetItem(nTab);
1220 if (pSheet)
1221 pSheet->mnPasswordHash = nHash;
1224 void XclImpSheetProtectBuffer::Apply() const
1226 for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
1227 itr != itrEnd; ++itr)
1229 if (!itr->second.mbProtected)
1230 // This sheet is (for whatever reason) not protected.
1231 continue;
1233 auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
1234 pProtect->setProtected(true);
1236 #if ENABLE_SHEET_PROTECTION
1237 // 16-bit hash password
1238 const sal_uInt16 nHash = itr->second.mnPasswordHash;
1239 if (nHash)
1241 Sequence<sal_Int8> aPass(2);
1242 aPass[0] = (nHash >> 8) & 0xFF;
1243 aPass[1] = nHash & 0xFF;
1244 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1246 #endif
1248 // sheet protection options
1249 const sal_uInt16 nOptions = itr->second.mnOptions;
1250 pProtect->setOption( ScTableProtection::OBJECTS, (nOptions & 0x0001) );
1251 pProtect->setOption( ScTableProtection::SCENARIOS, (nOptions & 0x0002) );
1252 pProtect->setOption( ScTableProtection::FORMAT_CELLS, (nOptions & 0x0004) );
1253 pProtect->setOption( ScTableProtection::FORMAT_COLUMNS, (nOptions & 0x0008) );
1254 pProtect->setOption( ScTableProtection::FORMAT_ROWS, (nOptions & 0x0010) );
1255 pProtect->setOption( ScTableProtection::INSERT_COLUMNS, (nOptions & 0x0020) );
1256 pProtect->setOption( ScTableProtection::INSERT_ROWS, (nOptions & 0x0040) );
1257 pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS, (nOptions & 0x0080) );
1258 pProtect->setOption( ScTableProtection::DELETE_COLUMNS, (nOptions & 0x0100) );
1259 pProtect->setOption( ScTableProtection::DELETE_ROWS, (nOptions & 0x0200) );
1260 pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS, (nOptions & 0x0400) );
1261 pProtect->setOption( ScTableProtection::SORT, (nOptions & 0x0800) );
1262 pProtect->setOption( ScTableProtection::AUTOFILTER, (nOptions & 0x1000) );
1263 pProtect->setOption( ScTableProtection::PIVOT_TABLES, (nOptions & 0x2000) );
1264 pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
1266 // all done. now commit.
1267 GetDoc().SetTabProtection(itr->first, pProtect.get());
1271 XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
1273 ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
1274 if (itr == maProtectedSheets.end())
1276 // new sheet
1277 if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
1278 return NULL;
1280 itr = maProtectedSheets.find(nTab);
1283 return &itr->second;
1286 // ============================================================================