1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xicontent.hxx"
21 #include <sfx2/objsh.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <tools/urlobj.hxx>
24 #include <editeng/editeng.hxx>
25 #include <editeng/editobj.hxx>
26 #include <sfx2/linkmgr.hxx>
27 #include <svl/itemset.hxx>
28 #include "scitems.hxx"
29 #include <editeng/eeitem.hxx>
30 #include <svl/intitem.hxx>
31 #include <svl/stritem.hxx>
32 #include <editeng/flditem.hxx>
33 #include <editeng/fhgtitem.hxx>
34 #include <editeng/wghtitem.hxx>
35 #include <editeng/udlnitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/colritem.hxx>
38 #include <editeng/crossedoutitem.hxx>
39 #include "stringutil.hxx"
40 #include "document.hxx"
41 #include "editutil.hxx"
42 #include "formulacell.hxx"
43 #include "validat.hxx"
44 #include "patattr.hxx"
45 #include "docpool.hxx"
46 #include "rangenam.hxx"
47 #include "arealink.hxx"
48 #include "stlsheet.hxx"
49 #include "scextopt.hxx"
50 #include "xlformula.hxx"
51 #include "xltracer.hxx"
52 #include "xistream.hxx"
53 #include "xihelper.hxx"
54 #include "xistyle.hxx"
55 #include "xiescher.hxx"
58 #include "excform.hxx"
59 #include "tabprotection.hxx"
63 using ::com::sun::star::uno::Sequence
;
64 using ::std::auto_ptr
;
66 // Shared string table ========================================================
68 XclImpSst::XclImpSst( const XclImpRoot
& rRoot
) :
73 void XclImpSst::ReadSst( XclImpStream
& rStrm
)
76 sal_uInt32
nStrCount(0);
79 maStrings
.reserve( static_cast< size_t >( nStrCount
) );
80 while( (nStrCount
> 0) && rStrm
.IsValid() )
83 aString
.Read( rStrm
);
84 maStrings
.push_back( aString
);
89 const XclImpString
* XclImpSst::GetString( sal_uInt32 nSstIndex
) const
91 return (nSstIndex
< maStrings
.size()) ? &maStrings
[ nSstIndex
] : 0;
94 // Hyperlinks =================================================================
98 /** Reads character array and stores it into rString.
99 @param nChars Number of following characters (not byte count!).
100 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
101 void lclAppendString32( String
& rString
, XclImpStream
& rStrm
, sal_uInt32 nChars
, bool b16Bit
)
103 sal_uInt16 nReadChars
= ulimit_cast
< sal_uInt16
>( nChars
);
104 rString
.Append( rStrm
.ReadRawUniString( nReadChars
, b16Bit
) );
105 // ignore remaining chars
106 sal_Size nIgnore
= nChars
- nReadChars
;
109 rStrm
.Ignore( nIgnore
);
112 /** Reads 32-bit string length and the character array and stores it into rString.
113 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
114 void lclAppendString32( String
& rString
, XclImpStream
& rStrm
, bool b16Bit
)
116 lclAppendString32( rString
, rStrm
, rStrm
.ReaduInt32(), b16Bit
);
119 /** Reads 32-bit string length and ignores following character array.
120 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
121 void lclIgnoreString32( XclImpStream
& rStrm
, bool b16Bit
)
123 sal_uInt32
nChars(0);
127 rStrm
.Ignore( nChars
);
130 /** Converts a path to an absolute path.
131 @param rPath The source path. The resulting path is returned here.
132 @param nLevel Number of parent directories to add in front of the path. */
133 void lclGetAbsPath( String
& rPath
, sal_uInt16 nLevel
, SfxObjectShell
* pDocShell
)
138 aTmpStr
.AppendAscii( "../" );
145 bool bWasAbs
= false;
146 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
, bWasAbs
).GetMainURL( INetURLObject::NO_DECODE
);
147 // full path as stored in SvxURLField must be encoded
153 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
154 void lclInsertUrl( const XclImpRoot
& rRoot
, const String
& rUrl
, SCCOL nScCol
, SCROW nScRow
, SCTAB nScTab
)
156 ScDocument
& rDoc
= rRoot
.GetDoc();
157 ScAddress
aScPos( nScCol
, nScRow
, nScTab
);
158 CellType eCellType
= rDoc
.GetCellType( aScPos
);
161 // #i54261# hyperlinks in string cells
162 case CELLTYPE_STRING
:
165 OUString aDisplText
= rDoc
.GetString(nScCol
, nScRow
, nScTab
);
166 if (aDisplText
.isEmpty())
169 ScEditEngineDefaulter
& rEE
= rRoot
.GetEditEngine();
170 SvxURLField
aUrlField( rUrl
, aDisplText
, SVXURLFORMAT_APPDEFAULT
);
172 const EditTextObject
* pEditObj
= rDoc
.GetEditText(aScPos
);
175 rEE
.SetText( *pEditObj
);
176 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection( 0, 0, EE_PARA_ALL
, 0 ) );
180 rEE
.SetText( EMPTY_STRING
);
181 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection() );
182 if( const ScPatternAttr
* pPattern
= rDoc
.GetPattern( aScPos
.Col(), aScPos
.Row(), nScTab
) )
184 SfxItemSet
aItemSet( rEE
.GetEmptyItemSet() );
185 pPattern
->FillEditItemSet( &aItemSet
);
186 rEE
.QuickSetAttribs( aItemSet
, ESelection( 0, 0, EE_PARA_ALL
, 0 ) );
190 // The cell will own the text object instance.
191 rDoc
.SetEditText(aScPos
, rEE
.CreateTextObject());
196 // Handle other cell types e.g. formulas ( and ? ) that have associated
198 // Ideally all hyperlinks should be treated as below. For the moment,
199 // given the current absence of ods support lets just handle what we
200 // previously didn't handle the new way.
201 // Unfortunately we won't be able to preserve such hyperlinks when
202 // saving to ods. Note: when we are able to save such hyperlinks to ods
203 // we should handle *all* imported hyperlinks as below ( e.g. as cell
204 // attribute ) for better interoperability.
206 SfxStringItem
aItem( ATTR_HYPERLINK
, rUrl
);
207 rDoc
.ApplyAttr( nScCol
, nScRow
, nScTab
, aItem
);
215 // ----------------------------------------------------------------------------
217 void XclImpHyperlink::ReadHlink( XclImpStream
& rStrm
)
219 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
221 // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
222 aXclRange
.maFirst
.mnCol
&= 0xFF;
223 aXclRange
.maLast
.mnCol
&= 0xFF;
224 String aString
= ReadEmbeddedData( rStrm
);
225 if ( aString
.Len() > 0 )
226 rStrm
.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange
, aString
);
229 String
XclImpHyperlink::ReadEmbeddedData( XclImpStream
& rStrm
)
231 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
232 SfxObjectShell
* pDocShell
= rRoot
.GetDocShell();
234 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
239 sal_uInt32
nFlags(0);
242 OSL_ENSURE( aGuid
== XclTools::maGuidStdLink
, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
244 SAL_WNODEPRECATED_DECLARATIONS_PUSH
245 ::std::auto_ptr
< String
> xLongName
; // link / file name
246 ::std::auto_ptr
< String
> xShortName
; // 8.3-representation of file name
247 ::std::auto_ptr
< String
> xTextMark
; // text mark
248 SAL_WNODEPRECATED_DECLARATIONS_POP
250 // description (ignore)
251 if( ::get_flag( nFlags
, EXC_HLINK_DESCR
) )
252 lclIgnoreString32( rStrm
, true );
253 // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
254 if( ::get_flag( nFlags
, EXC_HLINK_FRAME
) )
255 lclIgnoreString32( rStrm
, true );
257 // URL fields are zero-terminated - do not let the stream replace them
258 // in the lclAppendString32() with the '?' character.
259 rStrm
.SetNulSubstChar( '\0' );
262 if( ::get_flag( nFlags
, EXC_HLINK_UNC
) )
264 xLongName
.reset( new String
);
265 lclAppendString32( *xLongName
, rStrm
, true );
266 lclGetAbsPath( *xLongName
, 0, pDocShell
);
269 else if( ::get_flag( nFlags
, EXC_HLINK_BODY
) )
273 if( aGuid
== XclTools::maGuidFileMoniker
)
275 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
277 xShortName
.reset( new String
);
278 lclAppendString32( *xShortName
, rStrm
, false );
281 sal_uInt32 nStrLen
= 0;
287 nStrLen
/= 2; // it's byte count here...
289 xLongName
.reset( new String
);
290 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
291 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
294 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
296 else if( aGuid
== XclTools::maGuidUrlMoniker
)
298 sal_uInt32
nStrLen(0);
300 nStrLen
/= 2; // it's byte count here...
301 xLongName
.reset( new String
);
302 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
303 if( !::get_flag( nFlags
, EXC_HLINK_ABS
) )
304 lclGetAbsPath( *xLongName
, 0, pDocShell
);
308 OSL_FAIL( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
313 if( ::get_flag( nFlags
, EXC_HLINK_MARK
) )
315 xTextMark
.reset( new String
);
316 lclAppendString32( *xTextMark
, rStrm
, true );
319 rStrm
.SetNulSubstChar(); // back to default
321 OSL_ENSURE( rStrm
.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
323 if( !xLongName
.get() && xShortName
.get() )
324 xLongName
= xShortName
;
325 else if( !xLongName
.get() && xTextMark
.get() )
326 xLongName
.reset( new String
);
328 if( xLongName
.get() )
330 if( xTextMark
.get() )
332 if( xLongName
->Len() == 0 )
333 xTextMark
->SearchAndReplaceAll( '!', '.' );
334 xLongName
->Append( '#' );
335 xLongName
->Append( *xTextMark
);
339 return String::EmptyString();
342 void XclImpHyperlink::ConvertToValidTabName(String
& rUrl
)
344 xub_StrLen n
= rUrl
.Len();
346 // Needs at least 4 characters.
349 sal_Unicode c
= rUrl
.GetChar(0);
350 if (c
!= sal_Unicode('#'))
351 // the 1st character must be '#'.
354 String
aNewUrl(OUString('#')), aTabName
;
356 bool bInQuote
= false;
357 bool bQuoteTabName
= false;
358 for (xub_StrLen i
= 1; i
< n
; ++i
)
361 if (c
== sal_Unicode('\''))
363 if (bInQuote
&& i
+1 < n
&& rUrl
.GetChar(i
+1) == sal_Unicode('\''))
365 // Two consecutive single quotes ('') signify a single literal
366 // quite. When this occurs, the whole table name needs to be
368 bQuoteTabName
= true;
375 bInQuote
= !bInQuote
;
376 if (!bInQuote
&& aTabName
.Len() > 0)
379 aNewUrl
.Append(sal_Unicode('\''));
380 aNewUrl
.Append(aTabName
);
382 aNewUrl
.Append(sal_Unicode('\''));
392 // It should be outside the quotes!
395 // All is good. Pass the new URL.
399 void XclImpHyperlink::InsertUrl( const XclImpRoot
& rRoot
, const XclRange
& rXclRange
, const String
& rUrl
)
402 ConvertToValidTabName(aUrl
);
404 SCTAB nScTab
= rRoot
.GetCurrScTab();
405 ScRange
aScRange( ScAddress::UNINITIALIZED
);
406 if( rRoot
.GetAddressConverter().ConvertRange( aScRange
, rXclRange
, nScTab
, nScTab
, true ) )
408 SCCOL nScCol1
, nScCol2
;
409 SCROW nScRow1
, nScRow2
;
410 aScRange
.GetVars( nScCol1
, nScRow1
, nScTab
, nScCol2
, nScRow2
, nScTab
);
411 for( SCCOL nScCol
= nScCol1
; nScCol
<= nScCol2
; ++nScCol
)
412 for( SCROW nScRow
= nScRow1
; nScRow
<= nScRow2
; ++nScRow
)
413 lclInsertUrl( rRoot
, aUrl
, nScCol
, nScRow
, nScTab
);
417 // Label ranges ===============================================================
419 void XclImpLabelranges::ReadLabelranges( XclImpStream
& rStrm
)
421 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
422 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
424 ScDocument
& rDoc
= rRoot
.GetDoc();
425 SCTAB nScTab
= rRoot
.GetCurrScTab();
426 XclImpAddressConverter
& rAddrConv
= rRoot
.GetAddressConverter();
427 ScRangePairListRef xLabelRangesRef
;
428 const ScRange
* pScRange
= 0;
430 XclRangeList aRowXclRanges
, aColXclRanges
;
431 rStrm
>> aRowXclRanges
>> aColXclRanges
;
434 ScRangeList aRowScRanges
;
435 rAddrConv
.ConvertRangeList( aRowScRanges
, aRowXclRanges
, nScTab
, false );
436 xLabelRangesRef
= rDoc
.GetRowNameRangesRef();
437 for ( size_t i
= 0, nRanges
= aRowScRanges
.size(); i
< nRanges
; ++i
)
439 pScRange
= aRowScRanges
[ i
];
440 ScRange
aDataRange( *pScRange
);
441 if( aDataRange
.aEnd
.Col() < MAXCOL
)
443 aDataRange
.aStart
.SetCol( aDataRange
.aEnd
.Col() + 1 );
444 aDataRange
.aEnd
.SetCol( MAXCOL
);
446 else if( aDataRange
.aStart
.Col() > 0 )
448 aDataRange
.aEnd
.SetCol( aDataRange
.aStart
.Col() - 1 );
449 aDataRange
.aStart
.SetCol( 0 );
451 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
454 // column label ranges
455 ScRangeList aColScRanges
;
456 rAddrConv
.ConvertRangeList( aColScRanges
, aColXclRanges
, nScTab
, false );
457 xLabelRangesRef
= rDoc
.GetColNameRangesRef();
459 for ( size_t i
= 0, nRanges
= aColScRanges
.size(); i
< nRanges
; ++i
)
461 pScRange
= aColScRanges
[ i
];
462 ScRange
aDataRange( *pScRange
);
463 if( aDataRange
.aEnd
.Row() < MAXROW
)
465 aDataRange
.aStart
.SetRow( aDataRange
.aEnd
.Row() + 1 );
466 aDataRange
.aEnd
.SetRow( MAXROW
);
468 else if( aDataRange
.aStart
.Row() > 0 )
470 aDataRange
.aEnd
.SetRow( aDataRange
.aStart
.Row() - 1 );
471 aDataRange
.aStart
.SetRow( 0 );
473 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
477 // Conditional formatting =====================================================
479 XclImpCondFormat::XclImpCondFormat( const XclImpRoot
& rRoot
, sal_uInt32 nFormatIndex
) :
481 mnFormatIndex( nFormatIndex
),
487 XclImpCondFormat::~XclImpCondFormat()
491 void XclImpCondFormat::ReadCondfmt( XclImpStream
& rStrm
)
493 OSL_ENSURE( !mnCondCount
, "XclImpCondFormat::ReadCondfmt - already initialized" );
494 XclRangeList aXclRanges
;
495 rStrm
>> mnCondCount
;
498 GetAddressConverter().ConvertRangeList( maRanges
, aXclRanges
, GetCurrScTab(), true );
501 void XclImpCondFormat::ReadCF( XclImpStream
& rStrm
)
503 if( mnCondIndex
>= mnCondCount
)
505 OSL_FAIL( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
509 // entire conditional format outside of valid range?
510 if( maRanges
.empty() )
513 sal_uInt8
nType(0), nOperator(0);
514 sal_uInt16
nFmlaSize1(0), nFmlaSize2(0);
515 sal_uInt32
nFlags(0);
517 rStrm
>> nType
>> nOperator
>> nFmlaSize1
>> nFmlaSize2
>> nFlags
;
520 // *** mode and comparison operator ***
522 ScConditionMode eMode
= SC_COND_NONE
;
525 case EXC_CF_TYPE_CELL
:
529 case EXC_CF_CMP_BETWEEN
: eMode
= SC_COND_BETWEEN
; break;
530 case EXC_CF_CMP_NOT_BETWEEN
: eMode
= SC_COND_NOTBETWEEN
; break;
531 case EXC_CF_CMP_EQUAL
: eMode
= SC_COND_EQUAL
; break;
532 case EXC_CF_CMP_NOT_EQUAL
: eMode
= SC_COND_NOTEQUAL
; break;
533 case EXC_CF_CMP_GREATER
: eMode
= SC_COND_GREATER
; break;
534 case EXC_CF_CMP_LESS
: eMode
= SC_COND_LESS
; break;
535 case EXC_CF_CMP_GREATER_EQUAL
: eMode
= SC_COND_EQGREATER
; break;
536 case EXC_CF_CMP_LESS_EQUAL
: eMode
= SC_COND_EQLESS
; break;
538 OSL_TRACE( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator
);
543 case EXC_CF_TYPE_FMLA
:
544 eMode
= SC_COND_DIRECT
;
548 OSL_TRACE( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType
);
552 // *** create style sheet ***
554 String
aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex
, mnCondIndex
) );
555 SfxItemSet
& rStyleItemSet
= ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName
, true ).GetItemSet();
557 const XclImpPalette
& rPalette
= GetPalette();
559 // *** font block ***
561 if( ::get_flag( nFlags
, EXC_CF_BLOCK_FONT
) )
563 XclImpFont
aFont( GetRoot() );
564 aFont
.ReadCFFontBlock( rStrm
);
565 aFont
.FillToItemSet( rStyleItemSet
, EXC_FONTITEM_CELL
);
568 // *** border block ***
570 if( ::get_flag( nFlags
, EXC_CF_BLOCK_BORDER
) )
572 sal_uInt16
nLineStyle(0);
573 sal_uInt32
nLineColor(0);
574 rStrm
>> nLineStyle
>> nLineColor
;
577 XclImpCellBorder aBorder
;
578 aBorder
.FillFromCF8( nLineStyle
, nLineColor
, nFlags
);
579 aBorder
.FillToItemSet( rStyleItemSet
, rPalette
);
582 // *** pattern block ***
584 if( ::get_flag( nFlags
, EXC_CF_BLOCK_AREA
) )
586 sal_uInt16
nPattern(0), nColor(0);
587 rStrm
>> nPattern
>> nColor
;
589 XclImpCellArea aArea
;
590 aArea
.FillFromCF8( nPattern
, nColor
, nFlags
);
591 aArea
.FillToItemSet( rStyleItemSet
, rPalette
);
596 const ScAddress
& rPos
= maRanges
.front()->aStart
; // assured above that maRanges is not empty
597 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
599 SAL_WNODEPRECATED_DECLARATIONS_PUSH
600 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
601 SAL_WNODEPRECATED_DECLARATIONS_POP
604 const ScTokenArray
* pTokArr
= 0;
605 rFmlaConv
.Reset( rPos
);
606 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize1
, false, FT_CondFormat
);
607 // formula converter owns pTokArr -> create a copy of the token array
609 xTokArr1
.reset( pTokArr
->Clone() );
612 SAL_WNODEPRECATED_DECLARATIONS_PUSH
613 ::std::auto_ptr
< ScTokenArray
> pTokArr2
;
614 SAL_WNODEPRECATED_DECLARATIONS_POP
617 const ScTokenArray
* pTokArr
= 0;
618 rFmlaConv
.Reset( rPos
);
619 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize2
, false, FT_CondFormat
);
620 // formula converter owns pTokArr -> create a copy of the token array
622 pTokArr2
.reset( pTokArr
->Clone() );
625 // *** create the Calc conditional formatting ***
627 if( !mxScCondFmt
.get() )
630 mxScCondFmt
.reset( new ScConditionalFormat( nKey
, GetDocPtr() ) );
631 if(maRanges
.size() > 1)
632 maRanges
.Join(*maRanges
[0], true);
633 mxScCondFmt
->AddRange(maRanges
);
636 ScCondFormatEntry
* pEntry
= new ScCondFormatEntry( eMode
, xTokArr1
.get(), pTokArr2
.get(), GetDocPtr(), rPos
, aStyleName
);
637 mxScCondFmt
->AddEntry( pEntry
);
641 void XclImpCondFormat::Apply()
643 if( mxScCondFmt
.get() )
645 ScDocument
& rDoc
= GetDoc();
647 SCTAB nTab
= maRanges
.front()->aStart
.Tab();
648 sal_uLong nKey
= rDoc
.AddCondFormat( mxScCondFmt
->Clone(), nTab
);
650 rDoc
.AddCondFormatData( maRanges
, nTab
, nKey
);
654 // ----------------------------------------------------------------------------
656 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot
& rRoot
) :
661 void XclImpCondFormatManager::ReadCondfmt( XclImpStream
& rStrm
)
663 XclImpCondFormat
* pFmt
= new XclImpCondFormat( GetRoot(), maCondFmtList
.size() );
664 pFmt
->ReadCondfmt( rStrm
);
665 maCondFmtList
.push_back( pFmt
);
668 void XclImpCondFormatManager::ReadCF( XclImpStream
& rStrm
)
670 OSL_ENSURE( !maCondFmtList
.empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
671 if( !maCondFmtList
.empty() )
672 maCondFmtList
.back().ReadCF( rStrm
);
675 void XclImpCondFormatManager::Apply()
677 for( XclImpCondFmtList::iterator itFmt
= maCondFmtList
.begin(); itFmt
!= maCondFmtList
.end(); ++itFmt
)
679 maCondFmtList
.clear();
682 // Data Validation ============================================================
684 XclImpValidationManager::DVItem::DVItem( const ScRangeList
& rRanges
, const ScValidationData
& rValidData
) :
685 maRanges(rRanges
), maValidData(rValidData
) {}
687 XclImpValidationManager::XclImpValidationManager( const XclImpRoot
& rRoot
) :
692 void XclImpValidationManager::ReadDval( XclImpStream
& rStrm
)
694 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
695 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
697 sal_uInt32
nObjId(0);
700 if( nObjId
!= EXC_DVAL_NOOBJ
)
702 OSL_ENSURE( nObjId
<= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
703 rRoot
.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16
>( nObjId
) );
707 void XclImpValidationManager::ReadDV( XclImpStream
& rStrm
)
709 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
710 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
712 ScDocument
& rDoc
= rRoot
.GetDoc();
713 SCTAB nScTab
= rRoot
.GetCurrScTab();
714 ExcelToSc
& rFmlaConv
= rRoot
.GetOldFmlaConverter();
717 sal_uInt32
nFlags(0);
721 /* Empty strings are single NUL characters in Excel (string length is 1).
722 -> Do not let the stream replace them with '?' characters. */
723 rStrm
.SetNulSubstChar( '\0' );
724 String
aPromptTitle( rStrm
.ReadUniString() );
725 String
aErrorTitle( rStrm
.ReadUniString() );
726 String
aPromptMessage( rStrm
.ReadUniString() );
727 String
aErrorMessage( rStrm
.ReadUniString() );
728 rStrm
.SetNulSubstChar(); // back to default
731 if ( rStrm
.GetRecLeft() <= 8 )
732 // Not enough bytes left in the record. Bail out.
737 // string list is single tStr token with NUL separators -> replace them with LF
738 rStrm
.SetNulSubstChar( '\n' );
739 SAL_WNODEPRECATED_DECLARATIONS_PUSH
740 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
741 SAL_WNODEPRECATED_DECLARATIONS_POP
748 const ScTokenArray
* pTokArr
= 0;
750 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_CondFormat
);
751 // formula converter owns pTokArr -> create a copy of the token array
753 xTokArr1
.reset( pTokArr
->Clone() );
755 rStrm
.SetNulSubstChar(); // back to default
758 SAL_WNODEPRECATED_DECLARATIONS_PUSH
759 ::std::auto_ptr
< ScTokenArray
> xTokArr2
;
760 SAL_WNODEPRECATED_DECLARATIONS_POP
767 const ScTokenArray
* pTokArr
= 0;
769 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_CondFormat
);
770 // formula converter owns pTokArr -> create a copy of the token array
772 xTokArr2
.reset( pTokArr
->Clone() );
775 // read all cell ranges
776 XclRangeList aXclRanges
;
779 // convert to Calc range list
780 ScRangeList aScRanges
;
781 rRoot
.GetAddressConverter().ConvertRangeList( aScRanges
, aXclRanges
, nScTab
, true );
783 // only continue if there are valid ranges
784 if ( aScRanges
.empty() )
787 bool bIsValid
= true; // valid settings in flags field
789 ScValidationMode eValMode
= SC_VALID_ANY
;
790 switch( nFlags
& EXC_DV_MODE_MASK
)
792 case EXC_DV_MODE_ANY
: eValMode
= SC_VALID_ANY
; break;
793 case EXC_DV_MODE_WHOLE
: eValMode
= SC_VALID_WHOLE
; break;
794 case EXC_DV_MODE_DECIMAL
: eValMode
= SC_VALID_DECIMAL
; break;
795 case EXC_DV_MODE_LIST
: eValMode
= SC_VALID_LIST
; break;
796 case EXC_DV_MODE_DATE
: eValMode
= SC_VALID_DATE
; break;
797 case EXC_DV_MODE_TIME
: eValMode
= SC_VALID_TIME
; break;
798 case EXC_DV_MODE_TEXTLEN
: eValMode
= SC_VALID_TEXTLEN
; break;
799 case EXC_DV_MODE_CUSTOM
: eValMode
= SC_VALID_CUSTOM
; break;
800 default: bIsValid
= false;
802 rRoot
.GetTracer().TraceDVType(eValMode
== SC_VALID_CUSTOM
);
804 ScConditionMode eCondMode
= SC_COND_BETWEEN
;
805 switch( nFlags
& EXC_DV_COND_MASK
)
807 case EXC_DV_COND_BETWEEN
: eCondMode
= SC_COND_BETWEEN
; break;
808 case EXC_DV_COND_NOTBETWEEN
:eCondMode
= SC_COND_NOTBETWEEN
; break;
809 case EXC_DV_COND_EQUAL
: eCondMode
= SC_COND_EQUAL
; break;
810 case EXC_DV_COND_NOTEQUAL
: eCondMode
= SC_COND_NOTEQUAL
; break;
811 case EXC_DV_COND_GREATER
: eCondMode
= SC_COND_GREATER
; break;
812 case EXC_DV_COND_LESS
: eCondMode
= SC_COND_LESS
; break;
813 case EXC_DV_COND_EQGREATER
: eCondMode
= SC_COND_EQGREATER
; break;
814 case EXC_DV_COND_EQLESS
: eCondMode
= SC_COND_EQLESS
; break;
815 default: bIsValid
= false;
819 // No valid validation found. Bail out.
823 // first range for base address for relative references
824 const ScRange
& rScRange
= *aScRanges
.front(); // aScRanges is not empty
826 // process string list of a list validity (convert to list of string tokens)
827 if( xTokArr1
.get() && (eValMode
== SC_VALID_LIST
) && ::get_flag( nFlags
, EXC_DV_STRINGLIST
) )
828 XclTokenArrayHelper::ConvertStringToList( *xTokArr1
, '\n', true );
831 new DVItem(aScRanges
, ScValidationData(eValMode
, eCondMode
, xTokArr1
.get(), xTokArr2
.get(), &rDoc
, rScRange
.aStart
)));
832 DVItem
& rItem
= maDVItems
.back();
834 rItem
.maValidData
.SetIgnoreBlank( ::get_flag( nFlags
, EXC_DV_IGNOREBLANK
) );
835 rItem
.maValidData
.SetListType( ::get_flagvalue( nFlags
, EXC_DV_SUPPRESSDROPDOWN
, ValidListType::INVISIBLE
, ValidListType::UNSORTED
) );
837 // *** prompt box ***
838 if( aPromptTitle
.Len() || aPromptMessage
.Len() )
840 // set any text stored in the record
841 rItem
.maValidData
.SetInput( aPromptTitle
, aPromptMessage
);
842 if( !::get_flag( nFlags
, EXC_DV_SHOWPROMPT
) )
843 rItem
.maValidData
.ResetInput();
847 ScValidErrorStyle eErrStyle
= SC_VALERR_STOP
;
848 switch( nFlags
& EXC_DV_ERROR_MASK
)
850 case EXC_DV_ERROR_WARNING
: eErrStyle
= SC_VALERR_WARNING
; break;
851 case EXC_DV_ERROR_INFO
: eErrStyle
= SC_VALERR_INFO
; break;
853 // set texts and error style
854 rItem
.maValidData
.SetError( aErrorTitle
, aErrorMessage
, eErrStyle
);
855 if( !::get_flag( nFlags
, EXC_DV_SHOWERROR
) )
856 rItem
.maValidData
.ResetError();
859 void XclImpValidationManager::Apply()
861 ScDocument
& rDoc
= GetRoot().GetDoc();
862 DVItemList::iterator itr
= maDVItems
.begin(), itrEnd
= maDVItems
.end();
863 for (; itr
!= itrEnd
; ++itr
)
865 DVItem
& rItem
= *itr
;
867 sal_uLong nHandle
= rDoc
.AddValidationEntry( rItem
.maValidData
);
868 ScPatternAttr
aPattern( rDoc
.GetPool() );
869 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nHandle
) );
872 for ( size_t i
= 0, nRanges
= rItem
.maRanges
.size(); i
< nRanges
; ++i
)
874 const ScRange
* pScRange
= rItem
.maRanges
[ i
];
875 rDoc
.ApplyPatternAreaTab( pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
876 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(), pScRange
->aStart
.Tab(), aPattern
);
882 // Web queries ================================================================
884 XclImpWebQuery::XclImpWebQuery( const ScRange
& rDestRange
) :
885 maDestRange( rDestRange
),
886 meMode( xlWQUnknown
),
891 void XclImpWebQuery::ReadParamqry( XclImpStream
& rStrm
)
893 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
894 sal_uInt16 nType
= ::extract_value
< sal_uInt16
>( nFlags
, 0, 3 );
895 if( (nType
== EXC_PQRYTYPE_WEBQUERY
) && ::get_flag( nFlags
, EXC_PQRY_WEBQUERY
) )
897 if( ::get_flag( nFlags
, EXC_PQRY_TABLES
) )
899 meMode
= xlWQAllTables
;
900 maTables
= ScfTools::GetHTMLTablesName();
904 meMode
= xlWQDocument
;
905 maTables
= ScfTools::GetHTMLDocName();
910 void XclImpWebQuery::ReadWqstring( XclImpStream
& rStrm
)
912 maURL
= rStrm
.ReadUniString();
915 void XclImpWebQuery::ReadWqsettings( XclImpStream
& rStrm
)
918 sal_uInt16
nFlags(0);
923 if( ::get_flag( nFlags
, EXC_WQSETT_SPECTABLES
) && (meMode
== xlWQAllTables
) )
924 meMode
= xlWQSpecTables
;
927 void XclImpWebQuery::ReadWqtables( XclImpStream
& rStrm
)
929 if( meMode
== xlWQSpecTables
)
932 OUString
aTables( rStrm
.ReadUniString() );
934 const sal_Unicode cSep
= ';';
935 OUString
aQuotedPairs( "\"\"" );
936 xub_StrLen nTokenCnt
= ScStringUtil::GetQuotedTokenCount( aTables
, aQuotedPairs
, ',' );
938 sal_Int32 nStringIx
= 0;
939 for( xub_StrLen nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
941 OUString
aToken( ScStringUtil::GetQuotedToken( aTables
, 0, aQuotedPairs
, ',', nStringIx
) );
942 sal_Int32 nTabNum
= CharClass::isAsciiNumeric( aToken
) ? aToken
.toInt32() : 0;
944 maTables
= ScGlobal::addToken( maTables
, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32
>( nTabNum
) ), cSep
);
947 ScGlobal::EraseQuotes( aToken
, '"', false );
948 if( !aToken
.isEmpty() )
949 maTables
= ScGlobal::addToken( maTables
, ScfTools::GetNameFromHTMLName( aToken
), cSep
);
955 void XclImpWebQuery::Apply( ScDocument
& rDoc
, const String
& rFilterName
)
957 if( maURL
.Len() && (meMode
!= xlWQUnknown
) && rDoc
.GetDocumentShell() )
959 ScAreaLink
* pLink
= new ScAreaLink( rDoc
.GetDocumentShell(),
960 maURL
, rFilterName
, EMPTY_STRING
, maTables
, maDestRange
, mnRefresh
* 60UL );
961 rDoc
.GetLinkManager()->InsertFileLink( *pLink
, OBJECT_CLIENT_FILE
,
962 maURL
, &rFilterName
, &maTables
);
966 // ----------------------------------------------------------------------------
968 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot
& rRoot
) :
973 void XclImpWebQueryBuffer::ReadQsi( XclImpStream
& rStrm
)
975 if( GetBiff() == EXC_BIFF8
)
978 String
aXclName( rStrm
.ReadUniString() );
980 // #i64794# Excel replaces spaces with underscores
981 aXclName
.SearchAndReplaceAll( ' ', '_' );
983 // find the defined name used in Calc
984 if( const XclImpName
* pName
= GetNameManager().FindName( aXclName
, GetCurrScTab() ) )
986 if( const ScRangeData
* pRangeData
= pName
->GetScRangeData() )
989 if( pRangeData
->IsReference( aRange
) )
990 maWQList
.push_back( new XclImpWebQuery( aRange
) );
1000 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream
& rStrm
)
1002 if (!maWQList
.empty())
1003 maWQList
.back().ReadParamqry( rStrm
);
1006 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream
& rStrm
)
1008 if (!maWQList
.empty())
1009 maWQList
.back().ReadWqstring( rStrm
);
1012 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream
& rStrm
)
1014 if (!maWQList
.empty())
1015 maWQList
.back().ReadWqsettings( rStrm
);
1018 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream
& rStrm
)
1020 if (!maWQList
.empty())
1021 maWQList
.back().ReadWqtables( rStrm
);
1024 void XclImpWebQueryBuffer::Apply()
1026 ScDocument
& rDoc
= GetDoc();
1027 String
aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER
) );
1028 for( XclImpWebQueryList::iterator itQuery
= maWQList
.begin(); itQuery
!= maWQList
.end(); ++itQuery
)
1029 itQuery
->Apply( rDoc
, aFilterName
);
1032 // Decryption =================================================================
1036 XclImpDecrypterRef
lclReadFilepass5( XclImpStream
& rStrm
)
1038 XclImpDecrypterRef xDecr
;
1039 OSL_ENSURE( rStrm
.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1040 if( rStrm
.GetRecLeft() == 4 )
1042 sal_uInt16
nKey(0), nHash(0);
1043 rStrm
>> nKey
>> nHash
;
1044 xDecr
.reset( new XclImpBiff5Decrypter( nKey
, nHash
) );
1049 XclImpDecrypterRef
lclReadFilepass8_Standard( XclImpStream
& rStrm
)
1051 XclImpDecrypterRef xDecr
;
1052 OSL_ENSURE( rStrm
.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1053 if( rStrm
.GetRecLeft() == 48 )
1055 sal_uInt8 pnSalt
[ 16 ];
1056 sal_uInt8 pnVerifier
[ 16 ];
1057 sal_uInt8 pnVerifierHash
[ 16 ];
1058 rStrm
.Read( pnSalt
, 16 );
1059 rStrm
.Read( pnVerifier
, 16 );
1060 rStrm
.Read( pnVerifierHash
, 16 );
1061 xDecr
.reset( new XclImpBiff8Decrypter( pnSalt
, pnVerifier
, pnVerifierHash
) );
1066 XclImpDecrypterRef
lclReadFilepass8_Strong( XclImpStream
& /*rStrm*/ )
1069 return XclImpDecrypterRef();
1072 XclImpDecrypterRef
lclReadFilepass8( XclImpStream
& rStrm
)
1074 XclImpDecrypterRef xDecr
;
1076 sal_uInt16
nMode(0);
1080 case EXC_FILEPASS_BIFF5
:
1081 xDecr
= lclReadFilepass5( rStrm
);
1084 case EXC_FILEPASS_BIFF8
:
1087 sal_uInt16
nSubMode(0);
1091 case EXC_FILEPASS_BIFF8_STD
:
1092 xDecr
= lclReadFilepass8_Standard( rStrm
);
1094 case EXC_FILEPASS_BIFF8_STRONG
:
1095 xDecr
= lclReadFilepass8_Strong( rStrm
);
1098 OSL_FAIL( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1104 OSL_FAIL( "lclReadFilepass8 - unknown encryption mode" );
1112 // ----------------------------------------------------------------------------
1114 ErrCode
XclImpDecryptHelper::ReadFilepass( XclImpStream
& rStrm
)
1116 XclImpDecrypterRef xDecr
;
1117 rStrm
.DisableDecryption();
1119 // read the FILEPASS record and create a new decrypter object
1120 switch( rStrm
.GetRoot().GetBiff() )
1125 case EXC_BIFF5
: xDecr
= lclReadFilepass5( rStrm
); break;
1126 case EXC_BIFF8
: xDecr
= lclReadFilepass8( rStrm
); break;
1127 default: DBG_ERROR_BIFF();
1130 // set decrypter at import stream
1131 rStrm
.SetDecrypter( xDecr
);
1133 // request and verify a password (decrypter implements IDocPasswordVerifier)
1135 rStrm
.GetRoot().RequestEncryptionData( *xDecr
);
1137 // return error code (success, wrong password, etc.)
1138 return xDecr
? xDecr
->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT
;
1141 // Document protection ========================================================
1143 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot
& rRoot
) :
1144 XclImpRoot( rRoot
),
1146 mbDocProtect(false),
1151 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream
& rStrm
)
1153 mbDocProtect
= rStrm
.ReaduInt16() ? true : false;
1156 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream
& rStrm
)
1158 mbWinProtect
= rStrm
.ReaduInt16() ? true : false;
1161 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
)
1163 rStrm
.EnableDecryption();
1164 mnPassHash
= rStrm
.ReaduInt16();
1167 void XclImpDocProtectBuffer::Apply() const
1169 if (!mbDocProtect
&& !mbWinProtect
)
1170 // Excel requires either the structure or windows protection is set.
1171 // If neither is set then the document is not protected at all.
1174 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1175 auto_ptr
<ScDocProtection
> pProtect(new ScDocProtection
);
1176 SAL_WNODEPRECATED_DECLARATIONS_POP
1177 pProtect
->setProtected(true);
1181 // 16-bit password pash.
1182 Sequence
<sal_Int8
> aPass(2);
1183 aPass
[0] = (mnPassHash
>> 8) & 0xFF;
1184 aPass
[1] = mnPassHash
& 0xFF;
1185 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1188 // document protection options
1189 pProtect
->setOption(ScDocProtection::STRUCTURE
, mbDocProtect
);
1190 pProtect
->setOption(ScDocProtection::WINDOWS
, mbWinProtect
);
1192 GetDoc().SetDocProtection(pProtect
.get());
1195 // Sheet Protection ===========================================================
1197 XclImpSheetProtectBuffer::Sheet::Sheet() :
1199 mnPasswordHash(0x0000),
1204 // ----------------------------------------------------------------------------
1206 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet
& r
) :
1207 mbProtected(r
.mbProtected
),
1208 mnPasswordHash(r
.mnPasswordHash
),
1209 mnOptions(r
.mnOptions
)
1213 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot
& rRoot
) :
1218 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream
& rStrm
, SCTAB nTab
)
1220 if ( rStrm
.ReaduInt16() )
1222 Sheet
* pSheet
= GetSheetItem(nTab
);
1224 pSheet
->mbProtected
= true;
1228 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream
& rStrm
, SCTAB nTab
)
1232 // feature type can be either 2 or 4. If 2, this record stores flag for
1233 // enhanced protection, whereas if 4 it stores flag for smart tag.
1234 sal_uInt16
nFeatureType(0);
1235 rStrm
>> nFeatureType
;
1236 if (nFeatureType
!= 2)
1237 // We currently only support import of enhanced protection data.
1240 rStrm
.Ignore(1); // always 1
1242 // The flag size specifies the size of bytes that follows that stores
1243 // feature data. If -1 it depends on the feature type imported earlier.
1244 // For enhanced protection data, the size is always 4. For the most xls
1245 // documents out there this value is almost always -1.
1246 sal_Int32
nFlagSize(0);
1248 if (nFlagSize
!= -1)
1251 // There are actually 4 bytes to read, but the upper 2 bytes currently
1252 // don't store any bits.
1253 sal_uInt16
nOptions(0);
1256 Sheet
* pSheet
= GetSheetItem(nTab
);
1258 pSheet
->mnOptions
= nOptions
;
1261 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
, SCTAB nTab
)
1263 sal_uInt16
nHash(0);
1265 Sheet
* pSheet
= GetSheetItem(nTab
);
1267 pSheet
->mnPasswordHash
= nHash
;
1270 void XclImpSheetProtectBuffer::Apply() const
1272 for (ProtectedSheetMap::const_iterator itr
= maProtectedSheets
.begin(), itrEnd
= maProtectedSheets
.end();
1273 itr
!= itrEnd
; ++itr
)
1275 if (!itr
->second
.mbProtected
)
1276 // This sheet is (for whatever reason) not protected.
1279 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1280 auto_ptr
<ScTableProtection
> pProtect(new ScTableProtection
);
1281 SAL_WNODEPRECATED_DECLARATIONS_POP
1282 pProtect
->setProtected(true);
1284 // 16-bit hash password
1285 const sal_uInt16 nHash
= itr
->second
.mnPasswordHash
;
1288 Sequence
<sal_Int8
> aPass(2);
1289 aPass
[0] = (nHash
>> 8) & 0xFF;
1290 aPass
[1] = nHash
& 0xFF;
1291 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1294 // sheet protection options
1295 const sal_uInt16 nOptions
= itr
->second
.mnOptions
;
1296 pProtect
->setOption( ScTableProtection::OBJECTS
, (nOptions
& 0x0001) );
1297 pProtect
->setOption( ScTableProtection::SCENARIOS
, (nOptions
& 0x0002) );
1298 pProtect
->setOption( ScTableProtection::FORMAT_CELLS
, (nOptions
& 0x0004) );
1299 pProtect
->setOption( ScTableProtection::FORMAT_COLUMNS
, (nOptions
& 0x0008) );
1300 pProtect
->setOption( ScTableProtection::FORMAT_ROWS
, (nOptions
& 0x0010) );
1301 pProtect
->setOption( ScTableProtection::INSERT_COLUMNS
, (nOptions
& 0x0020) );
1302 pProtect
->setOption( ScTableProtection::INSERT_ROWS
, (nOptions
& 0x0040) );
1303 pProtect
->setOption( ScTableProtection::INSERT_HYPERLINKS
, (nOptions
& 0x0080) );
1304 pProtect
->setOption( ScTableProtection::DELETE_COLUMNS
, (nOptions
& 0x0100) );
1305 pProtect
->setOption( ScTableProtection::DELETE_ROWS
, (nOptions
& 0x0200) );
1306 pProtect
->setOption( ScTableProtection::SELECT_LOCKED_CELLS
, (nOptions
& 0x0400) );
1307 pProtect
->setOption( ScTableProtection::SORT
, (nOptions
& 0x0800) );
1308 pProtect
->setOption( ScTableProtection::AUTOFILTER
, (nOptions
& 0x1000) );
1309 pProtect
->setOption( ScTableProtection::PIVOT_TABLES
, (nOptions
& 0x2000) );
1310 pProtect
->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS
, (nOptions
& 0x4000) );
1312 // all done. now commit.
1313 GetDoc().SetTabProtection(itr
->first
, pProtect
.get());
1317 XclImpSheetProtectBuffer::Sheet
* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab
)
1319 ProtectedSheetMap::iterator itr
= maProtectedSheets
.find(nTab
);
1320 if (itr
== maProtectedSheets
.end())
1323 if ( !maProtectedSheets
.insert( ProtectedSheetMap::value_type(nTab
, Sheet()) ).second
)
1326 itr
= maProtectedSheets
.find(nTab
);
1329 return &itr
->second
;
1332 // ============================================================================
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */