ooo-build r14947 - in trunk: . patches/dev300



Author: kyoshida
Date: Mon Dec 29 16:42:06 2008
New Revision: 14947
URL: http://svn.gnome.org/viewvc/ooo-build?rev=14947&view=rev

Log:
2008-12-29  Kohei Yoshida  <kyoshida novell com>

	* patches/dev300/cws-scsheetprotection02-sc-m37.diff:
	* patches/dev300/cws-scsheetprotection02-sfx2-m37.diff:
	* patches/dev300/cws-scsheetprotection02-svx-m37.diff:
	* patches/dev300/cws-scsheetprotection02-sc.diff:
	* patches/dev300/cws-scsheetprotection02-sfx2.diff:
	* patches/dev300/cws-scsheetprotection02-svx.diff:
	* patches/dev300/apply: more dev300-m38 work.


Added:
   trunk/patches/dev300/cws-scsheetprotection02-sc-m37.diff   (props changed)
      - copied unchanged from r14946, /trunk/patches/dev300/cws-scsheetprotection02-sc.diff
   trunk/patches/dev300/cws-scsheetprotection02-sc.diff
   trunk/patches/dev300/cws-scsheetprotection02-sfx2-m37.diff   (props changed)
      - copied unchanged from r14946, /trunk/patches/dev300/cws-scsheetprotection02-sfx2.diff
   trunk/patches/dev300/cws-scsheetprotection02-sfx2.diff
   trunk/patches/dev300/cws-scsheetprotection02-svx-m37.diff   (props changed)
      - copied unchanged from r14946, /trunk/patches/dev300/cws-scsheetprotection02-svx.diff
   trunk/patches/dev300/cws-scsheetprotection02-svx.diff
Modified:
   trunk/ChangeLog
   trunk/patches/dev300/apply

Modified: trunk/patches/dev300/apply
==============================================================================
--- trunk/patches/dev300/apply	(original)
+++ trunk/patches/dev300/apply	Mon Dec 29 16:42:06 2008
@@ -823,13 +823,23 @@
 # able to paste it elsewhere (similar to Insert Cut Cells in Excel)
 sc-delete-rows-columns-remembers-content.diff, i#71921, jholesov
 
+[ CalcFixes < dev300-m38 ]
 # load, store and save the sheet protection options from and to an Excel file,
 # and use that information to constrain cell cursor movement when the sheet is
 # protected.  Also to support encryption on Excel file export.
-cws-scsheetprotection02-sc.diff,   i#60305, i#71468, i#84766, kohei
-cws-scsheetprotection02-sfx2.diff, i#60305, i#71468, i#84766, kohei
-cws-scsheetprotection02-svx.diff,  i#60305, i#71468, i#84766, kohei
+cws-scsheetprotection02-sc-m37.diff,   i#60305, i#71468, i#84766, kohei
+cws-scsheetprotection02-sfx2-m37.diff, i#60305, i#71468, i#84766, kohei
+cws-scsheetprotection02-svx-m37.diff,  i#60305, i#71468, i#84766, kohei
 
+[ CalcFixes >= dev300-m38 ]
+# load, store and save the sheet protection options from and to an Excel file,
+# and use that information to constrain cell cursor movement when the sheet is
+# protected.  Also to support encryption on Excel file export.
+cws-scsheetprotection02-sc.diff,   i#97515, kohei
+cws-scsheetprotection02-sfx2.diff, i#97515, kohei
+cws-scsheetprotection02-svx.diff,  i#97515, kohei
+
+[ CalcFixes ]
 # Ensure that Print Preview is consistent with Print output.
 sc-print-selected-sheets.diff, n#335684, i#45497, jonp
 

Added: trunk/patches/dev300/cws-scsheetprotection02-sc.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/cws-scsheetprotection02-sc.diff	Mon Dec 29 16:42:06 2008
@@ -0,0 +1,7325 @@
+diff --git sc/inc/document.hxx sc/inc/document.hxx
+index bc70a7a..596ca70 100644
+--- sc/inc/document.hxx
++++ sc/inc/document.hxx
+@@ -89,6 +89,7 @@ class ScDBData;
+ class ScDetOpData;
+ class ScDetOpList;
+ class ScDocOptions;
++class ScDocProtection;
+ class ScDocumentPool;
+ class ScDrawLayer;
+ class ScExtDocOptions;
+@@ -107,6 +108,7 @@ class ScRangeName;
+ class ScStyleSheet;
+ class ScStyleSheetPool;
+ class ScTable;
++class ScTableProtection;
+ class ScTokenArray;
+ class ScValidationData;
+ class ScValidationDataList;
+@@ -282,7 +284,7 @@ private:
+ 
+ 	ScFieldEditEngine*	pCacheFieldEditEngine;
+ 
+-	com::sun::star::uno::Sequence<sal_Int8>	aProtectPass;
++    ::std::auto_ptr<ScDocProtection> pDocProtection;
+ 
+     ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr;
+ 	String              aDocName;                       // opt: Dokumentname
+@@ -346,7 +348,6 @@ private:
+ 
+ 	ScLkUpdMode			eLinkMode;
+ 
+-	BOOL				bProtected;
+ 	BOOL				bAutoCalc;						// Automatisch Berechnen
+ 	BOOL				bAutoCalcShellDisabled;			// in/von/fuer ScDocShell disabled
+ 	// ob noch ForcedFormulas berechnet werden muessen,
+@@ -528,13 +529,14 @@ SC_DLLPUBLIC	ScDBCollection*	GetDBCollection() const;
+ 	inline SCTAB	GetTableCount() const { return nMaxTableNumber; }
+ 	SvNumberFormatterIndexTable* GetFormatExchangeList() const { return pFormatExchangeList; }
+ 
+-	void			SetDocProtection( BOOL bProtect, const com::sun::star::uno::Sequence <sal_Int8>& aPass );
+-	void			SetTabProtection( SCTAB nTab, BOOL bProtect, const com::sun::star::uno::Sequence <sal_Int8>& aPass );
++    ScDocProtection* GetDocProtection() const;
++    void            SetDocProtection(const ScDocProtection* pProtect);
+ 	BOOL			IsDocProtected() const;
+ 	BOOL			IsDocEditable() const;
+ 	BOOL			IsTabProtected( SCTAB nTab ) const;
+-	const com::sun::star::uno::Sequence <sal_Int8>&	GetDocPassword() const;
+-	const com::sun::star::uno::Sequence <sal_Int8>&	GetTabPassword( SCTAB nTab ) const;
++    SC_DLLPUBLIC    ScTableProtection* GetTabProtection( SCTAB nTab ) const;
++    void            SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect);
++    void            CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest);
+ 
+ 	void			LockTable(SCTAB nTab);
+ 	void			UnlockTable(SCTAB nTab);
+@@ -1464,7 +1466,8 @@ SC_DLLPUBLIC	SvNumberFormatter*	GetFormatTable() const;
+ 
+ 
+ private:
+-//UNUSED2008-05  void				SetAutoFilterFlags();
++    ScDocument(const ScDocument& r); // disabled with no definition
++
+ 	void				FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
+ 										SCCOL nX1, SCCOL nX2 ) const;
+ 
+diff --git sc/inc/sc.hrc sc/inc/sc.hrc
+index f4c942d..ea7ded5 100644
+--- sc/inc/sc.hrc
++++ sc/inc/sc.hrc
+@@ -1626,7 +1626,12 @@
+ #define RID_SCDLG_CONFLICTS             (SC_DIALOGS_START + 145)
+ #define RID_SCDLG_SHAREDOCUMENT         (SC_DIALOGS_START + 146)
+ 
+-#define SC_DIALOGS_END          (SC_DIALOGS_START + 150)
++#define RID_SCDLG_TABPROTECTION         (SC_DIALOGS_START + 147)
++#define RID_SCDLG_DOCPROTECTION         (SC_DIALOGS_START + 148)
++#define RID_SCDLG_RETYPEPASS            (SC_DIALOGS_START + 149)
++#define RID_SCDLG_RETYPEPASS_INPUT      (SC_DIALOGS_START + 150)
++
++#define SC_DIALOGS_END          (SC_DIALOGS_START + 151)
+ 
+ #ifndef STD_MASKCOLOR
+ #define STD_MASKCOLOR Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }
+diff --git sc/inc/scextopt.hxx sc/inc/scextopt.hxx
+index 772b77c..dac5afa 100644
+--- sc/inc/scextopt.hxx
++++ sc/inc/scextopt.hxx
+@@ -46,8 +46,6 @@ struct ScExtDocSettings
+     double              mfTabBarWidth;      /// Width of the tabbar, relative to frame window width (0.0 ... 1.0).
+     sal_uInt32          mnLinkCnt;          /// Recursive counter for loading external documents.
+     SCTAB               mnDisplTab;         /// Index of displayed sheet.
+-    bool                mbWinProtected;     /// true = Window properties are protected.
+-    bool                mbEncrypted;        /// true = Imported file was encrypted.
+ 
+     explicit            ScExtDocSettings();
+ };
+diff --git sc/inc/table.hxx sc/inc/table.hxx
+index ad1daf9..9f2ae22 100644
+--- sc/inc/table.hxx
++++ sc/inc/table.hxx
+@@ -39,6 +39,8 @@
+ #include "sortparam.hxx"
+ #include "compressedarray.hxx"
+ 
++#include <memory>
++
+ namespace utl {
+ 	class SearchParam;
+ 	class TextSearch;
+@@ -65,6 +67,7 @@ class ScRangeList;
+ class ScSortInfoArray;
+ class ScStyleSheet;
+ class ScTableLink;
++class ScTableProtection;
+ class ScUserListData;
+ class ScIndexMap;
+ struct RowInfo;
+@@ -102,8 +105,7 @@ private:
+ 	SCROW			nRepeatStartY;
+ 	SCROW			nRepeatEndY;
+ 
+-	BOOL			bProtected;
+-	com::sun::star::uno::Sequence<sal_Int8>	aProtectPass;
++    ::std::auto_ptr<ScTableProtection> pTabProtection;
+ 
+ 	USHORT*			pColWidth;
+ 	ScSummableCompressedArray< SCROW, USHORT>*  pRowHeight;
+@@ -218,10 +220,9 @@ public:
+ 	void			SetPageStyle( const String& rName );
+ 	void			PageStyleModified( const String& rNewName );
+ 
+-	BOOL			IsProtected() const						{ return bProtected; }
+-	const com::sun::star::uno::Sequence<sal_Int8>&	GetPassword() const						{ return aProtectPass; }
+-	void			SetProtection( BOOL bProtect, const com::sun::star::uno::Sequence<sal_Int8>& rPasswd )
+-										{ bProtected = bProtect; aProtectPass = rPasswd; }
++    BOOL            IsProtected() const;
++    void            SetProtection(const ScTableProtection* pProtect);
++    ScTableProtection* GetProtection();
+ 
+ 	Size			GetPageSize() const;
+ 	void			SetPageSize( const Size& rSize );
+diff --git sc/inc/tabprotection.hxx sc/inc/tabprotection.hxx
+new file mode 100644
+index 0000000..50b4798
+--- /dev/null
++++ sc/inc/tabprotection.hxx
+@@ -0,0 +1,180 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: tabprotection.hxx,v $
++ * $Revision: 1.1.4.6 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_TAB_PROTECTION_HXX
++#define SC_TAB_PROTECTION_HXX
++
++#include "sal/types.h"
++#include <com/sun/star/uno/Sequence.hxx>
++
++#include "global.hxx"
++#include <vector>
++#include <memory>
++
++#define ENABLE_SHEET_PROTECTION 1
++
++class ScDocument;
++class ScTableProtectionImpl;
++
++enum ScPasswordHash
++{
++    PASSHASH_OOO = 0,
++    PASSHASH_XL
++};
++
++class ScPassHashHelper
++{
++public:
++    /** Check for the compatibility of all password hashes.  If there is at
++        least one hash that needs to be regenerated, it returns true.  If all
++        hash values are compatible with the specified hash type, then it
++        returns false. */
++    static bool needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash);
++
++private:
++    ScPassHashHelper();
++    ~ScPassHashHelper();
++};
++
++// ============================================================================
++
++class SAL_NO_VTABLE ScPassHashProtectable
++{
++public:
++    virtual ~ScPassHashProtectable() = 0;
++
++    virtual bool isProtected() const = 0;
++    virtual bool isProtectedWithPass() const = 0;
++    virtual void setProtected(bool bProtected) = 0;
++
++    virtual bool isPasswordEmpty() const = 0;
++    virtual bool hasPasswordHash(ScPasswordHash eHash) const = 0;
++    virtual void setPassword(const String& aPassText) = 0;
++    virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const = 0;
++    virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, 
++                                 ScPasswordHash eHash = PASSHASH_OOO) = 0;
++    virtual bool verifyPassword(const String& aPassText) const = 0;
++};
++
++// ============================================================================
++
++class ScDocProtection : public ScPassHashProtectable
++{
++public:
++    enum Option
++    {
++        STRUCTURE = 0,
++        WINDOWS,
++        CONTENT,
++        NONE        // last item - used to resize the vector
++    };
++
++    explicit ScDocProtection();
++    explicit ScDocProtection(const ScDocProtection& r);
++    virtual ~ScDocProtection();
++
++    virtual bool isProtected() const;
++    virtual bool isProtectedWithPass() const;
++    virtual void setProtected(bool bProtected);
++            
++    virtual bool isPasswordEmpty() const;
++    virtual bool hasPasswordHash(ScPasswordHash eHash) const;
++    virtual void setPassword(const String& aPassText);
++    virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
++    virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, 
++                                 ScPasswordHash eHash = PASSHASH_OOO);
++    virtual bool verifyPassword(const String& aPassText) const;
++    
++    bool isOptionEnabled(Option eOption) const;
++    void setOption(Option eOption, bool bEnabled);
++
++private:
++    ::std::auto_ptr<ScTableProtectionImpl> mpImpl;
++};
++
++// ============================================================================
++
++/** sheet protection state container
++    
++    This class stores sheet's protection state: 1) whether the protection
++    is on, 2) password and/or password hash, and 3) any associated
++    protection options.  This class is also used as a protection state
++    container for the undo/redo stack, in which case the password, hash and
++    the options need to be preserved even when the protection flag is
++    off. */
++class ScTableProtection : public ScPassHashProtectable
++{
++public:
++    enum Option
++    {
++        AUTOFILTER = 0,
++        DELETE_COLUMNS,
++        DELETE_ROWS,
++        FORMAT_CELLS,
++        FORMAT_COLUMNS,
++        FORMAT_ROWS,
++        INSERT_COLUMNS,
++        INSERT_HYPERLINKS,
++        INSERT_ROWS,
++        OBJECTS,
++        PIVOT_TABLES,
++        SCENARIOS,
++        SELECT_LOCKED_CELLS,
++        SELECT_UNLOCKED_CELLS,
++        SHEET,
++        SORT,
++        NONE        // last item - used to resize the vector
++    };
++
++    explicit ScTableProtection();
++    explicit ScTableProtection(const ScTableProtection& r);
++    virtual ~ScTableProtection();
++
++    virtual bool isProtected() const;
++    virtual bool isProtectedWithPass() const;
++    virtual void setProtected(bool bProtected);
++            
++    virtual bool isPasswordEmpty() const;
++    virtual bool hasPasswordHash(ScPasswordHash eHash) const;
++    virtual void setPassword(const String& aPassText);
++    virtual ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
++    virtual void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, 
++                                 ScPasswordHash eHash = PASSHASH_OOO);
++    virtual bool verifyPassword(const String& aPassText) const;
++    
++    SC_DLLPUBLIC bool isOptionEnabled(Option eOption) const;
++    SC_DLLPUBLIC void setOption(Option eOption, bool bEnabled);
++
++private:
++    ::std::auto_ptr<ScTableProtectionImpl> mpImpl;
++};
++
++
++#endif
+diff --git sc/source/core/data/documen2.cxx sc/source/core/data/documen2.cxx
+index 9dc39d7..9db90f4 100644
+--- sc/source/core/data/documen2.cxx
++++ sc/source/core/data/documen2.cxx
+@@ -94,6 +94,7 @@
+ #include "recursionhelper.hxx"
+ #include "lookupcache.hxx"
+ #include "externalrefmgr.hxx"
++#include "tabprotection.hxx"
+ 
+ // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and
+ // dtor plus helpers are convenient.
+@@ -151,6 +152,7 @@ ScDocument::ScDocument( ScDocumentMode	eMode,
+ 		pChangeViewSettings( NULL ),
+ 		pScriptTypeData( NULL ),
+         pCacheFieldEditEngine( NULL ),
++        pDocProtection( NULL ),
+         pExternalRefMgr( NULL ),
+ 		pViewOptions( NULL ),
+ 		pDocOptions( NULL ),
+@@ -174,7 +176,6 @@ ScDocument::ScDocument( ScDocumentMode	eMode,
+ 		nHardRecalcState(0),
+ 		nVisibleTab( 0 ),
+ 		eLinkMode(LM_UNKNOWN),
+-		bProtected( FALSE ),
+ 		bAutoCalc( eMode == SCDOCMODE_DOCUMENT ),
+ 		bAutoCalcShellDisabled( FALSE ),
+ 		bForcedFormulaPending( FALSE ),
+diff --git sc/source/core/data/documen3.cxx sc/source/core/data/documen3.cxx
+index 14fce18..f21db61 100644
+--- sc/source/core/data/documen3.cxx
++++ sc/source/core/data/documen3.cxx
+@@ -79,6 +79,8 @@
+ #include "listenercalls.hxx"
+ #include "editutil.hxx"    // ScPostIt EditTextObject
+ #include "postit.hxx"
++#include "svtools/PasswordHelper.hxx"
++#include "tabprotection.hxx"
+ 
+ #include <memory>
+ 
+@@ -1672,28 +1674,28 @@ void ScDocument::SnapVisArea( Rectangle& rRect ) const
+         ScDrawLayer::MirrorRectRTL( rRect );        // back to real rectangle
+ }
+ 
+-void ScDocument::SetDocProtection( BOOL bProtect, const uno::Sequence<sal_Int8>& rPasswd )
++ScDocProtection* ScDocument::GetDocProtection() const
+ {
+-	bProtected = bProtect;
+-	aProtectPass = rPasswd;
++    return pDocProtection.get();
+ }
+ 
+-void ScDocument::SetTabProtection( SCTAB nTab, BOOL bProtect, const uno::Sequence<sal_Int8>& rPasswd )
++void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
+ {
+-	if (VALIDTAB(nTab))
+-		if (pTab[nTab])
+-			pTab[nTab]->SetProtection( bProtect, rPasswd );
++    if (pProtect)
++        pDocProtection.reset(new ScDocProtection(*pProtect));
++    else
++        pDocProtection.reset(NULL);
+ }
+ 
+ BOOL ScDocument::IsDocProtected() const
+ {
+-	return bProtected;
++    return pDocProtection.get() && pDocProtection->isProtected();
+ }
+ 
+ BOOL ScDocument::IsDocEditable() const
+ {
+     // import into read-only document is possible
+-    return !bProtected && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
++    return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
+ }
+ 
+ BOOL ScDocument::IsTabProtected( SCTAB nTab ) const
+@@ -1706,19 +1708,28 @@ BOOL ScDocument::IsTabProtected( SCTAB nTab ) const
+ 	return FALSE;
+ }
+ 
+-const uno::Sequence<sal_Int8>& ScDocument::GetDocPassword() const
++ScTableProtection* ScDocument::GetTabProtection( SCTAB nTab ) const
+ {
+-	return aProtectPass;
++    if (VALIDTAB(nTab) && pTab[nTab])
++        return pTab[nTab]->GetProtection();
++
++    return NULL;
+ }
+ 
+-const uno::Sequence<sal_Int8>& ScDocument::GetTabPassword( SCTAB nTab ) const
++void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
+ {
+-	if (VALIDTAB(nTab))
+-		if (pTab[nTab])
+-			return pTab[nTab]->GetPassword();
++    if (!ValidTab(nTab))
++        return;
+ 
+-	DBG_ERROR("Falsche Tabellennummer");
+-	return aProtectPass;
++    pTab[nTab]->SetProtection(pProtect);
++}
++
++void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
++{
++    if (!ValidTab(nTabSrc) || !ValidTab(nTabDest))
++        return;
++
++    pTab[nTabDest]->SetProtection( pTab[nTabSrc]->GetProtection() );
+ }
+ 
+ const ScDocOptions& ScDocument::GetDocOptions() const
+diff --git sc/source/core/data/document.cxx sc/source/core/data/document.cxx
+index 34cc8d7..d13323e 100644
+--- sc/source/core/data/document.cxx
++++ sc/source/core/data/document.cxx
+@@ -93,6 +93,7 @@
+ #include "bcaslot.hxx"
+ #include "postit.hxx"
+ #include "externalrefmgr.hxx"
++#include "tabprotection.hxx"
+ 
+ namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+ 
+@@ -3947,24 +3948,6 @@ BOOL ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
+ }
+ 
+ 
+-//UNUSED2008-05  void ScDocument::SetAutoFilterFlags()
+-//UNUSED2008-05  {
+-//UNUSED2008-05      USHORT nCount = pDBCollection->GetCount();
+-//UNUSED2008-05      for (USHORT i=0; i<nCount; i++)
+-//UNUSED2008-05      {
+-//UNUSED2008-05          ScDBData* pData = (*pDBCollection)[i];
+-//UNUSED2008-05          SCTAB nDBTab;
+-//UNUSED2008-05          SCCOL nDBStartCol;
+-//UNUSED2008-05          SCROW nDBStartRow;
+-//UNUSED2008-05          SCCOL nDBEndCol;
+-//UNUSED2008-05          SCROW nDBEndRow;
+-//UNUSED2008-05          pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
+-//UNUSED2008-05          pData->SetAutoFilter( HasAttrib( nDBStartCol,nDBStartRow,nDBTab,
+-//UNUSED2008-05                                  nDBEndCol,nDBStartRow,nDBTab, HASATTR_AUTOFILTER ) );
+-//UNUSED2008-05      }
+-//UNUSED2008-05  }
+-
+-
+ BOOL ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+ {
+ 	const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
+diff --git sc/source/core/data/makefile.mk sc/source/core/data/makefile.mk
+index bf3d3d0..3a608e0 100644
+--- sc/source/core/data/makefile.mk
++++ sc/source/core/data/makefile.mk
+@@ -108,6 +108,7 @@ SLOFILES =  \
+ 	$(SLO)$/table4.obj \
+ 	$(SLO)$/table5.obj \
+ 	$(SLO)$/table6.obj \
++	$(SLO)$/tabprotection.obj \
+ 	$(SLO)$/userdat.obj \
+ 	$(SLO)$/validat.obj \
+ 	$(SLO)$/postit.obj
+diff --git sc/source/core/data/table1.cxx sc/source/core/data/table1.cxx
+index 4b5069f..c831b0b 100644
+--- sc/source/core/data/table1.cxx
++++ sc/source/core/data/table1.cxx
+@@ -114,6 +114,7 @@
+ #include "progress.hxx"
+ #include "hints.hxx"		// fuer Paint-Broadcast
+ #include "prnsave.hxx"
++#include "tabprotection.hxx"
+ 
+ // STATIC DATA -----------------------------------------------------------
+ 
+@@ -132,7 +133,7 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
+ 	bPageSizeValid( FALSE ),
+ 	nRepeatStartX( SCCOL_REPEAT_NONE ),
+ 	nRepeatStartY( SCROW_REPEAT_NONE ),
+-	bProtected( FALSE ),
++    pTabProtection( NULL ),
+ 	pColWidth( NULL ),
+ 	pRowHeight( NULL ),
+ 	pColFlags( NULL ),
+diff --git sc/source/core/data/table2.cxx sc/source/core/data/table2.cxx
+index 66849b5..7202f1e 100644
+--- sc/source/core/data/table2.cxx
++++ sc/source/core/data/table2.cxx
+@@ -292,7 +292,7 @@ void ScTable::DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USH
+ 			// Zellschutz auf geschuetzter Tabelle nicht setzen
+ 			//
+ 
+-		if ( bProtected && (nDelFlag & IDF_ATTRIB) )
++		if ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
+ 		{
+ 			ScPatternAttr aPattern(pDocument->GetPool());
+ 			aPattern.GetItemSet().Put( ScProtectionAttr( FALSE ) );
+@@ -318,7 +318,7 @@ void ScTable::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
+ 		// Zellschutz auf geschuetzter Tabelle nicht setzen
+ 		//
+ 
+-	if ( bProtected && (nDelFlag & IDF_ATTRIB) )
++	if ( IsProtected() && (nDelFlag & IDF_ATTRIB) )
+ 	{
+ 		ScDocumentPool* pPool = pDocument->GetPool();
+ 		SfxItemSet aSet( *pPool, ATTR_PATTERN_START, ATTR_PATTERN_END );
+@@ -361,7 +361,7 @@ void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ 
+ 		//	ggf. Formeln durch Werte ersetzen
+ 
+-		if (bProtected)
++		if ( IsProtected() )
+ 			for (i = nCol1; i <= nCol2; i++)
+ 				pTable->aCol[i].RemoveProtected(nRow1, nRow2);
+ 	}
+@@ -406,7 +406,7 @@ void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ 				// Zellschutz auf geschuetzter Tabelle nicht setzen
+ 				//
+ 
+-			if ( bProtected && (nInsFlag & IDF_ATTRIB) )
++			if ( IsProtected() && (nInsFlag & IDF_ATTRIB) )
+ 			{
+ 				ScPatternAttr aPattern(pDocument->GetPool());
+ 				aPattern.GetItemSet().Put( ScProtectionAttr( FALSE ) );
+@@ -1436,7 +1436,7 @@ BOOL ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
+ 	BOOL bIsEditable = TRUE;
+ 	if ( nLockCount )
+ 		bIsEditable = FALSE;
+-    else if ( bProtected && !pDocument->IsScenario(nTab) )
++    else if ( IsProtected() && !pDocument->IsScenario(nTab) )
+     {
+         if((bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HASATTR_PROTECTED )) != FALSE)
+         {
+@@ -1503,7 +1503,7 @@ BOOL ScTable::IsSelectionEditable( const ScMarkData& rMark,
+ 	BOOL bIsEditable = TRUE;
+ 	if ( nLockCount )
+ 		bIsEditable = FALSE;
+-    else if ( bProtected && !pDocument->IsScenario(nTab))
++    else if ( IsProtected() && !pDocument->IsScenario(nTab) )
+     {
+         if((bIsEditable = !HasAttribSelection( rMark, HASATTR_PROTECTED )) != FALSE)
+         {
+diff --git sc/source/core/data/table5.cxx sc/source/core/data/table5.cxx
+index e557c56..2bd2fd1 100644
+--- sc/source/core/data/table5.cxx
++++ sc/source/core/data/table5.cxx
+@@ -51,8 +51,11 @@
+ #include "stlpool.hxx"
+ #include "stlsheet.hxx"
+ #include "brdcst.hxx"
++#include "tabprotection.hxx"
+ #include "globstr.hrc"
+ 
++using ::com::sun::star::uno::Sequence;
++
+ // STATIC DATA -----------------------------------------------------------
+ 
+ #define GET_SCALEVALUE(set,id) 	((const SfxUInt16Item&)(set.Get( id ))).GetValue()
+@@ -273,6 +276,24 @@ void ScTable::SetPageSize( const Size& rSize )
+ 		bPageSizeValid = FALSE;
+ }
+ 
++BOOL ScTable::IsProtected() const
++{
++    return pTabProtection.get() && pTabProtection->isProtected();
++}
++
++void ScTable::SetProtection(const ScTableProtection* pProtect)
++{
++    if (pProtect)
++        pTabProtection.reset(new ScTableProtection(*pProtect));
++    else
++        pTabProtection.reset(NULL);
++}
++
++ScTableProtection* ScTable::GetProtection()
++{
++    return pTabProtection.get();
++}
++
+ Size ScTable::GetPageSize() const
+ {
+ 	if ( bPageSizeValid )
+diff --git sc/source/core/data/tabprotection.cxx sc/source/core/data/tabprotection.cxx
+new file mode 100644
+index 0000000..d4f983b
+--- /dev/null
++++ sc/source/core/data/tabprotection.cxx
+@@ -0,0 +1,463 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: tabprotection.cxx,v $
++ * $Revision: 1.1.4.7 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++// INCLUDE ---------------------------------------------------------------
++
++#include "tabprotection.hxx"
++#include "tools/debug.hxx"
++#include "svtools/PasswordHelper.hxx"
++#include "document.hxx"
++
++#define DEBUG_TAB_PROTECTION 0
++
++using namespace ::com::sun::star;
++using ::com::sun::star::uno::Sequence;
++using ::rtl::OUString;
++
++// ============================================================================
++
++bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash)
++{
++    if (rDoc.IsDocProtected())
++    {
++        const ScDocProtection* p = rDoc.GetDocProtection();
++        if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
++            return true;
++    }
++
++    SCTAB nTabCount = rDoc.GetTableCount();
++    for (SCTAB i = 0; i < nTabCount; ++i)
++    {
++        const ScTableProtection* p = rDoc.GetTabProtection(i);
++        if (!p || !p->isProtected())
++            // Sheet not protected.  Skip it.
++            continue;
++
++        if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash))
++            return true;
++    }
++
++    return false;
++}
++
++// ============================================================================
++
++ScPassHashProtectable::~ScPassHashProtectable()
++{
++}
++
++// ============================================================================
++
++static sal_uInt16 lcl_getXLHashFromChar(const sal_Char* szPassword)
++{
++    sal_uInt16 cchPassword = strlen(szPassword);
++    sal_uInt16 wPasswordHash = 0;
++    if (!cchPassword)
++        return wPasswordHash;
++
++    const char* pch = &szPassword[cchPassword];
++    while (pch-- != szPassword)
++    {
++        wPasswordHash = ((wPasswordHash >> 14) & 0x01) | 
++                        ((wPasswordHash << 1) & 0x7fff);
++        wPasswordHash ^= *pch;
++    }
++
++    wPasswordHash = ((wPasswordHash >> 14) & 0x01) | 
++                    ((wPasswordHash << 1) & 0x7fff);
++
++    wPasswordHash ^= (0x8000 | ('N' << 8) | 'K');
++    wPasswordHash ^= cchPassword;
++
++    return wPasswordHash;
++}
++
++static Sequence<sal_Int8> lcl_getXLHash(const String& aPassText)
++{
++    const sal_Char* szBuf = OUStringToOString(OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr();
++    sal_uInt16 nHash = lcl_getXLHashFromChar(szBuf);
++    Sequence<sal_Int8> aHash(2);
++    aHash[0] = (nHash >> 8) & 0xFF;
++    aHash[1] = nHash & 0xFF;
++    return aHash;
++}
++
++class ScTableProtectionImpl
++{
++public:
++    static ::com::sun::star::uno::Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_OOO);
++
++    explicit ScTableProtectionImpl(SCSIZE nOptSize);
++    explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
++
++    bool isProtected() const;
++    bool isProtectedWithPass() const;
++    void setProtected(bool bProtected);
++
++    bool isPasswordEmpty() const;
++    bool hasPasswordHash(ScPasswordHash eHash) const;
++    void setPassword(const String& aPassText);
++    ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(ScPasswordHash eHash) const;
++    void setPasswordHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash = PASSHASH_OOO);
++    bool verifyPassword(const String& aPassText) const;
++    
++    bool isOptionEnabled(SCSIZE nOptId) const;
++    void setOption(SCSIZE nOptId, bool bEnabled);
++
++private:
++    String maPassText;
++    ::com::sun::star::uno::Sequence<sal_Int8>   maPassHash;
++    ::std::vector<bool> maOptions;
++    bool mbEmptyPass;
++    bool mbProtected;
++    ScPasswordHash meHash;
++};
++
++Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
++{
++    Sequence<sal_Int8> aHash;
++    switch (eHash)
++    {
++        case PASSHASH_XL:
++            aHash = lcl_getXLHash(aPassText);
++        break;
++        case PASSHASH_OOO:
++        default:            
++            SvPasswordHelper::GetHashPassword(aHash, aPassText);
++        break;
++    }
++    return aHash;
++}
++
++ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
++    maOptions(nOptSize),
++    mbEmptyPass(true),
++    mbProtected(false),
++    meHash(PASSHASH_OOO)
++{
++}
++
++ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
++    maPassText(r.maPassText),
++    maPassHash(r.maPassHash),
++    maOptions(r.maOptions),
++    mbEmptyPass(r.mbEmptyPass),
++    mbProtected(r.mbProtected),
++    meHash(r.meHash)
++{
++}
++
++bool ScTableProtectionImpl::isProtected() const
++{
++    return mbProtected;
++}
++
++bool ScTableProtectionImpl::isProtectedWithPass() const
++{
++    if (!mbProtected)
++        return false;
++
++    return maPassText.Len() || maPassHash.getLength();
++}
++
++void ScTableProtectionImpl::setProtected(bool bProtected)
++{
++    mbProtected = bProtected;
++    // We need to keep the old password even when the protection is off.  So, 
++    // don't erase the password data here.
++}
++
++void ScTableProtectionImpl::setPassword(const String& aPassText)
++{
++    // We can't hash it here because we don't know whether this document will
++    // get saved to Excel or ODF, depending on which we will need to use a
++    // different hashing algorithm.  One alternative is to hash it using all
++    // hash algorithms that we support, and store them all.
++
++    maPassText = aPassText;
++    mbEmptyPass = aPassText.Len() == 0;
++    if (mbEmptyPass)
++    {
++        maPassHash = Sequence<sal_Int8>();
++    }
++}
++
++bool ScTableProtectionImpl::isPasswordEmpty() const
++{
++    return mbEmptyPass;
++}
++
++bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash) const
++{
++    if (mbEmptyPass)
++        return true;
++
++    if (maPassText.Len())
++        return true;
++
++    if (meHash == eHash)
++        return true;
++
++    return false;
++}
++
++Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(ScPasswordHash eHash) const
++{
++    if (mbEmptyPass)
++        // Flaged as empty.
++        return Sequence<sal_Int8>();
++
++    if (maPassText.Len())
++        // Cleartext password exists.  Hash it.
++        return hashPassword(maPassText, eHash);
++
++    if (meHash == eHash)
++        // Stored hash exists.
++        return maPassHash;
++
++    // Failed to find a matching hash.
++    return Sequence<sal_Int8>();
++}
++
++void ScTableProtectionImpl::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
++{
++    sal_Int32 nLen = aPassword.getLength();
++    mbEmptyPass = nLen <= 0 ? true : false;
++    meHash = eHash;
++    maPassHash = aPassword;
++
++#if DEBUG_TAB_PROTECTION
++    for (sal_Int32 i = 0; i < nLen; ++i)
++        printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
++    printf("\n");
++#endif
++}
++
++bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
++{
++#if DEBUG_TAB_PROTECTION    
++    fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
++            OUStringToOString(rtl::OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
++#endif    
++
++    if (mbEmptyPass)
++        return aPassText.Len() == 0;
++
++    if (maPassText.Len())
++        // Clear text password exists, and this one takes precedence.
++        return aPassText.Equals(maPassText);
++
++    Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash);
++
++#if DEBUG_TAB_PROTECTION    
++    fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
++    for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
++        printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
++    printf("\n");
++#endif    
++
++    return aHash == maPassHash;
++}
++
++bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
++{
++    if ( maOptions.size() <= static_cast<size_t>(nOptId) )
++    {
++        DBG_ERROR("ScTableProtectionImpl::isOptionEnabled: wrong size");
++        return false;
++    }
++
++    return maOptions[nOptId];
++}
++
++void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
++{
++    if ( maOptions.size() <= static_cast<size_t>(nOptId) )
++    {
++        DBG_ERROR("ScTableProtectionImpl::setOption: wrong size");
++        return;
++    }
++
++    maOptions[nOptId] = bEnabled;
++}
++
++// ============================================================================
++
++ScDocProtection::ScDocProtection() :
++    mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
++{
++}
++
++ScDocProtection::ScDocProtection(const ScDocProtection& r) :
++    mpImpl(new ScTableProtectionImpl(*r.mpImpl.get()))
++{
++}
++
++ScDocProtection::~ScDocProtection()
++{
++}
++
++bool ScDocProtection::isProtected() const
++{
++    return mpImpl->isProtected();
++}
++
++bool ScDocProtection::isProtectedWithPass() const
++{
++    return mpImpl->isProtectedWithPass();
++}
++
++void ScDocProtection::setProtected(bool bProtected)
++{
++    mpImpl->setProtected(bProtected);
++
++    // Currently Calc doesn't support document protection options.  So, let's
++    // assume that when the document is protected, its structure is protected.
++    // We need to do this for Excel export.
++    mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
++}
++
++bool ScDocProtection::isPasswordEmpty() const
++{
++    return mpImpl->isPasswordEmpty();
++}
++
++bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash) const
++{
++    return mpImpl->hasPasswordHash(eHash);
++}
++
++void ScDocProtection::setPassword(const String& aPassText)
++{
++    mpImpl->setPassword(aPassText);
++}
++
++uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash) const
++{
++    return mpImpl->getPasswordHash(eHash);
++}
++
++void ScDocProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
++{
++    mpImpl->setPasswordHash(aPassword, eHash);
++}
++
++bool ScDocProtection::verifyPassword(const String& aPassText) const
++{
++    return mpImpl->verifyPassword(aPassText);
++}
++
++bool ScDocProtection::isOptionEnabled(Option eOption) const
++{
++    return mpImpl->isOptionEnabled(eOption);
++}
++
++void ScDocProtection::setOption(Option eOption, bool bEnabled)
++{
++    mpImpl->setOption(eOption, bEnabled);
++}
++
++// ============================================================================
++
++ScTableProtection::ScTableProtection() :
++    mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
++{
++    // Set default values for the options.
++    mpImpl->setOption(SELECT_LOCKED_CELLS,   true);
++    mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
++}
++
++ScTableProtection::ScTableProtection(const ScTableProtection& r) :
++    mpImpl(new ScTableProtectionImpl(*r.mpImpl.get()))
++{
++}
++
++ScTableProtection::~ScTableProtection()
++{
++}
++
++bool ScTableProtection::isProtected() const
++{
++    return mpImpl->isProtected();
++}
++
++bool ScTableProtection::isProtectedWithPass() const
++{
++    return mpImpl->isProtectedWithPass();
++}
++
++void ScTableProtection::setProtected(bool bProtected)
++{
++    mpImpl->setProtected(bProtected);
++}
++
++bool ScTableProtection::isPasswordEmpty() const
++{
++    return mpImpl->isPasswordEmpty();
++}
++
++bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash) const
++{
++    return mpImpl->hasPasswordHash(eHash);
++}
++
++void ScTableProtection::setPassword(const String& aPassText)
++{
++    mpImpl->setPassword(aPassText);
++}
++
++Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash) const
++{
++    return mpImpl->getPasswordHash(eHash);
++}
++
++void ScTableProtection::setPasswordHash(const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash)
++{
++    mpImpl->setPasswordHash(aPassword, eHash);
++}
++
++bool ScTableProtection::verifyPassword(const String& aPassText) const
++{
++    return mpImpl->verifyPassword(aPassText);
++}
++
++bool ScTableProtection::isOptionEnabled(Option eOption) const
++{
++    return mpImpl->isOptionEnabled(eOption);
++}
++
++void ScTableProtection::setOption(Option eOption, bool bEnabled)
++{
++    mpImpl->setOption(eOption, bEnabled);
++}
++
+diff --git sc/source/filter/excel/excdoc.cxx sc/source/filter/excel/excdoc.cxx
+index f6d7218..d991d0a 100644
+--- sc/source/filter/excel/excdoc.cxx
++++ sc/source/filter/excel/excdoc.cxx
+@@ -67,11 +67,11 @@
+ #include "convuno.hxx"
+ #include "patattr.hxx"
+ #include "docoptio.hxx"
++#include "tabprotection.hxx"
+ 
+ #include "excdoc.hxx"
+ #include "namebuff.hxx"
+ 
+-#include "xcl97dum.hxx"
+ #include "xcl97rec.hxx"
+ #include "xcl97esc.hxx"
+ #include "xetable.hxx"
+@@ -150,7 +150,16 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+ 		Add( new ExcDummy_00 );
+ 	else
+ 	{
+-		Add( new ExcDummy8_00a );
++        if ( IsDocumentEncrypted() )
++            Add( new XclExpFilePass(GetRoot()) );
++
++        Add( new XclExpInterfaceHdr );
++        Add( new XclExpMMS );
++        Add( new XclExpInterfaceEnd );
++        Add( new XclExpWriteAccess );
++        Add( new XclExpCodePage );
++        Add( new XclExpDSF );
++        Add( new XclExpExcel9File );
+ 		rR.pTabId = new XclExpChTrTabId( Max( nExcTabCount, nCodenames ) );
+ 		Add( rR.pTabId );
+         if( HasVbaStorage() )
+@@ -160,7 +169,8 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+             if( rCodeName.Len() )
+                 Add( new XclCodename( rCodeName ) );
+ 		}
+-		Add( new ExcDummy8_00b );
++
++        Add( new XclExpFnGroupCount );
+ 	}
+ 
+ 	// erst Namen- und Tabellen-Eintraege aufbauen
+@@ -180,15 +190,31 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+         aRecList.AppendRecord( CreateRecord( EXC_ID_NAME ) );
+     }
+ 
+-    aRecList.AppendNewRecord( new XclExpWindowProtection( GetExtDocOptions().GetDocSettings().mbWinProtected ) );
+-    aRecList.AppendNewRecord( new XclExpDocProtection( rDoc.IsDocProtected() ) );
+-    aRecList.AppendNewRecord( new XclExpBoolRecord( EXC_ID_PASSWORD, false ) );
++    // document protection options
++    const ScDocProtection* pProtect = GetDoc().GetDocProtection();
++    if (pProtect && pProtect->isProtected())
++    {
++        Add( new XclExpWindowProtection(pProtect->isOptionEnabled(ScDocProtection::WINDOWS)) );
++        Add( new XclExpProtection(pProtect->isOptionEnabled(ScDocProtection::STRUCTURE)) );
++#if ENABLE_SHEET_PROTECTION
++        Add( new XclExpPassHash(pProtect->getPasswordHash(PASSHASH_XL)) );
++#endif
++    }
+ 
+     if( GetBiff() == EXC_BIFF8 )
+-        Add( new ExcDummy8_040 );
++    {
++        Add( new XclExpProt4Rev );
++        Add( new XclExpProt4RevPass );
++    }
+ 
+     aRecList.AppendNewRecord( new XclExpWindow1( GetRoot() ) );
+ 
++    if ( GetBiff() == EXC_BIFF8 )
++    {
++        Add( new XclExpBoolRecord(0x0040, false) ); // BACKUP
++        Add( new XclExpBoolRecord(0x008D, false) ); // HIDEOBJ
++    }
++
+     if( GetBiff() <= EXC_BIFF5 )
+     {
+ 		Add( new ExcDummy_040 );
+@@ -197,9 +223,11 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+     }
+     else
+     {
++        // BIFF8
+         Add( new Exc1904( rDoc ) );
+         Add( new XclExpBoolRecord( 0x000E, !rDoc.GetDocOptions().IsCalcAsShown() ) );
+-        Add( new ExcDummy8_041 );
++        Add( new XclExpBoolRecord(0x01B7, false) ); // REFRESHALL
++        Add( new XclExpBoolRecord(0x00DA, false) ); // BOOKBOOL
+     }
+ 
+     // Formatting: FONT, FORMAT, XF, STYLE, PALETTE
+@@ -258,10 +286,14 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+         aRecList.AppendRecord( CreateRecord( EXC_ID_EXTERNSHEET ) );
+         aRecList.AppendRecord( CreateRecord( EXC_ID_NAME ) );
+ 
++        Add( new XclExpRecalcId );
++
+ 		// MSODRAWINGGROUP per-document data
+ 		Add( new XclMsodrawinggroup( rR, ESCHER_DggContainer ) );
+         // Shared string table: SST, EXTSST
+         aRecList.AppendRecord( CreateRecord( EXC_ID_SST ) );
++
++        Add( new XclExpBookExt );
+ 	}
+ 
+ 	Add( new ExcEof );
+@@ -303,7 +335,7 @@ void ExcTable::FillAsTable( size_t nCodeNameIdx )
+         Add( new XclRefmode( rDoc ) );
+         Add( new XclIteration( rDoc ) );
+         Add( new XclDelta( rDoc ) );
+-        Add( new ExcDummy8_02 );
++        Add( new XclExpBoolRecord(0x005F, true) ); // SAVERECALC
+     }
+ 
+     // GUTS (count & size of outline icons)
+@@ -320,8 +352,16 @@ void ExcTable::FillAsTable( size_t nCodeNameIdx )
+     // page settings (SETUP and various other records)
+     aRecList.AppendRecord( xPageSett );
+ 
+-    if( rDoc.IsTabProtected( mnScTab ) )
+-		Add( new XclProtection() );
++    const ScTableProtection* pTabProtect = rDoc.GetTabProtection(mnScTab);
++    if (pTabProtect && pTabProtect->isProtected())
++    {
++        Add( new XclExpProtection(true) );
++        Add( new XclExpBoolRecord(0x00DD, pTabProtect->isOptionEnabled(ScTableProtection::SCENARIOS)) );
++        Add( new XclExpBoolRecord(0x0063, pTabProtect->isOptionEnabled(ScTableProtection::OBJECTS)) );
++#if ENABLE_SHEET_PROTECTION
++        Add( new XclExpPassHash(pTabProtect->getPasswordHash(PASSHASH_XL)) );
++#endif
++    }
+ 
+     // local link table: EXTERNCOUNT, EXTERNSHEET
+     if( eBiff <= EXC_BIFF5 )
+@@ -367,6 +407,9 @@ void ExcTable::FillAsTable( size_t nCodeNameIdx )
+ 
+     if( eBiff == EXC_BIFF8 )
+ 	{
++        // sheet protection options
++        Add( new XclExpSheetProtectOptions( GetRoot(), mnScTab ) );
++
+ 		// web queries
+         Add( new XclExpWebQueryBuffer( GetRoot() ) );
+ 
+diff --git sc/source/filter/excel/excimp8.cxx sc/source/filter/excel/excimp8.cxx
+index 3b8913c..6b0860c 100644
+--- sc/source/filter/excel/excimp8.cxx
++++ sc/source/filter/excel/excimp8.cxx
+@@ -160,12 +160,6 @@ void ImportExcel8::Iteration( void )
+ }
+ 
+ 
+-void ImportExcel8:: WinProtection( void )
+-{
+-    if( aIn.ReaduInt16() != 0 )
+-        GetExtDocOptions().GetDocSettings().mbWinProtected = true;
+-}
+-
+ void ImportExcel8::Boundsheet( void )
+ {
+ 	UINT8			nLen;
+@@ -249,6 +243,11 @@ void ImportExcel8::Codename( BOOL bWorkbookGlobals )
+ 	}
+ }
+ 
++void ImportExcel8::SheetProtection( void )
++{
++    GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
++}
++
+ bool lcl_hasVBAEnabled()
+ {
+ 	uno::Reference< beans::XPropertySet > xProps( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY);
+@@ -295,6 +294,8 @@ void ImportExcel8::PostDocLoad( void )
+         pExcRoot->pAutoFilterBuffer->Apply();
+ 
+     GetWebQueryBuffer().Apply();    //! test if extant
++    GetSheetProtectBuffer().Apply();
++    GetDocProtectBuffer().Apply();
+ 
+ 	ImportExcel::PostDocLoad();
+ 
+diff --git sc/source/filter/excel/excrecds.cxx sc/source/filter/excel/excrecds.cxx
+index 16c04f1..81b97f0 100644
+--- sc/source/filter/excel/excrecds.cxx
++++ sc/source/filter/excel/excrecds.cxx
+@@ -99,6 +99,7 @@
+ #include "xcl97rec.hxx"
+ 
+ 
++using ::com::sun::star::uno::Sequence;
+ 
+ //--------------------------------------------------------- class ExcDummy_00 -
+ const BYTE		ExcDummy_00::pMyData[] = {
+@@ -418,7 +419,9 @@ ExcBundlesheetBase::ExcBundlesheetBase() :
+ void ExcBundlesheetBase::UpdateStreamPos( XclExpStream& rStrm )
+ {
+     rStrm.SetSvStreamPos( nOwnPos );
++    rStrm.DisableEncryption();
+ 	rStrm << static_cast<sal_uInt32>(nStrPos);
++    rStrm.EnableEncryption();
+ }
+ 
+ 
+@@ -494,19 +497,41 @@ XclExpWsbool::XclExpWsbool( bool bFitToPages ) :
+ // XclExpWindowProtection ===============================================================
+ 
+ XclExpWindowProtection::XclExpWindowProtection(bool bValue) :
+-	XclExpBoolRecord(EXC_ID_WINDOWPROTECT,bValue)
++	XclExpBoolRecord(EXC_ID_WINDOWPROTECT, bValue)
+ {
+ }
+ 
+ // XclExpDocProtection ===============================================================
+ 
+-XclExpDocProtection::XclExpDocProtection(bool bValue) :
+-	XclExpBoolRecord(EXC_ID_PROTECT,bValue)
++XclExpProtection::XclExpProtection(bool bValue) :
++	XclExpBoolRecord(EXC_ID_PROTECT, bValue)
+ {
+ }
+ 
+ // ============================================================================
+ 
++XclExpPassHash::XclExpPassHash(const Sequence<sal_Int8>& aHash) :
++    XclExpRecord(EXC_ID_PASSWORD, 2),
++    mnHash(0x0000)
++{
++    if (aHash.getLength() >= 2)
++    {
++        mnHash  = ((aHash[0] << 8) & 0xFFFF);
++        mnHash |= (aHash[1] & 0xFF);
++    }
++}
++
++XclExpPassHash::~XclExpPassHash()
++{
++}
++
++void XclExpPassHash::WriteBody(XclExpStream& rStrm)
++{
++    rStrm << mnHash;
++}
++
++// ============================================================================
++
+ XclExpFiltermode::XclExpFiltermode() :
+     XclExpEmptyRecord( EXC_ID_FILTERMODE )
+ {
+diff --git sc/source/filter/excel/impop.cxx sc/source/filter/excel/impop.cxx
+index 2a56ecc..b329b81 100644
+--- sc/source/filter/excel/impop.cxx
++++ sc/source/filter/excel/impop.cxx
+@@ -84,6 +84,7 @@
+ #include "xiview.hxx"
+ #include "xilink.hxx"
+ #include "xiescher.hxx"
++#include "xicontent.hxx"
+ 
+ #include "excimp8.hxx"
+ #include "excform.hxx"
+@@ -418,14 +419,12 @@ void ImportExcel::Eof( void )
+ }
+ 
+ 
+-BOOL ImportExcel::Password( void )
++void ImportExcel::SheetPassword( void )
+ {
+-	// POST: return = TRUE, wenn Password <> 0
+-	UINT16 nPasswd;
++    if (GetRoot().GetBiff() != EXC_BIFF8)
++        return;
+ 
+-	aIn >> nPasswd;
+-
+-	return nPasswd != 0x0000;
++    GetRoot().GetSheetProtectBuffer().ReadPasswordHash( aIn, GetCurrScTab() );
+ }
+ 
+ 
+@@ -439,6 +438,15 @@ void ImportExcel::Externsheet( void )
+ }
+ 
+ 
++void ImportExcel:: WinProtection( void )
++{
++    if (GetRoot().GetBiff() != EXC_BIFF8)
++        return;
++
++    GetRoot().GetDocProtectBuffer().ReadWinProtect( aIn );
++}
++
++
+ void ImportExcel::Columndefault( void )
+ {// Default Cell Attributes
+ 	UINT16	nColMic, nColMac;
+@@ -570,27 +578,33 @@ void ImportExcel::Defrowheight2( void )
+ }
+ 
+ 
+-void ImportExcel::Protect( void )
++void ImportExcel::SheetProtect( void )
+ {
+-    if( aIn.ReaduInt16() )
+-    {
+-        uno::Sequence<sal_Int8> aEmptyPass;
+-        GetDoc().SetTabProtection( GetCurrScTab(), TRUE, aEmptyPass );
+-    }
++    if (GetRoot().GetBiff() != EXC_BIFF8)
++        return;
++
++    GetRoot().GetSheetProtectBuffer().ReadProtect( aIn, GetCurrScTab() );
+ }
+ 
+ void ImportExcel::DocProtect( void )
+ {
+-    if( aIn.ReaduInt16() )
+-    {
+-        uno::Sequence<sal_Int8> aEmptyPass;
+-        GetDoc().SetDocProtection( TRUE, aEmptyPass );
+-    }
++    if (GetRoot().GetBiff() != EXC_BIFF8)
++        return;
++
++    GetRoot().GetDocProtectBuffer().ReadDocProtect( aIn );
+ }
+ 
++void ImportExcel::DocPasssword( void )
++{
++    if (GetRoot().GetBiff() != EXC_BIFF8)
++        return;
++
++    GetRoot().GetDocProtectBuffer().ReadPasswordHash( aIn );
++}
+ 
+ void ImportExcel::Codepage( void )
+ {
++    maStrm.EnableDecryption();
+     SetCodePage( maStrm.ReaduInt16() );
+ }
+ 
+diff --git sc/source/filter/excel/read.cxx sc/source/filter/excel/read.cxx
+index f92fc84..0d0088f 100644
+--- sc/source/filter/excel/read.cxx
++++ sc/source/filter/excel/read.cxx
+@@ -363,7 +363,7 @@ FltError ImportExcel::Read( void )
+                         Eof();
+ 						eAkt = Z_Ende;
+ 						break;
+-					case 0x12:  Protect(); break;       // SHEET PROTECTION
++					case 0x12:  SheetProtect(); break;       // SHEET PROTECTION
+                     case 0x14:
+                     case 0x15:  rPageSett.ReadHeaderFooter( maStrm );   break;
+ 					case 0x17:	Externsheet(); break;	// EXTERNSHEET	[ 2345]
+@@ -478,7 +478,7 @@ FltError ImportExcel::Read( void )
+                         Eof();
+                         eAkt = Z_Biff4E;
+                     break;
+-					case 0x12:  Protect(); break;       // SHEET PROTECTION
++					case 0x12:  SheetProtect(); break;       // SHEET PROTECTION
+                     case 0x14:
+                     case 0x15:  rPageSett.ReadHeaderFooter( maStrm );   break;
+                     case 0x1A:
+@@ -605,7 +605,7 @@ FltError ImportExcel::Read( void )
+                             eAkt = Z_Biff5T;
+                             aIn.SeekGlobalPosition(); // und zurueck an alte Position
+                             break;
+-                        case 0x12:  Protect(); break;       // SHEET PROTECTION
++                        case 0x12:  SheetProtect(); break;       // SHEET PROTECTION
+                         case 0x1A:
+                         case 0x1B:  rPageSett.ReadPageBreaks( maStrm );     break;
+                         case 0x1D:  rTabViewSett.ReadSelection( maStrm );   break;
+@@ -904,6 +904,7 @@ FltError ImportExcel8::Read( void )
+                         }
+ 						break;
+ 					case 0x12:	DocProtect(); break;	// PROTECT		[    5678]
++                    case 0x13:  DocPasssword(); break;
+ 					case 0x19:  WinProtection(); break;
+ 					case 0x2F:							// FILEPASS		[ 2345   ]
+                         eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+@@ -1048,7 +1049,8 @@ FltError ImportExcel8::Read( void )
+                         eAkt = EXC_STATE_SHEET;
+                         aIn.SeekGlobalPosition();         // und zurueck an alte Position
+                         break;
+-                    case 0x12:  Protect(); break;
++                    case 0x12:  SheetProtect(); break;
++                    case 0x13:  SheetPassword(); break;
+                     case 0x42:  Codepage(); break;      // CODEPAGE     [ 2345   ]
+                     case 0x55:  DefColWidth(); break;
+                     case 0x7D:  Colinfo(); break;       // COLINFO      [  345   ]
+@@ -1064,6 +1066,7 @@ FltError ImportExcel8::Read( void )
+                     case 0x0221: Array34(); break;      // ARRAY        [  34    ]
+                     case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[  345   ]
+                     case 0x04BC: Shrfmla(); break;      // SHRFMLA      [    5   ]
++                    case 0x0867: SheetProtection(); break; // SHEETPROTECTION
+                 }
+             }
+             break;
+diff --git sc/source/filter/excel/xeroot.cxx sc/source/filter/excel/xeroot.cxx
+index aa0e713..0c32b52 100644
+--- sc/source/filter/excel/xeroot.cxx
++++ sc/source/filter/excel/xeroot.cxx
+@@ -32,7 +32,11 @@
+ #include "precompiled_sc.hxx"
+ #include "xeroot.hxx"
+ #include <sfx2/docfile.hxx>
++#include <sfx2/sfxsids.hrc>
+ #include <svtools/saveopt.hxx>
++#include <svtools/itemset.hxx>
++#include <svtools/stritem.hxx>
++#include <svtools/eitem.hxx>
+ #include "xltracer.hxx"
+ #include "xehelper.hxx"
+ #include "xeformula.hxx"
+@@ -42,8 +46,10 @@
+ #include "xecontent.hxx"
+ #include "xepivot.hxx"
+ 
+-// for filter manager
+-#include "excrecds.hxx"
++#include "excrecds.hxx"  // for filter manager
++#include "tabprotection.hxx"
++#include "document.hxx"
++#include "scextopt.hxx"
+ 
+ // Global data ================================================================
+ 
+@@ -221,6 +227,40 @@ XclExpRecordRef XclExpRoot::CreateRecord( sal_uInt16 nRecId ) const
+     return xRec;
+ }
+ 
++bool XclExpRoot::IsDocumentEncrypted() const
++{
++    // We need to encrypt the content when the document structure is protected.
++    const ScDocProtection* pDocProt = GetDoc().GetDocProtection();
++    if (pDocProt && pDocProt->isProtected() && pDocProt->isOptionEnabled(ScDocProtection::STRUCTURE))
++        return true;
++
++    if (GetPassword().Len() > 0)
++        // Password is entered directly into the save dialog.
++        return true;
++
++    return false;
++}
++
++const String XclExpRoot::GetPassword() const
++{
++    SfxItemSet* pSet = GetMedium().GetItemSet();
++    if (!pSet)
++        return String();
++
++    const SfxPoolItem* pItem = NULL;
++    if (SFX_ITEM_SET == pSet->GetItemState(SID_PASSWORD, sal_True, &pItem))
++    {
++        const SfxStringItem* pStrItem = dynamic_cast<const SfxStringItem*>(pItem);
++        if (pStrItem)
++        {
++            // Password from the save dialog.
++            return pStrItem->GetValue();
++        }
++    }
++
++    return String();
++}
++
+ XclExpRootData::XclExpLinkMgrRef XclExpRoot::GetLocalLinkMgrRef() const
+ {
+     return IsInGlobals() ? mrExpData.mxGlobLinkMgr : mrExpData.mxLocLinkMgr;
+diff --git sc/source/filter/excel/xestream.cxx sc/source/filter/excel/xestream.cxx
+index 98a1da9..3eeb724 100644
+--- sc/source/filter/excel/xestream.cxx
++++ sc/source/filter/excel/xestream.cxx
+@@ -34,6 +34,9 @@
+ #include "xlstring.hxx"
+ #include "xeroot.hxx"
+ 
++#define DEBUG_XL_ENCRYPTION 0
++
++using ::std::vector;
+ 
+ // ============================================================================
+ 
+@@ -63,16 +66,19 @@ XclExpStream::~XclExpStream()
+ void XclExpStream::StartRecord( sal_uInt16 nRecId, sal_Size nRecSize )
+ {
+     DBG_ASSERT( !mbInRec, "XclExpStream::StartRecord - another record still open" );
++    DisableEncryption();
+     mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
+     mnPredictSize = nRecSize;
+     mbInRec = true;
+     InitRecord( nRecId );
+     SetSliceSize( 0 );
++    EnableEncryption();
+ }
+ 
+ void XclExpStream::EndRecord()
+ {
+     DBG_ASSERT( mbInRec, "XclExpStream::EndRecord - no record open" );
++    DisableEncryption();
+     UpdateRecSize();
+     mrStrm.Seek( STREAM_SEEK_TO_END );
+     mbInRec = false;
+@@ -84,6 +90,86 @@ void XclExpStream::SetSliceSize( sal_uInt16 nSize )
+     mnSliceSize = 0;
+ }
+ 
++XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
++{
++    PrepareWrite( 1 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
++{
++    PrepareWrite( 1 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
++{
++    PrepareWrite( 2 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
++{
++    PrepareWrite( 2 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
++{
++    PrepareWrite( 4 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
++{
++    PrepareWrite( 4 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, nValue);
++    else
++        mrStrm << nValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( float fValue )
++{
++    PrepareWrite( 4 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, fValue);
++    else
++        mrStrm << fValue;
++    return *this;
++}
++
++XclExpStream& XclExpStream::operator<<( double fValue )
++{
++    PrepareWrite( 8 );
++    if (mbUseEncrypter && HasValidEncrypter())
++        mxEncrypter->Encrypt(mrStrm, fValue);
++    else
++        mrStrm << fValue;
++    return *this;
++}
++
+ sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
+ {
+     sal_Size nRet = 0;
+@@ -98,9 +184,21 @@ sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
+             while( bValid && (nBytesLeft > 0) )
+             {
+                 sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
+-                sal_Size nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
++                sal_Size nWriteRet = nWriteLen;
++                if (mbUseEncrypter && HasValidEncrypter())
++                {
++                    DBG_ASSERT(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
++                    vector<sal_uInt8> aBytes(nWriteLen);
++                    memcpy(&aBytes[0], pBuffer, nWriteLen);
++                    mxEncrypter->EncryptBytes(mrStrm, aBytes);
++                    // TODO: How do I check if all the bytes have been successfully written ?
++                }
++                else
++                {
++                    nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
+                 bValid = (nWriteLen == nWriteRet);
+                 DBG_ASSERT( bValid, "XclExpStream::Write - stream write error" );
++                }
+                 pBuffer += nWriteRet;
+                 nRet += nWriteRet;
+                 nBytesLeft -= nWriteRet;
+@@ -236,6 +334,26 @@ void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
+     Write( &rBuffer[ 0 ], rBuffer.size() );
+ }
+ 
++void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter )
++{
++    mxEncrypter = xEncrypter;
++}
++
++bool XclExpStream::HasValidEncrypter() const
++{
++    return mxEncrypter.is() && mxEncrypter->IsValid();
++}
++
++void XclExpStream::EnableEncryption( bool bEnable )
++{
++    mbUseEncrypter = bEnable && HasValidEncrypter();
++}
++
++void XclExpStream::DisableEncryption()
++{
++    EnableEncryption(false);
++}
++
+ sal_Size XclExpStream::SetSvStreamPos( sal_Size nPos )
+ {
+     DBG_ASSERT( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
+@@ -327,3 +445,187 @@ void XclExpStream::WriteRawZeroBytes( sal_Size nBytes )
+ 
+ // ============================================================================
+ 
++XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot, const sal_uInt8 nDocId[16],
++                                            const sal_uInt8 nSalt[16] ) :
++    mrRoot(rRoot),
++    mnOldPos(STREAM_SEEK_TO_END),
++    mbValid(false)
++{
++    String aPass = rRoot.GetPassword();
++    if (aPass.Len() == 0)
++        // Empty password.  Get the default biff8 password.
++        aPass = XclCryptoHelper::GetBiff8WbProtPassword();
++    Init(aPass, nDocId, nSalt);
++}
++
++XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
++{
++}
++
++bool XclExpBiff8Encrypter::IsValid() const
++{
++    return mbValid;
++}
++
++void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 nSaltDigest[16] ) const
++{
++    memcpy(nSaltDigest, mnSaltDigest, 16);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
++{
++    vector<sal_uInt8> aByte(1);
++    aByte[0] = nData;
++    EncryptBytes(rStrm, aByte);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
++{
++    ::std::vector<sal_uInt8> pnBytes(2);
++    pnBytes[0] = nData & 0xFF;
++    pnBytes[1] = (nData >> 8) & 0xFF;
++    EncryptBytes(rStrm, pnBytes);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
++{
++    ::std::vector<sal_uInt8> pnBytes(4);
++    pnBytes[0] = nData & 0xFF;
++    pnBytes[1] = (nData >>  8) & 0xFF;
++    pnBytes[2] = (nData >> 16) & 0xFF;
++    pnBytes[3] = (nData >> 24) & 0xFF;
++    EncryptBytes(rStrm, pnBytes);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
++{
++    ::std::vector<sal_uInt8> pnBytes(4);
++    memcpy(&pnBytes[0], &fValue, 4);
++    EncryptBytes(rStrm, pnBytes);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
++{
++    ::std::vector<sal_uInt8> pnBytes(8);
++    memcpy(&pnBytes[0], &fValue, 8);
++    EncryptBytes(rStrm, pnBytes);
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
++{
++    Encrypt(rStrm, static_cast<sal_uInt8>(nData));
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
++{
++    Encrypt(rStrm, static_cast<sal_uInt16>(nData));
++}
++
++void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
++{
++    Encrypt(rStrm, static_cast<sal_uInt32>(nData));
++}
++
++void XclExpBiff8Encrypter::Init( const String& aPass, const sal_uInt8 nDocId[16],
++                                 const sal_uInt8 nSalt[16] )
++{
++    memset(mnSaltDigest, 0, sizeof(mnSaltDigest));
++
++    xub_StrLen nLen = aPass.Len();
++    bool bValid = (0 < nLen) && (nLen < 16);
++    if ( bValid )
++    {
++        // transform String to sal_uInt16 array
++        memset(mnPassw, 0, sizeof(mnPassw));
++        for (xub_StrLen nChar = 0; nChar < nLen; ++nChar)
++            mnPassw[nChar] = static_cast<sal_uInt16>(aPass.GetChar(nChar));
++
++        // copy document ID
++        memcpy(mnDocId, nDocId, sizeof(mnDocId));
++
++        // init codec
++        maCodec.InitKey(mnPassw, mnDocId);
++
++        // generate salt hash.
++        ::svx::MSCodec_Std97 aCodec;
++        aCodec.InitKey(mnPassw, mnDocId);
++        aCodec.CreateSaltDigest(nSalt, mnSaltDigest);
++
++        // verify to make sure it's in good shape.
++        bValid = maCodec.VerifyKey(nSalt, mnSaltDigest);
++    }
++
++    mbValid = bValid;
++}
++
++sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos ) const
++{
++    return static_cast<sal_uInt32>(nStrmPos / EXC_ENCR_BLOCKSIZE);
++}
++
++sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos ) const
++{
++    return static_cast<sal_uInt16>(nStrmPos % EXC_ENCR_BLOCKSIZE);
++}
++
++void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
++{
++    sal_Size nStrmPos = rStrm.Tell();
++    sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
++    sal_uInt16 nBlockPos = GetBlockPos(nStrmPos);
++
++#if DEBUG_XL_ENCRYPTION
++    fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld  offset in block = %d  block pos = %ld\n",
++            nStrmPos, nBlockOffset, nBlockPos);
++#endif
++
++    sal_uInt16 nSize = aBytes.size();
++    if (nSize == 0)
++        return;
++
++#if DEBUG_XL_ENCRYPTION    
++    fprintf(stdout, "RAW: ");
++    for (sal_uInt16 i = 0; i < nSize; ++i)
++        fprintf(stdout, "%2.2X ", aBytes[i]);
++    fprintf(stdout, "\n");
++#endif    
++
++    if (mnOldPos != nStrmPos)
++    {
++        sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
++        sal_uInt16 nOldBlockPos = GetBlockPos(mnOldPos);
++
++        if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
++        {
++            maCodec.InitCipher(nBlockPos);
++            nOldOffset = 0;
++        }
++
++        if (nBlockOffset > nOldOffset)
++            maCodec.Skip(nBlockOffset - nOldOffset);
++    }
++
++    sal_uInt16 nBytesLeft = nSize;
++    sal_uInt16 nPos = 0;
++    while (nBytesLeft > 0)
++    {
++        sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
++        sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
++
++        bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
++        DBG_ASSERT(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
++
++        sal_Size nRet = rStrm.Write(&aBytes[nPos], nEncBytes);
++        DBG_ASSERT(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
++
++        nStrmPos = rStrm.Tell();
++        nBlockOffset = GetOffsetInBlock(nStrmPos);
++        nBlockPos = GetBlockPos(nStrmPos);
++        if (nBlockOffset == 0)
++            maCodec.InitCipher(nBlockPos);
++
++        nBytesLeft -= nEncBytes;
++        nPos += nEncBytes;
++    }
++    mnOldPos = nStrmPos;
++}
+diff --git sc/source/filter/excel/xicontent.cxx sc/source/filter/excel/xicontent.cxx
+index 2e9d0d5..abc5d02 100644
+--- sc/source/filter/excel/xicontent.cxx
++++ sc/source/filter/excel/xicontent.cxx
+@@ -41,6 +41,7 @@
+ #include "scitems.hxx"
+ #include <svx/eeitem.hxx>
+ #include <svtools/intitem.hxx>
++#include <svtools/stritem.hxx>
+ #include <svx/flditem.hxx>
+ #include <svx/fhgtitem.hxx>
+ #include <svx/wghtitem.hxx>
+@@ -67,6 +68,12 @@
+ #include "xiname.hxx"
+ 
+ #include "excform.hxx"
++#include "tabprotection.hxx"
++
++#include <memory>
++
++using ::com::sun::star::uno::Sequence;
++using ::std::auto_ptr;
+ 
+ // Shared string table ========================================================
+ 
+@@ -1091,11 +1098,186 @@ ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
+     };
+     // set decrypter at import stream
+     rStrm.SetDecrypter( xDecr );
+-    // remember encryption for export
+-    rStrm.GetRoot().GetExtDocOptions().GetDocSettings().mbEncrypted = true;
++
++    // Store the document password for export.
++    SfxItemSet* pSet = rStrm.GetRoot().GetDocShell()->GetMedium()->GetItemSet();
++    if (pSet)
++    {
++        String aPass = xDecr->GetPassword();
++        pSet->Put( SfxStringItem(SID_PASSWORD, aPass) );
++    }
+ 
+     return xDecr.is() ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
+ }
+ 
++// Document protection ========================================================
++
++XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
++    XclImpRoot( rRoot ),
++    mnPassHash(0x0000),
++    mbDocProtect(false),
++    mbWinProtect(false)
++{
++}
++
++void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
++{
++    mbDocProtect = rStrm.ReaduInt16() ? true : false;
++}
++
++void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
++{
++    mbWinProtect = rStrm.ReaduInt16() ? true : false;
++}
++
++void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
++{
++    rStrm.EnableDecryption();
++    mnPassHash = rStrm.ReaduInt16();
++}
++
++void XclImpDocProtectBuffer::Apply() const
++{
++    if (!mbDocProtect && !mbWinProtect)
++        // Excel requires either the structure or windows protection is set.
++        // If neither is set then the document is not protected at all.
++        return;
++
++    auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
++    pProtect->setProtected(true);
++
++#if ENABLE_SHEET_PROTECTION
++    if (mnPassHash)
++    {
++        // 16-bit password pash.
++        Sequence<sal_Int8> aPass(2);
++        aPass[0] = (mnPassHash >> 8) & 0xFF;
++        aPass[1] = mnPassHash & 0xFF;
++        pProtect->setPasswordHash(aPass, PASSHASH_XL);
++    }
++#endif
++
++    // document protection options
++    pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
++    pProtect->setOption(ScDocProtection::WINDOWS,   mbWinProtect);
++
++    GetDoc().SetDocProtection(pProtect.get());
++}
++
++// Sheet Protection ===========================================================
++
++XclImpSheetProtectBuffer::Sheet::Sheet() :
++    mbProtected(false),
++    mnPasswordHash(0x0000),
++    mnOptions(0x4400)
++{
++}
++
++// ----------------------------------------------------------------------------
++
++XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
++    mbProtected(r.mbProtected),
++    mnPasswordHash(r.mnPasswordHash),
++    mnOptions(r.mnOptions)
++{
++}
++
++XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
++    XclImpRoot( rRoot )
++{
++}
++
++void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
++{
++    if ( rStrm.ReaduInt16() )
++    {
++        Sheet* pSheet = GetSheetItem(nTab);
++        if (pSheet)
++            pSheet->mbProtected = true;
++    }
++}
++
++void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
++{
++    rStrm.Ignore(19);
++    sal_uInt16 nOptions;
++    rStrm >> nOptions;
++
++    Sheet* pSheet = GetSheetItem(nTab);
++    if (pSheet)
++        pSheet->mnOptions = nOptions;
++}
++
++void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
++{
++    sal_uInt16 nHash;
++    rStrm >> nHash;
++    Sheet* pSheet = GetSheetItem(nTab);
++    if (pSheet)
++        pSheet->mnPasswordHash = nHash;
++}
++
++void XclImpSheetProtectBuffer::Apply() const
++{
++    for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
++         itr != itrEnd; ++itr)
++    {
++        if (!itr->second.mbProtected)
++            // This sheet is (for whatever reason) not protected.
++            continue;
++
++        auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
++        pProtect->setProtected(true);
++
++#if ENABLE_SHEET_PROTECTION
++        // 16-bit hash password
++        const sal_uInt16 nHash = itr->second.mnPasswordHash;
++        if (nHash)
++        {
++            Sequence<sal_Int8> aPass(2);
++            aPass[0] = (nHash >> 8) & 0xFF;
++            aPass[1] = nHash & 0xFF;
++            pProtect->setPasswordHash(aPass, PASSHASH_XL);
++        }
++#endif
++
++        // sheet protection options
++        const sal_uInt16 nOptions = itr->second.mnOptions;
++        pProtect->setOption( ScTableProtection::OBJECTS,               (nOptions & 0x0001) );
++        pProtect->setOption( ScTableProtection::SCENARIOS,             (nOptions & 0x0002) );
++        pProtect->setOption( ScTableProtection::FORMAT_CELLS,          (nOptions & 0x0004) );
++        pProtect->setOption( ScTableProtection::FORMAT_COLUMNS,        (nOptions & 0x0008) );
++        pProtect->setOption( ScTableProtection::FORMAT_ROWS,           (nOptions & 0x0010) );
++        pProtect->setOption( ScTableProtection::INSERT_COLUMNS,        (nOptions & 0x0020) );
++        pProtect->setOption( ScTableProtection::INSERT_ROWS,           (nOptions & 0x0040) );
++        pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS,     (nOptions & 0x0080) );
++        pProtect->setOption( ScTableProtection::DELETE_COLUMNS,        (nOptions & 0x0100) );
++        pProtect->setOption( ScTableProtection::DELETE_ROWS,           (nOptions & 0x0200) );
++        pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS,   (nOptions & 0x0400) );
++        pProtect->setOption( ScTableProtection::SORT,                  (nOptions & 0x0800) );
++        pProtect->setOption( ScTableProtection::AUTOFILTER,            (nOptions & 0x1000) );
++        pProtect->setOption( ScTableProtection::PIVOT_TABLES,          (nOptions & 0x2000) );
++        pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
++
++        // all done.  now commit.
++        GetDoc().SetTabProtection(itr->first, pProtect.get());
++    }
++}
++
++XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
++{
++    ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
++    if (itr == maProtectedSheets.end())
++    {
++        // new sheet
++        if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
++            return NULL;
++
++        itr = maProtectedSheets.find(nTab);
++    }
++
++    return &itr->second;
++}
++
+ // ============================================================================
+ 
+diff --git sc/source/filter/excel/xilink.cxx sc/source/filter/excel/xilink.cxx
+index 502316c..02c1357 100644
+--- sc/source/filter/excel/xilink.cxx
++++ sc/source/filter/excel/xilink.cxx
+@@ -263,6 +263,7 @@ void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
+     DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
+     if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+     {
++        rStrm.EnableDecryption();
+         sal_Size nReadCount = rStrm.GetRecLeft() / 2;
+         DBG_ASSERT( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
+         maTabIdVec.clear();
+diff --git sc/source/filter/excel/xiroot.cxx sc/source/filter/excel/xiroot.cxx
+index d5d1119..55ba4bd 100644
+--- sc/source/filter/excel/xiroot.cxx
++++ sc/source/filter/excel/xiroot.cxx
+@@ -52,6 +52,7 @@
+ XclImpRootData::XclImpRootData( XclBiff eBiff, SfxMedium& rMedium,
+         SotStorageRef xRootStrg, ScDocument& rDoc, rtl_TextEncoding eTextEnc ) :
+     XclRootData( eBiff, rMedium, xRootStrg, rDoc, eTextEnc, false ),
++    mbPassQueried( false ),
+     mbHasCodePage( false )
+ {
+ }
+@@ -86,6 +87,8 @@ XclImpRoot::XclImpRoot( XclImpRootData& rImpRootData ) :
+         GetOldRoot().pAutoFilterBuffer = new XclImpAutoFilterBuffer;
+         mrImpData.mxWebQueryBfr.reset( new XclImpWebQueryBuffer( GetRoot() ) );
+         mrImpData.mxPTableMgr.reset( new XclImpPivotTableManager( GetRoot() ) );
++        mrImpData.mxTabProtect.reset( new XclImpSheetProtectBuffer( GetRoot() ) );
++        mrImpData.mxDocProtect.reset( new XclImpDocProtectBuffer( GetRoot() ) );
+     }
+ 
+     mrImpData.mxPageSett.reset( new XclImpPageSettings( GetRoot() ) );
+@@ -232,6 +235,18 @@ XclImpPivotTableManager& XclImpRoot::GetPivotTableManager() const
+     return *mrImpData.mxPTableMgr;
+ }
+ 
++XclImpSheetProtectBuffer& XclImpRoot::GetSheetProtectBuffer() const
++{
++    DBG_ASSERT( mrImpData.mxTabProtect.is(), "XclImpRoot::GetSheetProtectBuffer - invalid call, wrong BIFF" );
++    return *mrImpData.mxTabProtect;
++}
++
++XclImpDocProtectBuffer& XclImpRoot::GetDocProtectBuffer() const
++{
++    DBG_ASSERT( mrImpData.mxDocProtect.is(), "XclImpRoot::GetDocProtectBuffer - invalid call, wrong BIFF" );
++    return *mrImpData.mxDocProtect;
++}
++
+ XclImpPageSettings& XclImpRoot::GetPageSettings() const
+ {
+     return *mrImpData.mxPageSett;
+@@ -255,5 +270,16 @@ String XclImpRoot::GetScAddInName( const String& rXclName ) const
+     return rXclName;
+ }
+ 
++const String& XclImpRoot::QueryPassword() const
++{
++    if( !mrImpData.mbPassQueried )
++    {
++        mrImpData.maPassw = ScfApiHelper::QueryPasswordForMedium( GetMedium() );
++        // set to true, even if dialog has been cancelled (never ask twice)
++        mrImpData.mbPassQueried = true;
++    }
++    return mrImpData.maPassw;
++}
++
+ // ============================================================================
+ 
+diff --git sc/source/filter/excel/xistream.cxx sc/source/filter/excel/xistream.cxx
+index b7f0d38..e7780c0 100644
+--- sc/source/filter/excel/xistream.cxx
++++ sc/source/filter/excel/xistream.cxx
+@@ -36,6 +36,8 @@
+ #include "xlstring.hxx"
+ #include "xiroot.hxx"
+ 
++#include <vector>
++
+ // ============================================================================
+ // Decryption
+ // ============================================================================
+@@ -97,11 +99,21 @@ sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nByte
+     return nRet;
+ }
+ 
++const String XclImpDecrypter::GetPassword() const
++{
++    return maPass;
++}
++
+ void XclImpDecrypter::SetHasValidPassword( bool bValid )
+ {
+     mnError = bValid ? ERRCODE_NONE : EXC_ENCR_ERROR_WRONG_PASS;
+ }
+ 
++void XclImpDecrypter::SetPassword( const String& rPass )
++{
++    maPass = rPass;
++}
++
+ // ----------------------------------------------------------------------------
+ 
+ XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpRoot& rRoot, sal_uInt16 nKey, sal_uInt16 nHash )
+@@ -157,6 +169,9 @@ void XclImpBiff5Decrypter::Init( const ByteString& rPass, sal_uInt16 nKey, sal_u
+         // init codec
+         maCodec.InitKey( mpnPassw );
+         bValid = maCodec.VerifyKey( nKey, nHash );
++
++        String aUniPass( rPass, RTL_TEXTENCODING_MS_1252 );
++        SetPassword( aUniPass );
+     }
+ 
+     SetHasValidPassword( bValid );
+@@ -255,6 +270,8 @@ void XclImpBiff8Decrypter::Init(
+         // init codec
+         maCodec.InitKey( mpnPassw, mpnDocId );
+         bValid = maCodec.VerifyKey( pnSaltData, pnSaltHash );
++
++        SetPassword(rPass);
+     }
+ 
+     SetHasValidPassword( bValid );
+diff --git sc/source/filter/excel/xlroot.cxx sc/source/filter/excel/xlroot.cxx
+index e4980d8..6d8357f 100644
+--- sc/source/filter/excel/xlroot.cxx
++++ sc/source/filter/excel/xlroot.cxx
+@@ -91,8 +91,7 @@ XclRootData::XclRootData( XclBiff eBiff, SfxMedium& rMedium,
+     mxRD( new RootData ),//!
+     mnCharWidth( 110 ),
+     mnScTab( 0 ),
+-    mbExport( bExport ),
+-    mbHasPassw( false )
++    mbExport( bExport )
+ {
+     // default script type, e.g. for empty cells
+     switch( ScGlobal::GetDefaultScriptType() )
+@@ -198,17 +197,6 @@ void XclRoot::SetCharWidth( const XclFontData& rFontData )
+     }
+ }
+ 
+-const String& XclRoot::QueryPassword() const
+-{
+-    if( !mrData.mbHasPassw )
+-    {
+-        mrData.maPassw = ScfApiHelper::QueryPasswordForMedium( GetMedium() );
+-        // set to true, even if dialog has been cancelled (never ask twice)
+-        mrData.mbHasPassw = true;
+-    }
+-    return mrData.maPassw;
+-}
+-
+ bool XclRoot::HasVbaStorage() const
+ {
+     SotStorageRef xRootStrg = GetRootStorage();
+diff --git sc/source/filter/inc/excimp8.hxx sc/source/filter/inc/excimp8.hxx
+index 8ea39ad..ed8df6c 100644
+--- sc/source/filter/inc/excimp8.hxx
++++ sc/source/filter/inc/excimp8.hxx
+@@ -61,7 +61,6 @@ class ImportExcel8 : public ImportExcel
+         void                    Precision( void );              // 0x0E
+ 		void					Delta( void );					// 0x10
+ 		void					Iteration( void );				// 0x11
+-		void					WinProtection(	void );         // 0x19
+ 		void					Boundsheet( void );				// 0x85
+ 		void					FilterMode( void );				// 0x9B
+ 		void					AutoFilterInfo( void );			// 0x9D
+@@ -73,6 +72,7 @@ class ImportExcel8 : public ImportExcel
+ 
+ 		void					Hlink( void );					// 0x01B8
+ 		void					Codename( BOOL bWBGlobals );	// 0x01BA
++        void                    SheetProtection( void );        // 0x0867
+ 
+         virtual void            EndSheet( void );
+ 		virtual void			PostDocLoad( void );
+diff --git sc/source/filter/inc/excrecds.hxx sc/source/filter/inc/excrecds.hxx
+index 0d85d9b..78f60c0 100644
+--- sc/source/filter/inc/excrecds.hxx
++++ sc/source/filter/inc/excrecds.hxx
+@@ -244,10 +244,23 @@ class XclExpWindowProtection : public	XclExpBoolRecord
+ };
+ 
+ // EXC_ID_PROTECT  Document Protection
+-class XclExpDocProtection : public	XclExpBoolRecord
++class XclExpProtection : public	XclExpBoolRecord
+ {
+ 	public:
+-		XclExpDocProtection(bool bValue);
++		XclExpProtection(bool bValue);
++};
++
++class XclExpPassHash : public XclExpRecord
++{
++public:
++    XclExpPassHash(const ::com::sun::star::uno::Sequence<sal_Int8>& aHash);
++    virtual ~XclExpPassHash();
++
++private:
++    virtual void    WriteBody(XclExpStream& rStrm);
++
++private:
++    sal_uInt16  mnHash;
+ };
+ 
+ 
+diff --git sc/source/filter/inc/imp_op.hxx sc/source/filter/inc/imp_op.hxx
+index fdc2d0a..5ae2156 100644
+--- sc/source/filter/inc/imp_op.hxx
++++ sc/source/filter/inc/imp_op.hxx
+@@ -135,9 +135,11 @@ protected:
+ 	void					Bof2( void );					// 0x09
+ 	void					Eof( void );					// 0x0A
+ 	void					DocProtect( void );             // 0x12
+-	void					Protect( void );				// 0x12	Sheet Protection
+-	BOOL					Password( void );				// 0x13
++    void                    SheetProtect( void );           // 0x12 Sheet Protection
++    void                    DocPasssword( void );           // 0x13 document password
++    void                    SheetPassword( void );               // 0x13 sheet password
+ 	void					Externsheet( void );			// 0x17
++    void                    WinProtection( void );          // 0x19
+ 	void					Columndefault( void );			// 0x20
+ 	void					Array25( void );				// 0x21
+ 	void					Rec1904( void );				// 0x22
+diff --git sc/source/filter/inc/xcl97rec.hxx sc/source/filter/inc/xcl97rec.hxx
+index a3a3589..0074d6a 100644
+--- sc/source/filter/inc/xcl97rec.hxx
++++ sc/source/filter/inc/xcl97rec.hxx
+@@ -35,6 +35,8 @@
+ #include "xcl97esc.hxx"
+ #include "xlstyle.hxx"
+ 
++#include <vector>
++
+ // --- class XclMsodrawing_Base --------------------------------------
+ 
+ class XclMsodrawing_Base
+@@ -57,29 +59,26 @@ public:
+ 
+ // --- class XclMsodrawinggroup --------------------------------------
+ 
+-class XclMsodrawinggroup : public XclMsodrawing_Base, public ExcRecord
++class XclMsodrawinggroup : public XclMsodrawing_Base, public XclExpRecord
+ {
+ private:
+ 
+-	virtual	void				SaveCont( XclExpStream& rStrm );
++	virtual	void				WriteBody( XclExpStream& rStrm );
+ 
+ public:
+ 								XclMsodrawinggroup( RootData& rRoot,
+ 									UINT16 nEscherType = 0 );
+ 	virtual						~XclMsodrawinggroup();
+-
+-	virtual UINT16				GetNum() const;
+-    virtual sal_Size            GetLen() const;
+ };
+ 
+ 
+ // --- class XclMsodrawing -------------------------------------------
+ 
+-class XclMsodrawing : public XclMsodrawing_Base, public ExcRecord
++class XclMsodrawing : public XclMsodrawing_Base, public XclExpRecord
+ {
+ private:
+ 
+-	virtual	void				SaveCont( XclExpStream& rStrm );
++	virtual	void				WriteBody( XclExpStream& rStrm );
+ 
+ public:
+                                 XclMsodrawing(
+@@ -87,9 +86,6 @@ public:
+                                     UINT16 nEscherType = 0,
+                                     sal_Size nInitialSize = 0 );
+ 	virtual						~XclMsodrawing();
+-
+-	virtual UINT16				GetNum() const;
+-    virtual sal_Size            GetLen() const;
+ };
+ 
+ 
+@@ -456,23 +452,24 @@ public:
+     virtual sal_Size            GetLen() const;
+ };
+ 
++// ============================================================================
+ 
+-// ---- class XclProtection ------------------------------------------
+-
+-class XclProtection : public ExcDummyRec
++/** Represents a SHEETPROTECTION record that stores sheet protection
++    options.  Note that a sheet still needs to save its sheet protection
++    options even when it's not protected. */
++class XclExpSheetProtectOptions : public XclExpRecord
+ {
+-	// replacement for records PROTECT, SCENPROTECT, OBJPROTECT...
+-private:
+-	static const BYTE			pMyData[];
+-    static const sal_Size       nMyLen;
+ public:
+-    virtual sal_Size            GetLen( void ) const;
+-	virtual	const BYTE*			GetData( void ) const;
+-};
++    explicit            XclExpSheetProtectOptions( const XclExpRoot& rRoot, SCTAB nTab );
+ 
++private:
++    virtual void        WriteBody( XclExpStream& rStrm );
+ 
+-// -------------------------------------------------------------------
++private:
++    sal_uInt16      mnOptions;      /// Encoded sheet protection options.
++};
+ 
++// ============================================================================
+ 
+ class XclCalccount : public ExcRecord
+ {
+@@ -528,5 +525,162 @@ public:
+                                 XclRefmode( const ScDocument& );
+ };
+ 
++// ============================================================================
++
++class XclExpFilePass : public XclExpRecord
++{
++public:
++    explicit XclExpFilePass( const XclExpRoot& rRoot );
++    virtual ~XclExpFilePass();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++
++private:
++    const XclExpRoot& mrRoot;
++};
++
++// ============================================================================
++
++class XclExpFnGroupCount : public XclExpRecord
++{
++public:
++    explicit XclExpFnGroupCount();
++    virtual ~XclExpFnGroupCount();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++/** Beginning of User Interface Records */
++class XclExpInterfaceHdr : public XclExpRecord
++{
++public:
++    explicit XclExpInterfaceHdr();
++    virtual ~XclExpInterfaceHdr();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++/** Beginning of User Interface Records */
++class XclExpInterfaceEnd : public XclExpRecord
++{
++public:
++    explicit XclExpInterfaceEnd();
++    virtual ~XclExpInterfaceEnd();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++/** ADDMENU/DELMENU Record Group Count */
++class XclExpMMS : public XclExpRecord
++{
++public:
++    explicit XclExpMMS();
++    virtual ~XclExpMMS();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++/** Write Access User Name - This record contains the user name, which is
++    the name you type when you install Excel. */
++class XclExpWriteAccess : public XclExpRecord
++{
++public:
++    explicit XclExpWriteAccess();
++    virtual ~XclExpWriteAccess();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++class XclExpCodePage : public XclExpRecord
++{
++public:
++    explicit XclExpCodePage();
++    virtual ~XclExpCodePage();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++class XclExpDSF : public XclExpRecord
++{
++public:
++    explicit XclExpDSF();
++    virtual ~XclExpDSF();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++class XclExpProt4Rev : public XclExpRecord
++{
++public:
++    explicit XclExpProt4Rev();
++    virtual ~XclExpProt4Rev();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++class XclExpProt4RevPass : public XclExpRecord
++{
++public:
++    explicit XclExpProt4RevPass();
++    virtual ~XclExpProt4RevPass();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++/** What's this record for?  It is a zero-byte record. */
++class XclExpExcel9File : public XclExpRecord
++{
++public:
++    explicit XclExpExcel9File();
++    virtual ~XclExpExcel9File();
++
++private:
++    virtual void WriteBody( XclExpStream& rStrm );
++};
++
++// ============================================================================
++
++class XclExpRecalcId : public XclExpDummyRecord
++{
++public:
++    explicit XclExpRecalcId();
++};
++
++// ============================================================================
++
++class XclExpBookExt : public XclExpDummyRecord
++{
++public:
++    explicit XclExpBookExt();
++};
++
+ 
+ #endif // _XCL97REC_HXX
+diff --git sc/source/filter/inc/xeroot.hxx sc/source/filter/inc/xeroot.hxx
+index 7e97e92..f4e1d25 100644
+--- sc/source/filter/inc/xeroot.hxx
++++ sc/source/filter/inc/xeroot.hxx
+@@ -154,7 +154,12 @@ public:
+         @param nRecId  Identifier that specifies which record is returned. */
+     XclExpRecordRef     CreateRecord( sal_uInt16 nRecId ) const;
+ 
++    bool                IsDocumentEncrypted() const;
++
++    const String        GetPassword() const;
++
+ private:
++
+     /** Returns the local or global link manager, depending on current context. */
+     XclExpRootData::XclExpLinkMgrRef GetLocalLinkMgrRef() const;
+ 
+diff --git sc/source/filter/inc/xestream.hxx sc/source/filter/inc/xestream.hxx
+index de3e58a..f485901 100644
+--- sc/source/filter/inc/xestream.hxx
++++ sc/source/filter/inc/xestream.hxx
+@@ -35,6 +35,9 @@
+ 
+ #include "xlstream.hxx"
+ 
++#include <svx/mscodec.hxx>
++#include <vector>
++
+ /* ============================================================================
+ Output stream class for Excel export
+ - CONTINUE record handling
+@@ -42,6 +45,8 @@ Output stream class for Excel export
+ ============================================================================ */
+ 
+ class XclExpRoot;
++class XclExpBiff8Encrypter;
++typedef ScfRef< XclExpBiff8Encrypter > XclExpEncrypterRef;
+ 
+ /** This class is used to export Excel record streams.
+     @descr  An instance is constructed with an SvStream and the maximum size of Excel
+@@ -100,14 +105,14 @@ public:
+     /** Sets data slice length. 0 = no slices. */
+     void                SetSliceSize( sal_uInt16 nSize );
+ 
+-    inline XclExpStream& operator<<( sal_Int8 nValue );
+-    inline XclExpStream& operator<<( sal_uInt8 nValue );
+-    inline XclExpStream& operator<<( sal_Int16 nValue );
+-    inline XclExpStream& operator<<( sal_uInt16 nValue );
+-    inline XclExpStream& operator<<( sal_Int32 nValue );
+-    inline XclExpStream& operator<<( sal_uInt32 nValue );
+-    inline XclExpStream& operator<<( float fValue );
+-    inline XclExpStream& operator<<( double fValue );
++    XclExpStream& operator<<( sal_Int8 nValue );
++    XclExpStream& operator<<( sal_uInt8 nValue );
++    XclExpStream& operator<<( sal_Int16 nValue );
++    XclExpStream& operator<<( sal_uInt16 nValue );
++    XclExpStream& operator<<( sal_Int32 nValue );
++    XclExpStream& operator<<( sal_uInt32 nValue );
++    XclExpStream& operator<<( float fValue );
++    XclExpStream& operator<<( double fValue );
+ 
+     /** Writes nBytes bytes from memory. */
+     sal_Size            Write( const void* pData, sal_Size nBytes );
+@@ -150,6 +155,14 @@ public:
+     /** Returns the absolute position of the system stream. */
+     inline sal_Size     GetSvStreamPos() const { return mrStrm.Tell(); }
+ 
++    void                SetEncrypter( XclExpEncrypterRef xEncrypter );
++
++    bool                HasValidEncrypter() const;
++
++    void                EnableEncryption( bool bEnable = true );
++
++    void                DisableEncryption();
++
+ private:
+     /** Writes header data, internal setup. */
+     void                InitRecord( sal_uInt16 nRecId );
+@@ -172,6 +185,9 @@ private:
+     SvStream&           mrStrm;         /// Reference to the system output stream.
+     const XclExpRoot&   mrRoot;         /// Filter root data.
+ 
++    bool                mbUseEncrypter;
++    XclExpEncrypterRef  mxEncrypter;
++
+                         // length data
+     sal_uInt16          mnMaxRecSize;   /// Maximum size of record content.
+     sal_uInt16          mnMaxContSize;  /// Maximum size of CONTINUE content.
+@@ -189,64 +205,51 @@ private:
+ 
+ // ----------------------------------------------------------------------------
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
+-{
+-    PrepareWrite( 1 );
+-    mrStrm << nValue;
+-    return *this;
+-}
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
+-{
+-    PrepareWrite( 1 );
+-    mrStrm << nValue;
+-    return *this;
+-}
++// ============================================================================
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
++class XclExpBiff8Encrypter
+ {
+-    PrepareWrite( 2 );
+-    mrStrm << nValue;
+-    return *this;
+-}
++public:
++    explicit XclExpBiff8Encrypter( const XclExpRoot& rRoot, const sal_uInt8 nDocId[16], 
++                                   const sal_uInt8 nSalt[16] );
++    ~XclExpBiff8Encrypter();
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
+-{
+-    PrepareWrite( 2 );
+-    mrStrm << nValue;
+-    return *this;
+-}
++    bool IsValid() const;
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
+-{
+-    PrepareWrite( 4 );
+-    mrStrm << nValue;
+-    return *this;
+-}
++    void GetSaltDigest( sal_uInt8 nSaltDigest[16] ) const;
+ 
+-inline XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
+-{
+-    PrepareWrite( 4 );
+-    mrStrm << nValue;
+-    return *this;
+-}
++    void Encrypt( SvStream& rStrm, sal_uInt8  nData );
++    void Encrypt( SvStream& rStrm, sal_uInt16 nData );
++    void Encrypt( SvStream& rStrm, sal_uInt32 nData );
+ 
+-inline XclExpStream& XclExpStream::operator<<( float fValue )
+-{
+-    PrepareWrite( 4 );
+-    mrStrm << fValue;
+-    return *this;
+-}
++    void Encrypt( SvStream& rStrm, sal_Int8  nData );
++    void Encrypt( SvStream& rStrm, sal_Int16 nData );
++    void Encrypt( SvStream& rStrm, sal_Int32 nData );
+ 
+-inline XclExpStream& XclExpStream::operator<<( double fValue )
+-{
+-    PrepareWrite( 8 );
+-    mrStrm << fValue;
+-    return *this;
+-}
++    void Encrypt( SvStream& rStrm, float fValue );
++    void Encrypt( SvStream& rStrm, double fValue );
+ 
++    void EncryptBytes( SvStream& rStrm, ::std::vector<sal_uInt8>& aBytes );
+ 
+-// ============================================================================
++private:
++    void Init( const String& aPass, const sal_uInt8 nDocId[16], 
++               const sal_uInt8 nSalt[16] );
++
++    sal_uInt32 GetBlockPos( sal_Size nStrmPos ) const;
++    sal_uInt16 GetOffsetInBlock( sal_Size nStrmPos ) const;
++
++
++private:
++    ::svx::MSCodec_Std97 maCodec;      /// Crypto algorithm implementation.
++    sal_uInt16          mnPassw[16];   /// Cached password data for copy construction.
++    sal_uInt8           mnDocId[16];   /// Cached document ID for copy construction.
++    sal_uInt8           mnSaltDigest[16];
++
++    const XclExpRoot&   mrRoot;
++    sal_Size            mnOldPos;      /// Last known stream position
++    bool                mbValid;
++};
+ 
+ #endif
+ 
+diff --git sc/source/filter/inc/xetable.hxx sc/source/filter/inc/xetable.hxx
+index b565289..8efd337 100644
+--- sc/source/filter/inc/xetable.hxx
++++ sc/source/filter/inc/xetable.hxx
+@@ -1069,7 +1069,5 @@ private:
+     XclExpDvalRef       mxDval;             /// Data validation with DVAL and DV records.
+ };
+ 
+-// ============================================================================
+-
+ #endif
+ 
+diff --git sc/source/filter/inc/xicontent.hxx sc/source/filter/inc/xicontent.hxx
+index 48f6917..07b237a 100644
+--- sc/source/filter/inc/xicontent.hxx
++++ sc/source/filter/inc/xicontent.hxx
+@@ -37,6 +37,8 @@
+ #include "xistring.hxx"
+ #include "xiroot.hxx"
+ 
++#include <map>
++
+ /* ============================================================================
+ Classes to import the big Excel document contents (related to several cells or
+ globals for the document).
+@@ -249,5 +251,64 @@ public:
+ 
+ // ============================================================================
+ 
++// Document protection ========================================================
++
++class XclImpDocProtectBuffer : protected XclImpRoot
++{
++public:
++    explicit            XclImpDocProtectBuffer( const XclImpRoot& rRoot );
++
++    /** document structure protection flag  */
++    void                ReadDocProtect( XclImpStream& rStrm );
++
++    /** document windows properties protection flag */
++    void                ReadWinProtect( XclImpStream& rStrm );
++
++    void                ReadPasswordHash( XclImpStream& rStrm );
++
++    void                Apply() const;
++
++private:
++    sal_uInt16      mnPassHash;
++    bool            mbDocProtect:1;
++    bool            mbWinProtect:1;
++};
++
++// Sheet protection ===========================================================
++
++class XclImpSheetProtectBuffer : protected XclImpRoot
++{
++public:
++    explicit            XclImpSheetProtectBuffer( const XclImpRoot& rRoot );
++
++    void                ReadProtect( XclImpStream& rStrm, SCTAB nTab );
++
++    void                ReadOptions( XclImpStream& rStrm, SCTAB nTab );
++
++    void                ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab );
++
++    void                Apply() const;
++
++private:
++    struct Sheet
++    {
++        bool        mbProtected;
++        sal_uInt16  mnPasswordHash;
++        sal_uInt16  mnOptions;
++
++        Sheet();
++        Sheet(const Sheet& r);
++    };
++
++    Sheet* GetSheetItem( SCTAB nTab );
++
++private:
++    typedef ::std::map<SCTAB, Sheet> ProtectedSheetMap;
++    ProtectedSheetMap   maProtectedSheets;
++};
++
++
++// ============================================================================
++
+ #endif
+ 
+diff --git sc/source/filter/inc/xiroot.hxx sc/source/filter/inc/xiroot.hxx
+index dfa2ca0..915f961 100644
+--- sc/source/filter/inc/xiroot.hxx
++++ sc/source/filter/inc/xiroot.hxx
+@@ -61,6 +61,8 @@ class XclImpPivotTableManager;
+ class XclImpPageSettings;
+ class XclImpDocViewSettings;
+ class XclImpTabViewSettings;
++class XclImpSheetProtectBuffer;
++class XclImpDocProtectBuffer;
+ 
+ class _ScRangeListTabs;
+ class ExcelToSc;
+@@ -87,6 +89,8 @@ struct XclImpRootData : public XclRootData
+     typedef ScfRef< XclImpPageSettings >        XclImpPageSettRef;
+     typedef ScfRef< XclImpDocViewSettings >     XclImpDocViewSettRef;
+     typedef ScfRef< XclImpTabViewSettings >     XclImpTabViewSettRef;
++    typedef ScfRef< XclImpSheetProtectBuffer >  XclImpTabProtectRef;
++    typedef ScfRef< XclImpDocProtectBuffer >    XclImpDocProtectRef;
+ 
+     XclImpAddrConvRef   mxAddrConv;         /// The address converter.
+     XclImpFmlaCompRef   mxFmlaComp;         /// The formula compiler.
+@@ -110,6 +114,11 @@ struct XclImpRootData : public XclRootData
+     XclImpPageSettRef   mxPageSett;         /// Page settings for current sheet.
+     XclImpDocViewSettRef mxDocViewSett;     /// View settings for entire document.
+     XclImpTabViewSettRef mxTabViewSett;     /// View settings for current sheet.
++    XclImpTabProtectRef mxTabProtect;       /// Sheet protection options for current sheet.
++    XclImpDocProtectRef mxDocProtect;       /// Document protection options.
++
++    String              maPassw;            /// Entered password for stream decryption.
++    bool                mbPassQueried;      /// true = Password already querried.
+ 
+     bool                mbHasCodePage;      /// true = CODEPAGE record exists.
+ 
+@@ -181,6 +190,10 @@ public:
+     XclImpWebQueryBuffer& GetWebQueryBuffer() const;
+     /** Returns the pivot table manager. */
+     XclImpPivotTableManager& GetPivotTableManager() const;
++    /** Returns the sheet protection options of the current sheet. */
++    XclImpSheetProtectBuffer& GetSheetProtectBuffer() const;
++    /** Returns the document protection options. */
++    XclImpDocProtectBuffer& GetDocProtectBuffer() const;
+ 
+     /** Returns the page settings of the current sheet. */
+     XclImpPageSettings& GetPageSettings() const;
+@@ -192,6 +205,9 @@ public:
+     /** Returns the Calc add-in function name for an Excel function name. */
+     String              GetScAddInName( const String& rXclName ) const;
+ 
++    /** Queries a password from the user and returns it (empty string -> input cancelled). */
++    const String&       QueryPassword() const;
++
+ private:
+     mutable XclImpRootData& mrImpData;      /// Reference to the global import data struct.
+ };
+diff --git sc/source/filter/inc/xistream.hxx sc/source/filter/inc/xistream.hxx
+index aa1cae8..ccaaccd 100644
+--- sc/source/filter/inc/xistream.hxx
++++ sc/source/filter/inc/xistream.hxx
+@@ -73,6 +73,8 @@ public:
+         @return  Count of bytes really read. */
+     sal_uInt16          Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes );
+ 
++    const String        GetPassword() const;
++
+ protected:
+     /** Protected copy c'tor for OnClone(). */
+     explicit            XclImpDecrypter( const XclImpDecrypter& rSrc );
+@@ -80,6 +82,8 @@ protected:
+     /** Sets the decrypter to a state showing whether the password was correct. */
+     void                SetHasValidPassword( bool bValid );
+ 
++    void                SetPassword( const String& rPass );
++
+ private:
+     /** Implementation of cloning this object. */
+     virtual XclImpDecrypter* OnClone() const = 0;
+@@ -89,6 +93,7 @@ private:
+     virtual sal_uInt16  OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes ) = 0;
+ 
+ private:
++    String              maPass;         /// Stored password (needed for export)
+     ErrCode             mnError;        /// Decrypter error code.
+     sal_Size            mnOldPos;       /// Last known stream position.
+     sal_uInt16          mnRecSize;      /// Current record size.
+diff --git sc/source/filter/inc/xlroot.hxx sc/source/filter/inc/xlroot.hxx
+index a09f5d0..38506c5 100644
+--- sc/source/filter/inc/xlroot.hxx
++++ sc/source/filter/inc/xlroot.hxx
+@@ -91,7 +91,6 @@ struct XclRootData
+     ScDocument&         mrDoc;              /// The source or destination document.
+     String              maDocUrl;           /// Document URL of imported/exported file.
+     String              maBasePath;         /// Base path of imported/exported file (path of maDocUrl).
+-    String              maPassw;            /// Entered password for stream encryption/decryption.
+     rtl_TextEncoding    meTextEnc;          /// Text encoding to import/export byte strings.
+     LanguageType        meSysLang;          /// System language.
+     LanguageType        meDocLang;          /// Document language (import: from file, export: from system).
+@@ -115,7 +114,6 @@ struct XclRootData
+     long                mnCharWidth;        /// Width of '0' in default font (twips).
+     SCTAB               mnScTab;            /// Current Calc sheet index.
+     const bool          mbExport;           /// false = Import, true = Export.
+-    bool                mbHasPassw;         /// true = Password already querried.
+ 
+     explicit            XclRootData( XclBiff eBiff, SfxMedium& rMedium,
+                             SotStorageRef xRootStrg, ScDocument& rDoc,
+@@ -181,8 +179,6 @@ public:
+     inline const String& GetDocUrl() const { return mrData.maDocUrl; }
+     /** Returns the base path of the imported/exported file. */
+     inline const String& GetBasePath() const { return mrData.maBasePath; }
+-    /** Queries a password from the user and returns it (empty string -> input cancelled). */
+-    const String&       QueryPassword() const;
+ 
+     /** Returns the OLE2 root storage of the imported/exported file.
+         @return  Pointer to root storage or 0, if the file is a simple stream. */
+diff --git sc/source/filter/starcalc/scflt.cxx sc/source/filter/starcalc/scflt.cxx
+index 9e2f57b..26cdd91 100644
+--- sc/source/filter/starcalc/scflt.cxx
++++ sc/source/filter/starcalc/scflt.cxx
+@@ -81,6 +81,7 @@
+ #include "postit.hxx"
+ #include "globstr.hrc"
+ #include "ftools.hxx"
++#include "tabprotection.hxx"
+ 
+ #include "fprogressbar.hxx"
+ 
+@@ -1087,9 +1088,11 @@ void Sc10Import::LoadProtect()
+ 	//rStream.Read(&SheetProtect, sizeof(SheetProtect));
+ 	lcl_ReadSheetProtect(rStream, SheetProtect);
+ 	nError = rStream.GetError();
+-	uno::Sequence<sal_Int8> aPass;
+-	SvPasswordHelper::GetHashPassword(aPass, SC10TOSTRING( SheetProtect.PassWord ));
+-	pDoc->SetDocProtection( SheetProtect.Protect,  aPass);
++
++    ScDocProtection aProtection;
++    aProtection.setProtected(static_cast<bool>(SheetProtect.Protect));
++    aProtection.setPassword(SC10TOSTRING(SheetProtect.PassWord));
++    pDoc->SetDocProtection(&aProtection);
+ }
+ 
+ 
+@@ -1441,10 +1444,11 @@ void Sc10Import::LoadTables()
+ 
+ 		//rStream.Read(&TabProtect, sizeof(TabProtect));
+ 		lcl_ReadTabProtect(rStream, TabProtect);
+-		uno::Sequence<sal_Int8> aPass;
+-		SvPasswordHelper::GetHashPassword(aPass, SC10TOSTRING( TabProtect.PassWord ));
+ 
+-		pDoc->SetTabProtection( static_cast<SCTAB>(Tab), TabProtect.Protect, aPass);
++        ScTableProtection aProtection;
++        aProtection.setProtected(static_cast<bool>(TabProtect.Protect));
++        aProtection.setPassword(SC10TOSTRING(TabProtect.PassWord));
++        pDoc->SetTabProtection(static_cast<SCTAB>(Tab), &aProtection);
+ 
+ 		rStream >> TabNo;
+ 
+diff --git sc/source/filter/xcl97/XclExpChangeTrack.cxx sc/source/filter/xcl97/XclExpChangeTrack.cxx
+index 4aec3d6..5b90f44 100644
+--- sc/source/filter/xcl97/XclExpChangeTrack.cxx
++++ sc/source/filter/xcl97/XclExpChangeTrack.cxx
+@@ -491,6 +491,7 @@ void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer& rBuffer )
+ 
+ void XclExpChTrTabId::SaveCont( XclExpStream& rStrm )
+ {
++    rStrm.EnableEncryption();
+ 	if( pBuffer )
+ 		for( sal_uInt16* pElem = pBuffer; pElem < (pBuffer + nTabCount); pElem++ )
+ 			rStrm << *pElem;
+diff --git sc/source/filter/xcl97/makefile.mk sc/source/filter/xcl97/makefile.mk
+index 9b081f3..e558ddd 100644
+--- sc/source/filter/xcl97/makefile.mk
++++ sc/source/filter/xcl97/makefile.mk
+@@ -50,7 +50,6 @@ PROJECTPCHSOURCE=..\pch\filt_pch
+ # --- Files --------------------------------------------------------
+ 
+ SLOFILES =									\
+-		$(SLO)$/xcl97dum.obj				\
+ 		$(SLO)$/xcl97esc.obj				\
+ 		$(SLO)$/xcl97rec.obj				\
+ 		$(SLO)$/XclImpChangeTrack.obj		\
+diff --git sc/source/filter/xcl97/xcl97rec.cxx sc/source/filter/xcl97/xcl97rec.cxx
+index bcf7d57..aa0fd88 100644
+--- sc/source/filter/xcl97/xcl97rec.cxx
++++ sc/source/filter/xcl97/xcl97rec.cxx
+@@ -78,6 +78,7 @@
+ #include "scextopt.hxx"
+ #include "docoptio.hxx"
+ #include "patattr.hxx"
++#include "tabprotection.hxx"
+ 
+ using ::rtl::OUString;
+ using namespace ::com::sun::star;
+@@ -132,9 +133,9 @@ sal_Size XclMsodrawing_Base::GetDataLen() const
+ 
+ // --- class XclMsodrawinggroup --------------------------------------
+ 
+-XclMsodrawinggroup::XclMsodrawinggroup( RootData& rRoot, UINT16 nEscherType )
+-		:
+-		XclMsodrawing_Base( *rRoot.pEscher )
++XclMsodrawinggroup::XclMsodrawinggroup( RootData& rRoot, UINT16 nEscherType ) :
++    XclMsodrawing_Base( *rRoot.pEscher ),
++    XclExpRecord(0x00EB, 2) // bogus record size since we don't know the actual size yet.
+ {
+ 	if ( nEscherType )
+ 	{
+@@ -179,7 +180,7 @@ XclMsodrawinggroup::~XclMsodrawinggroup()
+ }
+ 
+ 
+-void XclMsodrawinggroup::SaveCont( XclExpStream& rStrm )
++void XclMsodrawinggroup::WriteBody( XclExpStream& rStrm )
+ {
+     DBG_ASSERT( GetEscherEx()->GetStreamPos() == GetEscherEx()->GetOffsetFromMap( nStartPos ),
+ 		"XclMsodrawinggroup::SaveCont: Escher stream position mismatch" );
+@@ -187,23 +188,11 @@ void XclMsodrawinggroup::SaveCont( XclExpStream& rStrm )
+ }
+ 
+ 
+-UINT16 XclMsodrawinggroup::GetNum() const
+-{
+-	return 0x00EB;
+-}
+-
+-
+-sal_Size XclMsodrawinggroup::GetLen() const
+-{
+-    return GetDataLen();
+-}
+-
+-
+-
+ // --- class XclMsodrawing --------------------------------------
+ 
+ XclMsodrawing::XclMsodrawing( const XclExpRoot& rRoot, UINT16 nEscherType, sal_Size nInitialSize ) :
+-    XclMsodrawing_Base( *rRoot.GetOldRoot().pEscher, nInitialSize )
++    XclMsodrawing_Base( *rRoot.GetOldRoot().pEscher, nInitialSize ),
++    XclExpRecord( 0x00EC, nInitialSize )
+ {
+ 	if ( nEscherType )
+ 	{
+@@ -229,7 +218,7 @@ XclMsodrawing::~XclMsodrawing()
+ }
+ 
+ 
+-void XclMsodrawing::SaveCont( XclExpStream& rStrm )
++void XclMsodrawing::WriteBody( XclExpStream& rStrm )
+ {
+     DBG_ASSERT( GetEscherEx()->GetStreamPos() == GetEscherEx()->GetOffsetFromMap( nStartPos ),
+ 		"XclMsodrawing::SaveCont: Escher stream position mismatch" );
+@@ -237,16 +226,6 @@ void XclMsodrawing::SaveCont( XclExpStream& rStrm )
+ }
+ 
+ 
+-UINT16 XclMsodrawing::GetNum() const
+-{
+-	return 0x00EC;
+-}
+-
+-
+-sal_Size XclMsodrawing::GetLen() const
+-{
+-    return GetDataLen();
+-}
+ 
+ 
+ // --- class XclObjList ----------------------------------------------
+@@ -883,6 +862,7 @@ ExcBof8_Base::ExcBof8_Base()
+ 
+ void ExcBof8_Base::SaveCont( XclExpStream& rStrm )
+ {
++    rStrm.DisableEncryption();
+ 	rStrm	<< nVers << nDocType << nRupBuild << nRupYear
+ 			<< nFileHistory << nLowestBiffVer;
+ }
+@@ -936,7 +916,10 @@ void ExcBundlesheet8::SaveCont( XclExpStream& rStrm )
+ {
+     nOwnPos = rStrm.GetSvStreamPos();
+     // write dummy position, real position comes later
+-    rStrm << sal_uInt32( 0 ) << nGrbit << aUnicodeName;
++    rStrm.DisableEncryption();
++    rStrm << sal_uInt32(0);
++    rStrm.EnableEncryption();
++    rStrm << nGrbit << aUnicodeName;
+ }
+ 
+ 
+@@ -1177,33 +1160,73 @@ sal_Size ExcEScenarioManager::GetLen() const
+ 	return 8;
+ }
+ 
++// ============================================================================
+ 
+-
+-// ---- class XclProtection ------------------------------------------
+-
+-const BYTE		XclProtection::pMyData[] =
++struct XclExpTabProtectOption
+ {
+-	0x12, 0x00, 0x02, 0x00, 0x01, 0x00,			// PROTECT
+-	0xDD, 0x00, 0x02, 0x00, 0x01, 0x00,			// SCENPROTECT
+-	0x63, 0x00, 0x02, 0x00, 0x01, 0x00			// OBJPROTECT
++    ScTableProtection::Option   eOption;
++    sal_uInt16                  nMask;
+ };
+-const sal_Size XclProtection::nMyLen = sizeof( XclProtection::pMyData );
+ 
+-sal_Size XclProtection::GetLen( void ) const
++XclExpSheetProtectOptions::XclExpSheetProtectOptions( const XclExpRoot& rRoot, SCTAB nTab ) :
++    XclExpRecord( 0x0867, 23 )
+ {
+-	return nMyLen;
++    static const XclExpTabProtectOption aTable[] =
++    {
++        { ScTableProtection::OBJECTS,               0x0001 },
++        { ScTableProtection::SCENARIOS,             0x0002 },
++        { ScTableProtection::FORMAT_CELLS,          0x0004 },
++        { ScTableProtection::FORMAT_COLUMNS,        0x0008 },
++        { ScTableProtection::FORMAT_ROWS,           0x0010 },
++        { ScTableProtection::INSERT_COLUMNS,        0x0020 },
++        { ScTableProtection::INSERT_ROWS,           0x0040 },
++        { ScTableProtection::INSERT_HYPERLINKS,     0x0080 },
++
++        { ScTableProtection::DELETE_COLUMNS,        0x0100 },
++        { ScTableProtection::DELETE_ROWS,           0x0200 },
++        { ScTableProtection::SELECT_LOCKED_CELLS,   0x0400 },
++        { ScTableProtection::SORT,                  0x0800 },
++        { ScTableProtection::AUTOFILTER,            0x1000 },
++        { ScTableProtection::PIVOT_TABLES,          0x2000 },
++        { ScTableProtection::SELECT_UNLOCKED_CELLS, 0x4000 },
++
++        { ScTableProtection::NONE,                  0x0000 }
++    };
++
++    mnOptions = 0x0000;
++    ScTableProtection* pProtect = rRoot.GetDoc().GetTabProtection(nTab);
++    if (!pProtect)
++        return;
++
++    for (int i = 0; aTable[i].nMask != 0x0000; ++i)
++    {
++        if ( pProtect->isOptionEnabled(aTable[i].eOption) )
++            mnOptions |= aTable[i].nMask;
++    }
+ }
+ 
+-
+-const BYTE* XclProtection::GetData( void ) const
++void XclExpSheetProtectOptions::WriteBody( XclExpStream& rStrm )
+ {
+-	return pMyData;
+-}
+-
++    sal_uInt16 nBytes = 0x0867;
++    rStrm << nBytes;
+ 
++    sal_uChar nZero = 0x00;
++    for (int i = 0; i < 9; ++i)
++        rStrm << nZero;
+ 
++    nBytes = 0x0200;
++    rStrm << nBytes;
++    nBytes = 0x0100;
++    rStrm << nBytes;
++    nBytes = 0xFFFF;
++    rStrm << nBytes << nBytes;
+ 
++    rStrm << mnOptions;
++    nBytes = 0;
++    rStrm << nBytes;
++}
+ 
++// ============================================================================
+ 
+ 
+ 
+@@ -1291,3 +1314,250 @@ XclRefmode::XclRefmode( const ScDocument& rDoc ) :
+     XclExpBoolRecord( 0x000F, rDoc.GetAddressConvention() != ScAddress::CONV_XL_R1C1 )
+ {
+ }
++
++// ============================================================================
++
++XclExpFilePass::XclExpFilePass( const XclExpRoot& rRoot ) :
++    XclExpRecord(0x002F, 54),
++    mrRoot(rRoot)
++{
++}
++
++XclExpFilePass::~XclExpFilePass()
++{
++}
++
++void XclExpFilePass::WriteBody( XclExpStream& rStrm )
++{
++    static const sal_uInt8 nDocId[] = {
++        0x17, 0xf7, 0x01, 0x08, 0xea, 0xad, 0x30, 0x5c,
++        0x1a, 0x95, 0xa5, 0x75, 0xd6, 0x79, 0xcd, 0x8d };
++
++
++    static const sal_uInt8 nSalt[] = {    
++        0xa4, 0x5b, 0xf7, 0xe9, 0x9f, 0x55, 0x21, 0xc5, 
++        0xc5, 0x56, 0xa8, 0x0d, 0x39, 0x05, 0x3a, 0xb4 };
++
++    // 0x0000 - neither standard nor strong encryption
++    // 0x0001 - standard or strong encryption
++    rStrm << static_cast<sal_uInt16>(0x0001);
++
++    // 0x0000 - non standard encryption
++    // 0x0001 - standard encryption
++    sal_uInt16 nStdEnc = 0x0001;
++    rStrm << nStdEnc << nStdEnc;
++
++    sal_uInt8 nSaltHash[16];
++    XclExpEncrypterRef xEnc( new XclExpBiff8Encrypter(mrRoot, nDocId, nSalt) );
++    xEnc->GetSaltDigest(nSaltHash);
++
++    rStrm.Write(nDocId, 16);
++    rStrm.Write(nSalt, 16);
++    rStrm.Write(nSaltHash, 16);
++
++    rStrm.SetEncrypter(xEnc);
++}
++
++// ============================================================================
++
++XclExpFnGroupCount::XclExpFnGroupCount() :
++    XclExpRecord(0x009C, 2)
++{
++}
++
++XclExpFnGroupCount::~XclExpFnGroupCount()
++{
++}
++
++void XclExpFnGroupCount::WriteBody( XclExpStream& rStrm )
++{
++    rStrm << static_cast<sal_uInt16>(14);
++}
++
++// ============================================================================
++
++XclExpInterfaceHdr::XclExpInterfaceHdr() :
++    XclExpRecord(0x00E1, 2)
++{
++}
++
++XclExpInterfaceHdr::~XclExpInterfaceHdr()
++{
++}
++
++void XclExpInterfaceHdr::WriteBody( XclExpStream& rStrm )
++{
++    // The value must be the same value as the CODEPAGE record.
++    rStrm.DisableEncryption();
++    rStrm << static_cast<sal_uInt16>(0x04B0);
++}
++
++// ============================================================================
++
++XclExpInterfaceEnd::XclExpInterfaceEnd() :
++    XclExpRecord(0x00E2, 0)
++{
++}
++
++XclExpInterfaceEnd::~XclExpInterfaceEnd()
++{
++}
++
++void XclExpInterfaceEnd::WriteBody( XclExpStream& /*rStrm*/ )
++{
++}
++
++// ============================================================================
++
++XclExpMMS::XclExpMMS() :
++    XclExpRecord(0x00C1, 2)
++{
++}
++
++XclExpMMS::~XclExpMMS()
++{
++}
++
++void XclExpMMS::WriteBody( XclExpStream& rStrm )
++{
++    rStrm << static_cast<sal_uInt16>(0x0000);
++}
++
++// ============================================================================
++
++XclExpWriteAccess::XclExpWriteAccess() :
++    XclExpRecord(0x005C, 112)
++{
++}
++
++XclExpWriteAccess::~XclExpWriteAccess()
++{
++}
++
++void XclExpWriteAccess::WriteBody( XclExpStream& rStrm )
++{
++    static const sal_uInt8 aData[] = {
++        0x04, 0x00, 0x00,  'C',  'a',  'l',  'c', 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
++
++    sal_Size nDataSize = sizeof(aData);
++    for (sal_Size i = 0; i < nDataSize; ++i)
++        rStrm << aData[i];
++}
++
++// ============================================================================
++
++XclExpCodePage::XclExpCodePage() :
++    XclExpRecord(0x0042, 2)
++{
++}
++
++XclExpCodePage::~XclExpCodePage()
++{
++}
++
++void XclExpCodePage::WriteBody( XclExpStream& rStrm )
++{
++    // 0x04B0 : UTF-16 (BIFF8)
++    rStrm << static_cast<sal_uInt16>(0x04B0);
++}
++
++// ============================================================================
++
++XclExpDSF::XclExpDSF() :
++    XclExpRecord(0x0161, 2)
++{
++}
++
++XclExpDSF::~XclExpDSF()
++{
++}
++
++void XclExpDSF::WriteBody( XclExpStream& rStrm )
++{
++    rStrm << static_cast<sal_uInt16>(0x0000);
++}
++
++// ============================================================================
++
++XclExpProt4Rev::XclExpProt4Rev() :
++    XclExpRecord(0x01AF, 2)
++{
++}
++
++XclExpProt4Rev::~XclExpProt4Rev()
++{
++}
++
++void XclExpProt4Rev::WriteBody( XclExpStream& rStrm )
++{
++    rStrm << static_cast<sal_uInt16>(0x0000);
++}
++
++// ============================================================================
++
++XclExpProt4RevPass::XclExpProt4RevPass() :
++    XclExpRecord(0x01BC, 2)
++{
++}
++
++XclExpProt4RevPass::~XclExpProt4RevPass()
++{
++}
++
++void XclExpProt4RevPass::WriteBody( XclExpStream& rStrm )
++{
++    rStrm << static_cast<sal_uInt16>(0x0000);
++}
++
++// ============================================================================
++
++XclExpExcel9File::XclExpExcel9File() :
++    XclExpRecord(0x01C0, 0)
++{
++}
++
++XclExpExcel9File::~XclExpExcel9File()
++{
++}
++
++void XclExpExcel9File::WriteBody( XclExpStream& /*rStrm*/ )
++{
++}
++
++// ============================================================================
++
++static const sal_uInt8 nDataRecalcId[] = {
++    0xC1, 0x01, 0x00, 0x00, 0x54, 0x8D, 0x01, 0x00
++};
++
++XclExpRecalcId::XclExpRecalcId() :
++    XclExpDummyRecord(0x01C1, nDataRecalcId, sizeof(nDataRecalcId))
++{
++}
++
++// ============================================================================
++
++static const sal_uInt8 nDataBookExt[] = {
++    0x63, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++    0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
++    0x02
++};
++
++XclExpBookExt::XclExpBookExt() :
++    XclExpDummyRecord(0x0863, nDataBookExt, sizeof(nDataBookExt))
++{
++}
++
+diff --git sc/source/filter/xml/xmlbodyi.cxx sc/source/filter/xml/xmlbodyi.cxx
+index 320c8ac..2105eec 100644
+--- sc/source/filter/xml/xmlbodyi.cxx
++++ sc/source/filter/xml/xmlbodyi.cxx
+@@ -52,6 +52,7 @@
+ #include "XMLTrackedChangesContext.hxx"
+ #include "XMLEmptyContext.hxx"
+ #include "scerrors.hxx"
++#include "tabprotection.hxx"
+ 
+ #include <xmloff/xmltkmap.hxx>
+ #include <xmloff/xmltoken.hxx>
+@@ -62,6 +63,8 @@
+ #include <sal/types.h>
+ #include <tools/debug.hxx>
+ 
++#include <memory>
++
+ using namespace com::sun::star;
+ using namespace xmloff::token;
+ using ::rtl::OUString;
+@@ -281,10 +284,17 @@ void ScXMLBodyContext::EndElement()
+         // #i37959# handle document protection after the sheet settings
+ 		if (bProtected)
+ 		{
++            ::std::auto_ptr<ScDocProtection> pProtection(new ScDocProtection);
++            pProtection->setProtected(true);
++
+ 			uno::Sequence<sal_Int8> aPass;
+ 			if (sPassword.getLength())
++            {
+ 				SvXMLUnitConverter::decodeBase64(aPass, sPassword);
+-			pDoc->SetDocProtection(bProtected, aPass);
++                pProtection->setPasswordHash(aPass, PASSHASH_OOO);
++            }
++
++            pDoc->SetDocProtection(pProtection.get());
+ 		}
+ 	}
+ 	GetScImport().UnlockSolarMutex();
+diff --git sc/source/filter/xml/xmlexprt.cxx sc/source/filter/xml/xmlexprt.cxx
+index 3d5a0ef..906ecc8 100644
+--- sc/source/filter/xml/xmlexprt.cxx
++++ sc/source/filter/xml/xmlexprt.cxx
+@@ -68,6 +68,7 @@
+ #include "convuno.hxx"
+ #include "postit.hxx"
+ #include "externalrefmgr.hxx"
++#include "tabprotection.hxx"
+ 
+ #include <xmloff/xmltoken.hxx>
+ #include <xmloff/xmlnmspe.hxx>
+@@ -1470,7 +1471,11 @@ void ScXMLExport::SetBodyAttributes()
+ 	{
+ 		AddAttribute(XML_NAMESPACE_TABLE, XML_STRUCTURE_PROTECTED, XML_TRUE);
+ 		rtl::OUStringBuffer aBuffer;
+-		SvXMLUnitConverter::encodeBase64(aBuffer, pDoc->GetDocPassword());
++        uno::Sequence<sal_Int8> aPassHash;
++        const ScDocProtection* p = pDoc->GetDocProtection();
++        if (p)
++            aPassHash = p->getPasswordHash(PASSHASH_OOO);
++		SvXMLUnitConverter::encodeBase64(aBuffer, aPassHash);
+ 		if (aBuffer.getLength())
+ 			AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
+ 	}
+@@ -1544,7 +1549,11 @@ void ScXMLExport::_ExportContent()
+                         AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
+                         rtl::OUStringBuffer aBuffer;
+                         if (pDoc)
+-                            SvXMLUnitConverter::encodeBase64(aBuffer, pDoc->GetTabPassword(static_cast<SCTAB>(nTable)));
++                        {
++                            ScTableProtection* pProtect = pDoc->GetTabProtection(static_cast<SCTAB>(nTable));
++                            if (pProtect)
++                                SvXMLUnitConverter::encodeBase64(aBuffer, pProtect->getPasswordHash(PASSHASH_OOO));
++                        }
+                         if (aBuffer.getLength())
+                             AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
+                     }
+diff --git sc/source/filter/xml/xmlsubti.cxx sc/source/filter/xml/xmlsubti.cxx
+index a268069..798f41f 100644
+--- sc/source/filter/xml/xmlsubti.cxx
++++ sc/source/filter/xml/xmlsubti.cxx
+@@ -42,6 +42,7 @@
+ #include "docuno.hxx"
+ #include "cellsuno.hxx"
+ #include "XMLStylesImportHelper.hxx"
++#include "tabprotection.hxx"
+ 
+ #include <xmloff/xmltkmap.hxx>
+ #include <xmloff/nmspmap.hxx>
+@@ -58,6 +59,10 @@
+ #include <com/sun/star/util/XProtectable.hpp>
+ #include <com/sun/star/sheet/XArrayFormulaRange.hpp>
+ 
++#include <memory>
++
++using ::std::auto_ptr;
++
+ //------------------------------------------------------------------
+ 
+ using namespace com::sun::star;
+@@ -615,13 +620,10 @@ void ScMyTables::DeleteTable()
+ 	{
+ 		uno::Sequence<sal_Int8> aPass;
+ 		SvXMLUnitConverter::decodeBase64(aPass, sPassword);
+-		rImport.GetDocument()->SetTabProtection(static_cast<SCTAB>(nCurrentSheet), bProtection, aPass);
+-		/*uno::Reference <util::XProtectable> xProtectable(xCurrentSheet, uno::UNO_QUERY);
+-		if (xProtectable.is())
+-		{
+-			rtl::OUString sKey;
+-			xProtectable->protect(sKey);
+-		}*/
++        auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
++        pProtect->setProtected(bProtection);
++        pProtect->setPasswordHash(aPass, PASSHASH_OOO);
++        rImport.GetDocument()->SetTabProtection(static_cast<SCTAB>(nCurrentSheet), pProtect.get());
+ 	}
+ 
+ 	rImport.UnlockSolarMutex();
+diff --git sc/source/ui/docshell/docfunc.cxx sc/source/ui/docshell/docfunc.cxx
+index 37d799c..969afad 100644
+--- sc/source/ui/docshell/docfunc.cxx
++++ sc/source/ui/docshell/docfunc.cxx
+@@ -92,7 +92,12 @@
+ #include "editable.hxx"
+ #include "compiler.hxx"
+ #include "scui_def.hxx" //CHINA001
++#include "tabprotection.hxx"
++
++#include <memory>
++
+ using namespace com::sun::star;
++using ::com::sun::star::uno::Sequence;
+ 
+ // STATIC DATA -----------------------------------------------------------
+ 
+@@ -2790,103 +2795,156 @@ BOOL ScDocFunc::RemovePageBreak( BOOL bColumn, const ScAddress& rPos,
+ 
+ //------------------------------------------------------------------------
+ 
+-BOOL lcl_ValidPassword( ScDocument* pDoc, SCTAB nTab,
+-						const String& rPassword,
+-						uno::Sequence<sal_Int8>* pReturnOld = NULL )
++void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
+ {
+-	uno::Sequence<sal_Int8> aOldPassword;
+-	if ( nTab == TABLEID_DOC )
+-	{
+-		if (pDoc->IsDocProtected())
+-			aOldPassword = pDoc->GetDocPassword();
+-	}
+-	else
+-	{
+-		if (pDoc->IsTabProtected(nTab))
+-			aOldPassword = pDoc->GetTabPassword(nTab);
+-	}
++    ScDocument* pDoc = rDocShell.GetDocument();
+ 
+-	if (pReturnOld)
+-		*pReturnOld = aOldPassword;
++    pDoc->SetTabProtection(nTab, &rProtect);
++    if (pDoc->IsUndoEnabled())
++    {
++        ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++        DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
++        if (pProtect)
++        {
++            ::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
++            p->setProtected(true); // just in case ...
++            rDocShell.GetUndoManager()->AddUndoAction(
++                new ScUndoTabProtect(&rDocShell, nTab, p) );
++
++            // ownership of auto_ptr now transferred to ScUndoTabProtect.
++        }
++    }
+ 
+-	return ((aOldPassword.getLength() == 0) || SvPasswordHelper::CompareHashPassword(aOldPassword, rPassword));
++    rDocShell.PostPaintGridAll();
++    ScDocShellModificator aModificator(rDocShell);
++    aModificator.SetDocumentModified();
+ }
+ 
+-BOOL ScDocFunc::Protect( SCTAB nTab, const String& rPassword, BOOL bApi )
++BOOL ScDocFunc::Protect( SCTAB nTab, const String& rPassword, BOOL /*bApi*/ )
+ {
+-	ScDocShellModificator aModificator( rDocShell );
++    ScDocument* pDoc = rDocShell.GetDocument();
++    if (nTab == TABLEID_DOC)
++    {
++        // document protection
++        ScDocProtection aProtection;
++        aProtection.setProtected(true);
++        aProtection.setPassword(rPassword);
++        pDoc->SetDocProtection(&aProtection);
++        if (pDoc->IsUndoEnabled())
++        {
++            ScDocProtection* pProtect = pDoc->GetDocProtection();
++            DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScDocProtection pointer is NULL!");
++            if (pProtect)
++            {
++                ::std::auto_ptr<ScDocProtection> p(new ScDocProtection(*pProtect));
++                p->setProtected(true); // just in case ...
++                rDocShell.GetUndoManager()->AddUndoAction(
++                    new ScUndoDocProtect(&rDocShell, p) );
++                // ownership of auto_ptr is transferred to ScUndoDocProtect.
++            }
++        }
++    }
++    else
++    {
++        // sheet protection
+ 
+-	ScDocument* pDoc = rDocShell.GetDocument();
+-	BOOL bUndo(pDoc->IsUndoEnabled());
+-	BOOL bOk = lcl_ValidPassword( pDoc, nTab, rPassword);
+-	if ( bOk )
+-	{
+-	    uno::Sequence<sal_Int8> aPass;
+-	    if (rPassword.Len())
+-	        SvPasswordHelper::GetHashPassword(aPass, rPassword);
++        ScTableProtection aProtection;
++        aProtection.setProtected(true);
++        aProtection.setPassword(rPassword);
++        pDoc->SetTabProtection(nTab, &aProtection);
++        if (pDoc->IsUndoEnabled())
++        {
++            ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++            DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!");
++            if (pProtect)
++            {
++                ::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect));
++                p->setProtected(true); // just in case ...
++                rDocShell.GetUndoManager()->AddUndoAction(
++                    new ScUndoTabProtect(&rDocShell, nTab, p) );
++                // ownership of auto_ptr now transferred to ScUndoTabProtect.
++            }
++        }
++    }
+ 
+-		if (bUndo)
+-		{
+-			rDocShell.GetUndoManager()->AddUndoAction(
+-						new ScUndoProtect( &rDocShell, nTab, TRUE, aPass ) );
+-		}
++    rDocShell.PostPaintGridAll();
++    ScDocShellModificator aModificator( rDocShell );
++    aModificator.SetDocumentModified();
+ 
+-		if ( nTab == TABLEID_DOC )
+-			pDoc->SetDocProtection( TRUE, aPass );
+-		else
+-			pDoc->SetTabProtection( nTab, TRUE, aPass );
++    return true;
++}
+ 
+-		rDocShell.PostPaintGridAll();
+-		aModificator.SetDocumentModified();
+-	}
+-	else if (!bApi)
+-	{
+-		//	different password was set before
++BOOL ScDocFunc::Unprotect( SCTAB nTab, const String& rPassword, BOOL bApi )
++{
++    ScDocument* pDoc = rDocShell.GetDocument();
+ 
+-//!		rDocShell.ErrorMessage(...);
++    if (nTab == TABLEID_DOC)
++    {
++        // document protection
+ 
+-		InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
+-		aBox.Execute();
+-	}
++        ScDocProtection* pDocProtect = pDoc->GetDocProtection();
++        if (!pDocProtect || !pDocProtect->isProtected())
++            // already unprotected (should not happen)!
++            return true;
+ 
+-	return bOk;
+-}
++        // save the protection state before unprotect (for undo).
++        ::std::auto_ptr<ScDocProtection> pProtectCopy(new ScDocProtection(*pDocProtect));
+ 
+-BOOL ScDocFunc::Unprotect( SCTAB nTab, const String& rPassword, BOOL bApi )
+-{
+-	ScDocShellModificator aModificator( rDocShell );
++        if (!pDocProtect->verifyPassword(rPassword))
++        {
++            if (!bApi)
++            {
++                InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
++                aBox.Execute();
++            }
++            return false;
++        }
+ 
+-	ScDocument* pDoc = rDocShell.GetDocument();
+-	BOOL bUndo(pDoc->IsUndoEnabled());
+-	uno::Sequence<sal_Int8> aOldPassword;
+-	uno::Sequence<sal_Int8> aPass;
+-	BOOL bOk = lcl_ValidPassword( pDoc, nTab, rPassword, &aOldPassword );
+-	if ( bOk )
+-	{
+-		uno::Sequence<sal_Int8> aEmptyPass;
+-		if ( nTab == TABLEID_DOC )
+-			pDoc->SetDocProtection( FALSE, aEmptyPass );
+-		else
+-			pDoc->SetTabProtection( nTab, FALSE, aEmptyPass );
++        pDoc->SetDocProtection(NULL);
++        if (pDoc->IsUndoEnabled())
++        {
++            pProtectCopy->setProtected(false);
++            rDocShell.GetUndoManager()->AddUndoAction(
++                new ScUndoDocProtect(&rDocShell, pProtectCopy) );
++            // ownership of auto_ptr now transferred to ScUndoDocProtect.
++        }
++    }
++    else
++    {
++        // sheet protection
+ 
+-		if (bUndo)
+-		{
+-			rDocShell.GetUndoManager()->AddUndoAction(
+-						new ScUndoProtect( &rDocShell, nTab, FALSE, aOldPassword ) );
+-		}
++        ScTableProtection* pTabProtect = pDoc->GetTabProtection(nTab);
++        if (!pTabProtect || !pTabProtect->isProtected())
++            // already unprotected (should not happen)!
++            return true;
+ 
+-		rDocShell.PostPaintGridAll();
+-		aModificator.SetDocumentModified();
+-	}
+-	else if (!bApi)
+-	{
+-//!		rDocShell.ErrorMessage(...);
++        // save the protection state before unprotect (for undo).
++        ::std::auto_ptr<ScTableProtection> pProtectCopy(new ScTableProtection(*pTabProtect));
++        if (!pTabProtect->verifyPassword(rPassword))
++        {
++            if (!bApi)
++            {
++                InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
++                aBox.Execute();
++            }
++            return false;
++        }
+ 
+-		InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) );
+-		aBox.Execute();
+-	}
++        pDoc->SetTabProtection(nTab, NULL);
++        if (pDoc->IsUndoEnabled())
++        {
++            pProtectCopy->setProtected(false);
++            rDocShell.GetUndoManager()->AddUndoAction(
++                new ScUndoTabProtect(&rDocShell, nTab, pProtectCopy) );
++            // ownership of auto_ptr now transferred to ScUndoTabProtect.
++        }
++    }
++
++    rDocShell.PostPaintGridAll();
++    ScDocShellModificator aModificator( rDocShell );
++    aModificator.SetDocumentModified();
+ 
+-	return bOk;
++    return true;
+ }
+ 
+ //------------------------------------------------------------------------
+diff --git sc/source/ui/docshell/docsh.cxx sc/source/ui/docshell/docsh.cxx
+index 50c8344..257f21b 100644
+--- sc/source/ui/docshell/docsh.cxx
++++ sc/source/ui/docshell/docsh.cxx
+@@ -79,11 +79,6 @@
+ #include <sot/formats.hxx>
+ #define SOT_FORMATSTR_ID_STARCALC_30 SOT_FORMATSTR_ID_STARCALC
+ 
+-//REMOVE	#ifndef SO2_DECL_SVSTORAGESTREAM_DEFINED
+-//REMOVE	#define SO2_DECL_SVSTORAGESTREAM_DEFINED
+-//REMOVE	SO2_DECL_REF(SotStorageStream)
+-//REMOVE	#endif
+-
+ // INCLUDE ---------------------------------------------------------------
+ 
+ #include "cell.hxx"
+@@ -97,7 +92,6 @@
+ #include "scresid.hxx"
+ #include "sc.hrc"
+ #include "globstr.hrc"
+-//CHINA001 #include "tpstat.hxx"
+ #include "scerrors.hxx"
+ #include "brdcst.hxx"
+ #include "stlpool.hxx"
+@@ -126,6 +120,7 @@
+ #include "cfgids.hxx"
+ #include "warnpassword.hxx"
+ #include "optsolver.hxx"
++#include "tabprotection.hxx"
+ 
+ #include "docsh.hxx"
+ #include "docshimp.hxx"
+@@ -1297,6 +1292,16 @@ BOOL __EXPORT ScDocShell::SaveAs( SfxMedium& rMedium )
+ {
+ 	RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::SaveAs" );
+ 
++#if ENABLE_SHEET_PROTECTION
++    ScTabViewShell* pViewShell = GetBestViewShell();
++    if (pViewShell && ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_OOO))
++    {
++        if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_OOO))
++            // password re-type cancelled.  Don't save the document.
++            return false;
++    }
++#endif
++
+ 	ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() );
+ 
+ 	//	DoEnterHandler hier nicht (wegen AutoSave), ist im ExecuteSave
+@@ -1771,7 +1776,6 @@ void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt
+ 	rStream.SetNumberFormatInt( nOldNumberFormatInt );
+ }
+ 
+-
+ BOOL __EXPORT ScDocShell::ConvertTo( SfxMedium &rMed )
+ {
+ 	RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ConvertTo" );
+@@ -1824,15 +1828,40 @@ BOOL __EXPORT ScDocShell::ConvertTo( SfxMedium &rMed )
+                 aDocument.SetExtDocOptions( pExtDocOpt = new ScExtDocOptions );
+             pViewShell->GetViewData()->WriteExtOptions( *pExtDocOpt );
+ 
+-            /*  #115980 #If the imported document contained an encrypted password -
+-                determine if we should save without it. */
+-            ScExtDocSettings& rDocSett = pExtDocOpt->GetDocSettings();
+-            if( rDocSett.mbEncrypted )
++#if ENABLE_SHEET_PROTECTION
++            bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_XL);
++            if (bNeedRetypePassDlg && !pViewShell->ExecuteRetypePassDlg(PASSHASH_XL))
++            {
++                SetError( ERRCODE_ABORT );
++                return false;
++            }
++#else
++            bool bEncrypted = false;
++
++            do
+             {
++                SfxItemSet* pSet = rMed.GetItemSet();
++                if (!pSet)
++                    break;
++                                                                                              
++                const SfxPoolItem* pItem = NULL;
++                if (SFX_ITEM_SET != pSet->GetItemState(SID_PASSWORD, sal_True, &pItem))
++                    // password is not set.
++                    break;
++
++                /*  #115980 #If the imported document contained an encrypted password -
++                    determine if we should save without it. */
+                 bDoSave = ScWarnPassword::WarningOnPassword( rMed );
+-                // #i42858# warn only on time
+-                rDocSett.mbEncrypted = false;
++
++                if (bDoSave)
++                {
++                    // #i42858# warn only one time
++                    pSet->ClearItem(SID_PASSWORD);
++                }
+             }
++            while (false);
++
++#endif            
+         }
+ 
+         if( bDoSave )
+diff --git sc/source/ui/docshell/docsh5.cxx sc/source/ui/docshell/docsh5.cxx
+index 8a503ee..d3a3d16 100644
+--- sc/source/ui/docshell/docsh5.cxx
++++ sc/source/ui/docshell/docsh5.cxx
+@@ -827,7 +827,7 @@ BOOL ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, BOOL bCopy, BOOL bRec
+ 				++nAdjSource;				// new position of source table after CopyTab
+ 
+ 			if ( aDocument.IsTabProtected( nAdjSource ) )
+-				aDocument.SetTabProtection( nDestTab, TRUE, aDocument.GetTabPassword( nAdjSource ) );
++                aDocument.CopyTabProtection(nAdjSource, nDestTab);
+ 
+ 			if (bRecord)
+ 			{
+diff --git sc/source/ui/inc/docfunc.hxx sc/source/ui/inc/docfunc.hxx
+index 6d32644..bf9961e 100644
+--- sc/source/ui/inc/docfunc.hxx
++++ sc/source/ui/inc/docfunc.hxx
+@@ -47,7 +47,7 @@ class ScRangeName;
+ class ScBaseCell;
+ class ScTokenArray;
+ struct ScTabOpParam;
+-
++class ScTableProtection;
+ 
+ // ---------------------------------------------------------------------------
+ 
+@@ -131,6 +131,8 @@ public:
+ 	BOOL			RemovePageBreak( BOOL bColumn, const ScAddress& rPos,
+ 									BOOL bRecord, BOOL bSetModified, BOOL bApi );
+ 
++    void            ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect );
++
+ 	BOOL			Protect( SCTAB nTab, const String& rPassword, BOOL bApi );
+ 	BOOL			Unprotect( SCTAB nTab, const String& rPassword, BOOL bApi );
+ 
+diff --git sc/source/ui/inc/protectiondlg.hrc sc/source/ui/inc/protectiondlg.hrc
+new file mode 100644
+index 0000000..63cb9bf
+--- /dev/null
++++ sc/source/ui/inc/protectiondlg.hrc
+@@ -0,0 +1,47 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: protectiondlg.hrc,v $
++ * $Revision: 1.1.2.1 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include <sc.hrc>
++
++#define BTN_OK                  1
++#define BTN_CANCEL              2
++#define BTN_HELP                3
++
++#define BTN_PROTECT             4
++#define FT_PASSWORD1            5
++#define ED_PASSWORD1            6
++#define FT_PASSWORD2            7
++#define ED_PASSWORD2            8
++#define FL_OPTIONS              9
++#define FT_OPTIONS             10
++#define CLB_OPTIONS            11
++
++#define ST_SELECT_LOCKED_CELLS          50
++#define ST_SELECT_UNLOCKED_CELLS        51
+diff --git sc/source/ui/inc/protectiondlg.hxx sc/source/ui/inc/protectiondlg.hxx
+new file mode 100644
+index 0000000..263931f
+--- /dev/null
++++ sc/source/ui/inc/protectiondlg.hxx
+@@ -0,0 +1,85 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: protectiondlg.hxx,v $
++ * $Revision: 1.1.2.4 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_UI_PROTECTION_DLG_HXX
++#define SC_UI_PROTECTION_DLG_HXX
++
++#include <vcl/dialog.hxx>
++#include <vcl/button.hxx>
++#include <vcl/fixed.hxx>
++#include <vcl/edit.hxx>
++#include <svx/checklbx.hxx>
++
++class Window;
++class ScTableProtection;
++
++class ScTableProtectionDlg : public ModalDialog
++{
++public:
++    explicit ScTableProtectionDlg(Window* pParent);
++    virtual ~ScTableProtectionDlg();
++
++    virtual short Execute();
++
++    void SetDialogData(const ScTableProtection& rData);
++
++    void WriteData(ScTableProtection& rData) const;
++
++private:
++    ScTableProtectionDlg(); // disabled
++
++    void Init();
++
++    void EnableOptionalWidgets(bool bEnable = true);
++
++    CheckBox        maBtnProtect;
++
++    FixedText       maPassword1Text;
++    Edit            maPassword1Edit;
++    FixedText       maPassword2Text;
++    Edit            maPassword2Edit;
++
++    FixedLine       maOptionsLine;
++    FixedText       maOptionsText;
++    SvxCheckListBox maOptionsListBox;
++
++    OKButton        maBtnOk;
++    CancelButton    maBtnCancel;
++    HelpButton      maBtnHelp;
++
++    String          maSelectLockedCells;
++    String          maSelectUnlockedCells;
++
++    DECL_LINK( OKHdl, OKButton* );
++    DECL_LINK( CheckBoxHdl, CheckBox* );
++    DECL_LINK( PasswordModifyHdl, Edit* );
++};
++
++#endif
+diff --git sc/source/ui/inc/retypepassdlg.hrc sc/source/ui/inc/retypepassdlg.hrc
+new file mode 100644
+index 0000000..2bd8d00
+--- /dev/null
++++ sc/source/ui/inc/retypepassdlg.hrc
+@@ -0,0 +1,74 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: retypepassdlg.hrc,v $
++ * $Revision: 1.1.2.2 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include <sc.hrc>
++
++#define BTN_OK                   1
++#define BTN_CANCEL               2
++#define BTN_HELP                 3
++
++#define FT_DESC                 10
++#define FL_DOCUMENT             11
++#define FT_DOCSTATUS            12
++#define BTN_RETYPE_DOC          13
++
++#define FL_SHEET                112
++
++#define FT_SHEETNAME1           113
++#define FT_SHEETSTATUS1         114
++#define BTN_RETYPE_SHEET1       115
++
++#define FT_SHEETNAME2           116
++#define FT_SHEETSTATUS2         117
++#define BTN_RETYPE_SHEET2       118
++
++#define FT_SHEETNAME3           119
++#define FT_SHEETSTATUS3         120
++#define BTN_RETYPE_SHEET3       121
++
++#define FT_SHEETNAME4           122
++#define FT_SHEETSTATUS4         123
++#define BTN_RETYPE_SHEET4       124
++
++#define SB_SCROLL               190
++
++#define STR_NOT_PROTECTED       200
++#define STR_NOT_PASS_PROTECTED  201
++#define STR_HASH_BAD            202
++#define STR_HASH_GOOD           203
++#define STR_HASH_REGENERATED    204
++
++#define FT_PASSWORD1            301
++#define ED_PASSWORD1            302
++#define FT_PASSWORD2            303
++#define ED_PASSWORD2            304
++#define BTN_MATCH_OLD_PASSWORD  305
++#define BTN_RETYPE_PASSWORD     306
++#define BTN_REMOVE_PASSWORD     307
+diff --git sc/source/ui/inc/retypepassdlg.hxx sc/source/ui/inc/retypepassdlg.hxx
+new file mode 100644
+index 0000000..4899d8f
+--- /dev/null
++++ sc/source/ui/inc/retypepassdlg.hxx
+@@ -0,0 +1,177 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: retypepassdlg.hxx,v $
++ * $Revision: 1.1.2.7 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_UI_RETYPEPASS_DLG_HXX
++#define SC_UI_RETYPEPASS_DLG_HXX
++
++#include <vcl/dialog.hxx>
++#include <vcl/button.hxx>
++#include <vcl/fixed.hxx>
++#include <vcl/edit.hxx>
++#include <vcl/scrbar.hxx>
++#include <svx/checklbx.hxx>
++#include <svtools/stdctrl.hxx>
++
++#include "tabprotection.hxx"
++
++#include <boost/shared_ptr.hpp>
++
++class Window;
++class ScDocProtection;
++class ScTableProtection;
++class ScDocument;
++
++class ScRetypePassDlg : public ModalDialog
++{
++public:
++    typedef ::boost::shared_ptr<ScDocProtection>    DocProtectionPtr;
++    typedef ::boost::shared_ptr<ScTableProtection>  TabProtectionPtr;
++
++    explicit ScRetypePassDlg(Window* pParent);
++    virtual ~ScRetypePassDlg();
++
++    virtual short Execute();
++
++    void SetData(const ScDocument& rDoc);
++    void SetDesiredHash(ScPasswordHash eHash);
++
++    /** Write the new set of password data to the document instance to
++        overwrite the current ones. */
++    void WriteNewDataToDocument(ScDocument& rDoc) const;
++
++private:
++    ScRetypePassDlg(); // disabled
++
++    void Init();
++    void PopulateDialog();
++    void SetDocData();
++    void SetTableData(sal_uInt8 nRowPos, SCTAB nTab);
++    void ResetTableRows();
++
++    /** Check the status of all hash values to see if it's okay to enable
++        the OK button. */
++    void CheckHashStatus();
++
++private:
++    OKButton        maBtnOk;
++    CancelButton    maBtnCancel;
++    HelpButton      maBtnHelp;
++
++    FixedInfo       maTextDescription;
++
++    FixedLine       maLineDocument;
++    FixedText       maTextDocStatus;
++    PushButton      maBtnRetypeDoc;
++
++    FixedLine       maLineSheet;
++    FixedText       maTextSheetName1;
++    FixedText       maTextSheetStatus1;
++    PushButton      maBtnRetypeSheet1;
++
++    FixedText       maTextSheetName2;
++    FixedText       maTextSheetStatus2;
++    PushButton      maBtnRetypeSheet2;
++
++    FixedText       maTextSheetName3;
++    FixedText       maTextSheetStatus3;
++    PushButton      maBtnRetypeSheet3;
++
++    FixedText       maTextSheetName4;
++    FixedText       maTextSheetStatus4;
++    PushButton      maBtnRetypeSheet4;
++
++    ScrollBar       maScrollBar;
++
++    String          maTextNotProtected;
++    String          maTextNotPassProtected;
++    String          maTextHashBad;
++    String          maTextHashGood;
++    String          maTextHashRegen;
++
++    DECL_LINK( OKHdl, OKButton* );
++    DECL_LINK( RetypeBtnHdl, PushButton* );
++    DECL_LINK( ScrollHdl, ScrollBar* );
++
++    struct TableItem
++    {
++        String              maName;
++        TabProtectionPtr    mpProtect;
++    };
++    ::std::vector<TableItem> maTableItems;
++
++    DocProtectionPtr    mpDocItem;
++    size_t              mnCurScrollPos;
++    ScPasswordHash      meDesiredHash;
++};
++
++// ============================================================================
++
++class ScRetypePassInputDlg : public ModalDialog
++{
++public:
++    explicit ScRetypePassInputDlg(Window* pParent, ScPassHashProtectable* pProtected);
++    virtual ~ScRetypePassInputDlg();
++
++    virtual short Execute();
++
++    bool IsRemovePassword() const;
++    String GetNewPassword() const;
++
++private:
++    ScRetypePassInputDlg(); // disabled
++
++    void Init();
++    void CheckPasswordInput();
++
++private:
++    OKButton        maBtnOk;
++    CancelButton    maBtnCancel;
++    HelpButton      maBtnHelp;
++
++    RadioButton     maBtnRetypePassword;
++
++    FixedText       maPassword1Text;
++    Edit            maPassword1Edit;
++    FixedText       maPassword2Text;
++    Edit            maPassword2Edit;
++
++    CheckBox        maBtnMatchOldPass;
++
++    RadioButton     maBtnRemovePassword;
++
++    DECL_LINK( OKHdl, OKButton* );
++    DECL_LINK( RadioBtnHdl, RadioButton* );
++    DECL_LINK( CheckBoxHdl, CheckBox* );
++    DECL_LINK( PasswordModifyHdl, Edit* );
++
++    ScPassHashProtectable* mpProtected;
++};
++
++#endif
+diff --git sc/source/ui/inc/tabvwsh.hxx sc/source/ui/inc/tabvwsh.hxx
+index 85051b9..8ebd718 100644
+--- sc/source/ui/inc/tabvwsh.hxx
++++ sc/source/ui/inc/tabvwsh.hxx
+@@ -38,6 +38,7 @@
+ #include "target.hxx"
+ #include "rangelst.hxx"			// ScRangeListRef
+ #include "shellids.hxx"
++#include "tabprotection.hxx" // for ScPasswordHash
+ 
+ class FmFormShell;
+ class SbxObject;
+@@ -428,6 +429,8 @@ public:
+ 	void	BroadcastAccessibility( const SfxHint &rHint );
+ 	BOOL	HasAccessibilityObjects();
+ 
++    bool    ExecuteRetypePassDlg(ScPasswordHash eDesiredHash);
++
+     using ScTabView::ShowCursor;
+ };
+ 
+diff --git sc/source/ui/inc/undotab.hxx sc/source/ui/inc/undotab.hxx
+index e965071..b4d7ca5 100644
+--- sc/source/ui/inc/undotab.hxx
++++ sc/source/ui/inc/undotab.hxx
+@@ -52,11 +52,15 @@
+ 
+ #include <com/sun/star/uno/Sequence.hxx>
+ 
++#include <memory>
++
+ class ScDocShell;
+ class ScDocument;
+ class SdrUndoAction;
+ class ScPrintRangeSaver;
+ class SdrObject;
++class ScDocProtection;
++class ScTableProtection;
+ 
+ //----------------------------------------------------------------------------
+ 
+@@ -335,14 +339,15 @@ private:
+ 	void DoChange( BOOL bShow ) const;
+ };
+ 
++// ============================================================================
+ 
+-class ScUndoProtect : public ScSimpleUndo
++/** This class implements undo & redo of document protect & unprotect
++    operations. */
++class ScUndoDocProtect : public ScSimpleUndo
+ {
+ public:
+-					TYPEINFO();
+-					ScUndoProtect( ScDocShell* pShell, SCTAB nNewTab,
+-									BOOL bNewProtect, const com::sun::star::uno::Sequence<sal_Int8>& rNewPassword );
+-	virtual			~ScUndoProtect();
++                    ScUndoDocProtect(ScDocShell* pShell, ::std::auto_ptr<ScDocProtection> pProtectSettings);
++	virtual			~ScUndoDocProtect();
+ 
+ 	virtual void	Undo();
+ 	virtual void	Redo();
+@@ -352,11 +357,34 @@ public:
+ 	virtual String	GetComment() const;
+ 
+ private:
+-	SCTAB	nTab;
+-	BOOL	bProtect;
+-	com::sun::star::uno::Sequence<sal_Int8>	aPassword;
++    ::std::auto_ptr<ScDocProtection> mpProtectSettings;
++
++	void	DoProtect(bool bProtect);
++};
++
++// ============================================================================
++
++/** This class implements undo & redo of both protect and unprotect of
++    sheet. */
++class ScUndoTabProtect : public ScSimpleUndo
++{
++public:
++                    ScUndoTabProtect(ScDocShell* pShell, SCTAB nTab, 
++                                     ::std::auto_ptr<ScTableProtection> pProtectSettings);
++	virtual			~ScUndoTabProtect();
++
++	virtual void	Undo();
++	virtual void	Redo();
++	virtual void	Repeat(SfxRepeatTarget& rTarget);
++	virtual BOOL	CanRepeat(SfxRepeatTarget& rTarget) const;
++
++	virtual String	GetComment() const;
++
++private:
++    SCTAB   mnTab;
++    ::std::auto_ptr<ScTableProtection> mpProtectSettings;
+ 
+-	void	DoProtect( BOOL bDo );
++	void	DoProtect(bool bProtect);
+ };
+ 
+ 
+diff --git sc/source/ui/inc/viewfunc.hxx sc/source/ui/inc/viewfunc.hxx
+index 8542b69..72e2d96 100644
+--- sc/source/ui/inc/viewfunc.hxx
++++ sc/source/ui/inc/viewfunc.hxx
+@@ -69,6 +69,7 @@ class Exchange;
+ class ScRangeList;
+ class SvxHyperlinkItem;
+ class ScTransferObj;
++class ScTableProtection;
+ 
+ namespace com { namespace sun { namespace star { namespace datatransfer { class XTransferable; } } } }
+ 
+@@ -199,6 +200,8 @@ public:
+ 
+ 	void			ChangeIndent( BOOL bIncrement );
+ 
++	void			ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect );
++
+ 	void			Protect( SCTAB nTab, const String& rPassword );
+ 	BOOL			Unprotect( SCTAB nTab, const String& rPassword );
+ 
+diff --git sc/source/ui/miscdlgs/makefile.mk sc/source/ui/miscdlgs/makefile.mk
+index bb81bba..8fe1d6d 100644
+--- sc/source/ui/miscdlgs/makefile.mk
++++ sc/source/ui/miscdlgs/makefile.mk
+@@ -79,7 +79,9 @@ SLOFILES =  \
+ 	$(SLO)$/warnbox.obj	\
+ 	$(SLO)$/scuiautofmt.obj     \
+ 	$(SLO)$/conflictsdlg.obj    \
+-	$(SLO)$/sharedocdlg.obj
++	$(SLO)$/sharedocdlg.obj \
++	$(SLO)$/protectiondlg.obj \
++	$(SLO)$/retypepassdlg.obj
+ 
+ EXCEPTIONSFILES = \
+     $(SLO)$/acredlin.obj        \
+@@ -88,7 +90,9 @@ EXCEPTIONSFILES = \
+     $(SLO)$/optsolver.obj       \
+     $(SLO)$/solveroptions.obj   \
+     $(SLO)$/crnrdlg.obj         \
+-    $(SLO)$/solverutil.obj
++    $(SLO)$/solverutil.obj \
++    $(SLO)$/protectiondlg.obj \
++    $(SLO)$/retypepassdlg.obj
+ 
+ SRS1NAME=$(TARGET)
+ SRC1FILES = \
+@@ -97,7 +101,9 @@ SRC1FILES = \
+ 	highred.src					\
+ 	linkarea.src                \
+ 	conflictsdlg.src            \
+-	sharedocdlg.src
++	sharedocdlg.src \
++	protectiondlg.src \
++	retypepassdlg.src
+ 
+ LIB1TARGET = $(SLB)$/$(TARGET).lib
+ 
+@@ -119,7 +125,9 @@ LIB1OBJFILES =  \
+ 	$(SLO)$/conflictsdlg.obj    \
+ 	$(SLO)$/sharedocdlg.obj     \
+ 	$(SLO)$/scuiautofmt.obj			\
+-	$(SLO)$/strindlg.obj            
++	$(SLO)$/strindlg.obj \
++	$(SLO)$/protectiondlg.obj \
++	$(SLO)$/retypepassdlg.obj
+ 
+ # --- Tagets -------------------------------------------------------
+ 
+diff --git sc/source/ui/miscdlgs/protectiondlg.cxx sc/source/ui/miscdlgs/protectiondlg.cxx
+new file mode 100644
+index 0000000..ab77209
+--- /dev/null
++++ sc/source/ui/miscdlgs/protectiondlg.cxx
+@@ -0,0 +1,161 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: protectiondlg.cxx,v $
++ * $Revision: 1.1.2.6 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include "protectiondlg.hxx"
++#include "protectiondlg.hrc"
++#include "scresid.hxx"
++#include "tabprotection.hxx"
++
++#include <vcl/msgbox.hxx>
++
++
++// The order must match that of the list box.
++static const ScTableProtection::Option aOptions[] = {
++    ScTableProtection::SELECT_LOCKED_CELLS,
++    ScTableProtection::SELECT_UNLOCKED_CELLS,
++};
++static const USHORT nOptionCount = sizeof(aOptions)/sizeof(aOptions[0]);
++
++
++ScTableProtectionDlg::ScTableProtectionDlg(Window* pParent) :
++    ModalDialog(pParent, ScResId(RID_SCDLG_TABPROTECTION)),
++
++    maBtnProtect    (this, ScResId(BTN_PROTECT)),
++    maPassword1Text (this, ScResId(FT_PASSWORD1)),
++    maPassword1Edit (this, ScResId(ED_PASSWORD1)),
++    maPassword2Text (this, ScResId(FT_PASSWORD2)),
++    maPassword2Edit (this, ScResId(ED_PASSWORD2)),
++    maOptionsLine   (this, ScResId(FL_OPTIONS)),
++    maOptionsText   (this, ScResId(FT_OPTIONS)),
++    maOptionsListBox(this, ScResId(CLB_OPTIONS)),
++
++    maBtnOk     (this, ScResId(BTN_OK)),
++    maBtnCancel (this, ScResId(BTN_CANCEL)),
++    maBtnHelp   (this, ScResId(BTN_HELP)),
++
++    maSelectLockedCells(ScResId(ST_SELECT_LOCKED_CELLS)),
++    maSelectUnlockedCells(ScResId(ST_SELECT_UNLOCKED_CELLS))
++{
++    Init();
++    FreeResource();
++}
++
++ScTableProtectionDlg::~ScTableProtectionDlg()
++{
++}
++
++short ScTableProtectionDlg::Execute()
++{
++    return ModalDialog::Execute();
++}
++
++void ScTableProtectionDlg::SetDialogData(const ScTableProtection& rData)
++{
++    for (USHORT i = 0; i < nOptionCount; ++i)
++        maOptionsListBox.CheckEntryPos(i, rData.isOptionEnabled(aOptions[i]));
++}
++
++void ScTableProtectionDlg::WriteData(ScTableProtection& rData) const
++{
++    rData.setProtected(maBtnProtect.IsChecked());
++
++    // We assume that the two password texts match.
++    rData.setPassword(maPassword1Edit.GetText());
++
++    for (USHORT i = 0; i < nOptionCount; ++i)
++        rData.setOption(aOptions[i], maOptionsListBox.IsChecked(i));
++}
++
++void ScTableProtectionDlg::Init()
++{
++    Link aLink = LINK( this, ScTableProtectionDlg, CheckBoxHdl );
++    maBtnProtect.SetClickHdl(aLink);
++
++    aLink = LINK( this, ScTableProtectionDlg, OKHdl );
++    maBtnOk.SetClickHdl(aLink);
++
++    aLink = LINK( this, ScTableProtectionDlg, PasswordModifyHdl );
++    maPassword1Edit.SetModifyHdl(aLink);
++    maPassword2Edit.SetModifyHdl(aLink);
++
++    maOptionsListBox.SetUpdateMode(false);
++    maOptionsListBox.Clear();
++
++    maOptionsListBox.InsertEntry(maSelectLockedCells);
++    maOptionsListBox.InsertEntry(maSelectUnlockedCells);
++
++    maOptionsListBox.CheckEntryPos(0, true);
++    maOptionsListBox.CheckEntryPos(1, true);
++
++    maOptionsListBox.SetUpdateMode(true);
++
++    // Set the default state of the dialog.
++    maBtnProtect.Check(true);
++    maPassword1Edit.GrabFocus();
++}
++
++void ScTableProtectionDlg::EnableOptionalWidgets(bool bEnable)
++{
++    maPassword1Text.Enable(bEnable);
++    maPassword1Edit.Enable(bEnable);
++    maPassword2Text.Enable(bEnable);
++    maPassword2Edit.Enable(bEnable);
++    maOptionsLine.Enable(bEnable);
++    maOptionsText.Enable(bEnable);
++
++    maOptionsListBox.Enable(bEnable);
++    maOptionsListBox.Invalidate();
++}
++
++IMPL_LINK( ScTableProtectionDlg, CheckBoxHdl, CheckBox*, pBtn )
++{
++    if (pBtn == &maBtnProtect)
++    {
++        bool bChecked = maBtnProtect.IsChecked();
++        EnableOptionalWidgets(bChecked);
++        maBtnOk.Enable(bChecked);
++    }
++
++    return 0;
++}
++
++IMPL_LINK( ScTableProtectionDlg, OKHdl, OKButton*, EMPTYARG )
++{
++    EndDialog(RET_OK);
++    return 0;
++}
++
++IMPL_LINK( ScTableProtectionDlg, PasswordModifyHdl, Edit*, EMPTYARG )
++{
++    String aPass1 = maPassword1Edit.GetText();
++    String aPass2 = maPassword2Edit.GetText();
++    maBtnOk.Enable(aPass1.Equals(aPass2));
++    return 0;
++}
+diff --git sc/source/ui/miscdlgs/protectiondlg.src sc/source/ui/miscdlgs/protectiondlg.src
+new file mode 100644
+index 0000000..14a1c85
+--- /dev/null
++++ sc/source/ui/miscdlgs/protectiondlg.src
+@@ -0,0 +1,130 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: protectiondlg.src,v $
++ * $Revision: 1.1.2.6 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include "protectiondlg.hrc"
++
++ModalDialog RID_SCDLG_TABPROTECTION
++{
++    Text [ en-US ] = "Protect Sheet" ;
++    Size = MAP_APPFONT ( 220 , 135 ) ;
++    Moveable = TRUE ;
++    Closeable = TRUE ;
++
++    OKButton BTN_OK
++    {
++        Pos = MAP_APPFONT ( 164 , 6 ) ;
++        Size = MAP_APPFONT ( 50 , 14 ) ;
++        DefButton = TRUE ;
++    };
++    CancelButton BTN_CANCEL
++    {
++        Pos = MAP_APPFONT ( 164 , 23 ) ;
++        Size = MAP_APPFONT ( 50 , 14 ) ;
++    };
++    HelpButton BTN_HELP
++    {
++        Pos = MAP_APPFONT ( 164 , 43 ) ;
++        Size = MAP_APPFONT ( 50 , 14 ) ;
++    };
++
++    CheckBox BTN_PROTECT
++    {
++        Pos = MAP_APPFONT ( 6 , 6 ) ;
++        Size = MAP_APPFONT ( 150 , 10 );
++
++        Text [ en-US ] = "P~rotect this sheet and the contents of locked cells" ;
++    };
++
++    FixedText FT_PASSWORD1
++    {
++        Pos = MAP_APPFONT ( 11, 23 );
++        Size = MAP_APPFONT ( 42, 10 );
++
++        Text [ en-US ] = "~Password" ;
++    };
++
++    Edit ED_PASSWORD1
++    {
++        Border = TRUE;
++        PassWord = TRUE;
++        Pos = MAP_APPFONT ( 56, 22 );
++        Size = MAP_APPFONT ( 75, 12 );
++    };
++
++    FixedText FT_PASSWORD2
++    {
++        Pos = MAP_APPFONT ( 11, 40 );
++        Size = MAP_APPFONT ( 42, 10 );
++
++        Text [ en-US ] = "~Confirm" ;
++    };
++
++    Edit ED_PASSWORD2
++    {
++        Border = TRUE;
++        PassWord = TRUE;
++        Pos = MAP_APPFONT ( 56, 39 );
++        Size = MAP_APPFONT ( 75, 12 );
++    };
++
++    FixedLine FL_OPTIONS
++    {
++        Pos = MAP_APPFONT ( 6, 60 );
++        Size = MAP_APPFONT ( 150, 8 );
++
++        Text [ en-US ] = "Options";
++    };
++
++    FixedText FT_OPTIONS
++    {
++        Pos = MAP_APPFONT ( 11, 74 );
++        Size = MAP_APPFONT ( 140, 8 );
++
++        Text [ en-US ] = "Allow all users of this sheet to:";
++    };
++
++    Control CLB_OPTIONS
++    {
++        Pos = MAP_APPFONT ( 11, 85 );
++        Size = MAP_APPFONT ( 140, 40 );
++        Border = TRUE ;
++        TabStop = TRUE ;
++    };
++
++    String ST_SELECT_LOCKED_CELLS
++    {
++        Text [ en-US ] = "Select locked cells";
++    };
++
++    String ST_SELECT_UNLOCKED_CELLS
++    {
++        Text [ en-US ] = "Select unlocked cells";
++    };
++};
+diff --git sc/source/ui/miscdlgs/retypepassdlg.cxx sc/source/ui/miscdlgs/retypepassdlg.cxx
+new file mode 100644
+index 0000000..28b41b8
+--- /dev/null
++++ sc/source/ui/miscdlgs/retypepassdlg.cxx
+@@ -0,0 +1,544 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: retypepassdlg.cxx,v $
++ * $Revision: 1.1.2.7 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include "retypepassdlg.hxx"
++#include "retypepassdlg.hrc"
++#include "scresid.hxx"
++#include "document.hxx"
++#include "tabprotection.hxx"
++
++#include <stdio.h>
++
++#include <vcl/msgbox.hxx>
++
++ScRetypePassDlg::ScRetypePassDlg(Window* pParent) :
++    ModalDialog(pParent, ScResId(RID_SCDLG_RETYPEPASS)),
++
++    maBtnOk     (this, ScResId(BTN_OK)),
++    maBtnCancel (this, ScResId(BTN_CANCEL)),
++    maBtnHelp   (this, ScResId(BTN_HELP)),
++
++    maTextDescription(this, ScResId(FT_DESC)),
++    maLineDocument(this, ScResId(FL_DOCUMENT)),
++    maTextDocStatus(this, ScResId(FT_DOCSTATUS)),
++    maBtnRetypeDoc(this, ScResId(BTN_RETYPE_DOC)),
++
++    maLineSheet(this, ScResId(FL_SHEET)),
++    maTextSheetName1(this, ScResId(FT_SHEETNAME1)),
++    maTextSheetStatus1(this, ScResId(FT_SHEETSTATUS1)),
++    maBtnRetypeSheet1(this, ScResId(BTN_RETYPE_SHEET1)),
++
++    maTextSheetName2(this, ScResId(FT_SHEETNAME2)),
++    maTextSheetStatus2(this, ScResId(FT_SHEETSTATUS2)),
++    maBtnRetypeSheet2(this, ScResId(BTN_RETYPE_SHEET2)),
++
++    maTextSheetName3(this, ScResId(FT_SHEETNAME3)),
++    maTextSheetStatus3(this, ScResId(FT_SHEETSTATUS3)),
++    maBtnRetypeSheet3(this, ScResId(BTN_RETYPE_SHEET3)),
++
++    maTextSheetName4(this, ScResId(FT_SHEETNAME4)),
++    maTextSheetStatus4(this, ScResId(FT_SHEETSTATUS4)),
++    maBtnRetypeSheet4(this, ScResId(BTN_RETYPE_SHEET4)),
++
++    maScrollBar (this, ScResId(SB_SCROLL)),
++
++    maTextNotProtected(ScResId(STR_NOT_PROTECTED)),
++    maTextNotPassProtected(ScResId(STR_NOT_PASS_PROTECTED)),
++    maTextHashBad(ScResId(STR_HASH_BAD)),
++    maTextHashGood(ScResId(STR_HASH_GOOD)),
++    maTextHashRegen(ScResId(STR_HASH_REGENERATED)),
++
++    mpDocItem(static_cast<ScDocProtection*>(NULL)),
++    mnCurScrollPos(0),
++    meDesiredHash(PASSHASH_OOO)
++{
++    Init();
++}
++
++ScRetypePassDlg::~ScRetypePassDlg()
++{
++}
++
++short ScRetypePassDlg::Execute()
++{
++    PopulateDialog();
++    CheckHashStatus();
++    return ModalDialog::Execute();
++}
++
++void ScRetypePassDlg::SetData(const ScDocument& rDoc)
++{
++    const ScDocProtection* pDocProtect = rDoc.GetDocProtection();
++    if (pDocProtect && pDocProtect->isProtected())
++        mpDocItem.reset(new ScDocProtection(*pDocProtect));
++
++    SCTAB nTabCount = rDoc.GetTableCount();
++    maTableItems.reserve(nTabCount);
++    for (SCTAB i = 0; i < nTabCount; ++i)
++    {
++        TableItem aTabItem;
++        rDoc.GetName(i, aTabItem.maName);
++
++        const ScTableProtection* pTabProtect = rDoc.GetTabProtection(i);
++        if (pTabProtect && pTabProtect->isProtected())
++            aTabItem.mpProtect.reset(new ScTableProtection(*pTabProtect));
++
++        maTableItems.push_back(aTabItem);
++    }
++}
++
++void ScRetypePassDlg::SetDesiredHash(ScPasswordHash eHash)
++{
++    meDesiredHash = eHash;
++}
++
++void ScRetypePassDlg::WriteNewDataToDocument(ScDocument& rDoc) const
++{
++    if (mpDocItem.get())
++        rDoc.SetDocProtection(mpDocItem.get());
++
++    SCTAB nTabCount = rDoc.GetTableCount();
++    size_t n = maTableItems.size();
++    for (size_t i = 0; i < n; ++i)
++    {
++        if (i >= nTabCount)
++            break;
++
++        ScTableProtection* pTabProtect = maTableItems[i].mpProtect.get();
++        if (pTabProtect)
++            rDoc.SetTabProtection(static_cast<SCTAB>(i), pTabProtect);
++    }
++}
++
++void ScRetypePassDlg::Init()
++{
++    Link aLink = LINK( this, ScRetypePassDlg, OKHdl );
++    maBtnOk.SetClickHdl(aLink);
++
++    aLink = LINK( this, ScRetypePassDlg, RetypeBtnHdl );
++    maBtnRetypeDoc.SetClickHdl(aLink);
++    maBtnRetypeSheet1.SetClickHdl(aLink);
++    maBtnRetypeSheet2.SetClickHdl(aLink);
++    maBtnRetypeSheet3.SetClickHdl(aLink);
++    maBtnRetypeSheet4.SetClickHdl(aLink);
++
++    maTextDocStatus.SetText(maTextNotProtected);
++    maTextSheetStatus1.SetText(maTextNotProtected);
++    maTextSheetStatus2.SetText(maTextNotProtected);
++    maTextSheetStatus3.SetText(maTextNotProtected);
++    maTextSheetStatus4.SetText(maTextNotProtected);
++    maBtnRetypeDoc.Disable();
++
++    // Make all sheet rows invisible.
++
++    maTextSheetName1.Show(false);
++    maTextSheetStatus1.Show(false);
++    maBtnRetypeSheet1.Show(false);
++    maBtnRetypeSheet1.Disable();
++    
++    maTextSheetName2.Show(false);
++    maTextSheetStatus2.Show(false);
++    maBtnRetypeSheet2.Show(false);
++    maBtnRetypeSheet2.Disable();
++
++    maTextSheetName3.Show(false);
++    maTextSheetStatus3.Show(false);
++    maBtnRetypeSheet3.Show(false);
++    maBtnRetypeSheet3.Disable();
++
++    maTextSheetName4.Show(false);
++    maTextSheetStatus4.Show(false);
++    maBtnRetypeSheet4.Show(false);
++    maBtnRetypeSheet4.Disable();
++
++    maScrollBar.Show(false);
++
++    maScrollBar.SetEndScrollHdl( LINK( this, ScRetypePassDlg, ScrollHdl ) );
++    maScrollBar.SetScrollHdl( LINK( this, ScRetypePassDlg, ScrollHdl ) );
++
++    maScrollBar.SetPageSize(4);
++    maScrollBar.SetVisibleSize(4);
++    maScrollBar.SetLineSize(1);
++}
++
++void ScRetypePassDlg::PopulateDialog()
++{
++    // Document protection first.
++    SetDocData();
++
++    // Sheet protection next.  We're only interested in the first 4 sheets
++    // (or less).
++    size_t n = maTableItems.size();
++    for (size_t i = 0; i < n && i < 4; ++i)
++        SetTableData(i, i);
++
++    if (n > 4)
++    {
++        maScrollBar.Show(true);
++        maScrollBar.SetRange(Range(0, n));
++    }
++}
++
++void ScRetypePassDlg::SetDocData()
++{
++    bool bBtnEnabled = false;
++    if (mpDocItem.get() && mpDocItem->isProtected())
++    {
++        if (mpDocItem->isPasswordEmpty())
++            maTextDocStatus.SetText(maTextNotPassProtected);
++        else if (mpDocItem->hasPasswordHash(meDesiredHash))
++            maTextDocStatus.SetText(maTextHashGood);
++        else
++        {
++            // incompatible hash
++            maTextDocStatus.SetText(maTextHashBad);
++            bBtnEnabled = true;
++        }
++    }
++    maBtnRetypeDoc.Enable(bBtnEnabled);
++}
++
++void ScRetypePassDlg::SetTableData(sal_uInt8 nRowPos, SCTAB nTab)
++{
++    if (nRowPos >= 4)
++        return;
++
++    FixedText* pName = NULL;
++    FixedText* pStatus = NULL;
++    PushButton* pBtn = NULL;
++    switch (nRowPos)
++    {
++        case 0:
++            pName = &maTextSheetName1;
++            pStatus = &maTextSheetStatus1;
++            pBtn = &maBtnRetypeSheet1;
++        break;
++        case 1:
++            pName = &maTextSheetName2;
++            pStatus = &maTextSheetStatus2;
++            pBtn = &maBtnRetypeSheet2;
++        break;
++        case 2:
++            pName = &maTextSheetName3;
++            pStatus = &maTextSheetStatus3;
++            pBtn = &maBtnRetypeSheet3;
++        break;
++        case 3:
++            pName = &maTextSheetName4;
++            pStatus = &maTextSheetStatus4;
++            pBtn = &maBtnRetypeSheet4;
++        break;
++        default:
++            return;
++    }
++
++    bool bBtnEnabled = false;
++    pName->SetText(maTableItems[nTab].maName);
++    pName->Show(true);
++    const ScTableProtection* pTabProtect = maTableItems[nTab].mpProtect.get();
++    if (pTabProtect && pTabProtect->isProtected())
++    {
++        if (pTabProtect->isPasswordEmpty())
++            pStatus->SetText(maTextNotPassProtected);
++        else if (pTabProtect->hasPasswordHash(meDesiredHash))
++            pStatus->SetText(maTextHashGood);
++        else
++        {
++            // incompatible hash 
++            pStatus->SetText(maTextHashBad);
++            bBtnEnabled = true;
++        }
++    }
++    else
++        pStatus->SetText(maTextNotProtected);
++
++    pStatus->Show(true);
++    pBtn->Show(true);
++    pBtn->Enable(bBtnEnabled);
++}
++
++void ScRetypePassDlg::ResetTableRows()
++{
++    long nScrollPos = maScrollBar.GetThumbPos();
++    mnCurScrollPos = nScrollPos < 0 ? 0 : nScrollPos;
++    size_t nRowCount = maTableItems.size() - nScrollPos;
++    for (size_t i = 0; i < nRowCount; ++i)
++        SetTableData(i, i + nScrollPos);
++}
++
++bool lcl_IsInGoodStatus(ScPassHashProtectable* pProtected, ScPasswordHash eDesiredHash)
++{
++    if (!pProtected || !pProtected->isProtected())
++        // Not protected.
++        return true;
++
++    if (pProtected->isPasswordEmpty())
++        return true;
++
++    if (pProtected->hasPasswordHash(eDesiredHash))
++        return true;
++
++    return false;
++}
++
++void ScRetypePassDlg::CheckHashStatus()
++{
++    do
++    {
++        if (!lcl_IsInGoodStatus(mpDocItem.get(), meDesiredHash))
++            break;
++
++        bool bStatusGood = true;
++        size_t nTabCount = maTableItems.size();
++        for (size_t i = 0; i < nTabCount && bStatusGood; ++i)
++        {
++            if (!lcl_IsInGoodStatus(maTableItems[i].mpProtect.get(), meDesiredHash))
++                bStatusGood = false;
++        }
++        if (!bStatusGood)
++            break;
++
++        maBtnOk.Enable();
++        return;
++    }
++    while (false);
++
++    maBtnOk.Disable();
++}
++
++IMPL_LINK( ScRetypePassDlg, OKHdl, OKButton*, EMPTYARG )
++{
++    EndDialog(RET_OK);
++    return 0;
++}
++
++IMPL_LINK( ScRetypePassDlg, RetypeBtnHdl, PushButton*, pBtn )
++{
++    ScPassHashProtectable* pProtected = NULL;
++    if (pBtn == &maBtnRetypeDoc)
++    {
++        // document protection.
++        pProtected = mpDocItem.get();
++    }
++    else
++    {
++        // sheet protection.
++        size_t nTabPos = mnCurScrollPos;
++        if (pBtn == &maBtnRetypeSheet2)
++            nTabPos += 1;
++        else if (pBtn == &maBtnRetypeSheet3)
++            nTabPos += 2;
++        else if (pBtn == &maBtnRetypeSheet4)
++            nTabPos += 3;
++        else if (pBtn != &maBtnRetypeSheet1)
++            // This should never happen !
++            return 0;
++
++        if (nTabPos >= maTableItems.size())
++            // Likewise, this should never happen !
++            return 0;
++
++        pProtected = maTableItems[nTabPos].mpProtect.get();
++    }
++
++    if (!pProtected)
++        // What the ... !?
++        return 0;
++
++    ScRetypePassInputDlg aDlg(this, pProtected);
++    if (aDlg.Execute() == RET_OK)
++    {
++        // OK is pressed.  Update the protected item.
++        if (aDlg.IsRemovePassword())
++        {
++            // Remove password from this item.
++            pProtected->setPassword(String());
++        }
++        else
++        {
++            // Set a new password.
++            String aNewPass = aDlg.GetNewPassword();
++            pProtected->setPassword(aNewPass);
++        }
++
++        SetDocData();
++        ResetTableRows();
++        CheckHashStatus();
++    }
++    return 0;
++}
++
++IMPL_LINK( ScRetypePassDlg, ScrollHdl, ScrollBar*, EMPTYARG )
++{
++    ResetTableRows();
++    return 0;
++}
++
++// ============================================================================
++
++ScRetypePassInputDlg::ScRetypePassInputDlg(Window* pParent, ScPassHashProtectable* pProtected) :
++    ModalDialog(pParent, ScResId(RID_SCDLG_RETYPEPASS_INPUT)),
++
++    maBtnOk     (this, ScResId(BTN_OK)),
++    maBtnCancel (this, ScResId(BTN_CANCEL)),
++    maBtnHelp   (this, ScResId(BTN_HELP)),
++
++    maBtnRetypePassword(this, ScResId(BTN_RETYPE_PASSWORD)),
++
++    maPassword1Text (this, ScResId(FT_PASSWORD1)),
++    maPassword1Edit (this, ScResId(ED_PASSWORD1)),
++    maPassword2Text (this, ScResId(FT_PASSWORD2)),
++    maPassword2Edit (this, ScResId(ED_PASSWORD2)),
++    maBtnMatchOldPass(this, ScResId(BTN_MATCH_OLD_PASSWORD)),
++
++    maBtnRemovePassword(this, ScResId(BTN_REMOVE_PASSWORD)),
++
++    mpProtected(pProtected)
++{
++    Init();
++}
++
++ScRetypePassInputDlg::~ScRetypePassInputDlg()
++{
++}
++
++short ScRetypePassInputDlg::Execute()
++{
++    return ModalDialog::Execute();
++}
++
++bool ScRetypePassInputDlg::IsRemovePassword() const
++{
++    return maBtnRemovePassword.IsChecked();
++}
++
++String ScRetypePassInputDlg::GetNewPassword() const
++{
++    return maPassword1Edit.GetText();
++}
++
++void ScRetypePassInputDlg::Init()
++{
++    Link aLink = LINK( this, ScRetypePassInputDlg, OKHdl );
++    maBtnOk.SetClickHdl(aLink);
++    aLink = LINK( this, ScRetypePassInputDlg, RadioBtnHdl );
++    maBtnRetypePassword.SetClickHdl(aLink);
++    maBtnRemovePassword.SetClickHdl(aLink);
++    aLink = LINK( this, ScRetypePassInputDlg, CheckBoxHdl );
++    maBtnMatchOldPass.SetClickHdl(aLink);
++    aLink = LINK( this, ScRetypePassInputDlg, PasswordModifyHdl );
++    maPassword1Edit.SetModifyHdl(aLink);
++    maPassword2Edit.SetModifyHdl(aLink);
++
++    maBtnOk.Disable();
++    maBtnRetypePassword.Check(true);
++    maBtnMatchOldPass.Check(true);
++    maPassword1Edit.GrabFocus();
++}
++
++void ScRetypePassInputDlg::CheckPasswordInput()
++{
++    String aPass1 = maPassword1Edit.GetText();
++    String aPass2 = maPassword2Edit.GetText();
++
++    if (!aPass1.Len() || !aPass2.Len())
++    {
++        // Empty password is not allowed.
++        maBtnOk.Disable();
++        return;
++    }
++
++    if (!aPass1.Equals(aPass2))
++    {
++        // The two passwords differ.
++        maBtnOk.Disable();
++        return;
++    }
++
++    if (!maBtnMatchOldPass.IsChecked())
++    {
++        maBtnOk.Enable();
++        return;
++    }
++
++    if (!mpProtected)
++    {
++        // This should never happen!
++        maBtnOk.Disable();
++        return;
++    }
++
++    bool bPassGood = mpProtected->verifyPassword(aPass1);
++    maBtnOk.Enable(bPassGood);
++}
++
++IMPL_LINK( ScRetypePassInputDlg, OKHdl, OKButton*, EMPTYARG )
++{
++    EndDialog(RET_OK);
++    return 0;
++}
++
++IMPL_LINK( ScRetypePassInputDlg, RadioBtnHdl, RadioButton*, pBtn )
++{
++    if (pBtn == &maBtnRetypePassword)
++    {
++        maBtnRemovePassword.Check(false);
++        maPassword1Text.Enable();
++        maPassword1Edit.Enable();
++        maPassword2Text.Enable();
++        maPassword2Edit.Enable();
++        maBtnMatchOldPass.Enable();
++        CheckPasswordInput();
++    }
++    else if (pBtn == &maBtnRemovePassword)
++    {
++        maBtnRetypePassword.Check(false);
++        maPassword1Text.Disable();
++        maPassword1Edit.Disable();
++        maPassword2Text.Disable();
++        maPassword2Edit.Disable();
++        maBtnMatchOldPass.Disable();
++        maBtnOk.Enable();
++    }
++
++    return 0;
++}
++
++IMPL_LINK( ScRetypePassInputDlg, CheckBoxHdl, CheckBox*, pBtn )
++{
++    CheckPasswordInput();
++    return 0;
++}
++
++IMPL_LINK( ScRetypePassInputDlg, PasswordModifyHdl, Edit*, pEdit )
++{
++    CheckPasswordInput();
++    return 0;
++}
+diff --git sc/source/ui/miscdlgs/retypepassdlg.src sc/source/ui/miscdlgs/retypepassdlg.src
+new file mode 100644
+index 0000000..60ccfec
+--- /dev/null
++++ sc/source/ui/miscdlgs/retypepassdlg.src
+@@ -0,0 +1,316 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: retypepassdlg.src,v $
++ * $Revision: 1.1.2.3 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#include "retypepassdlg.hrc"
++
++
++ModalDialog RID_SCDLG_RETYPEPASS
++{
++    Text [ en-US ] = "Re-type Password" ;
++    Size = MAP_APPFONT ( 260 , 165 ) ;
++    Moveable = TRUE ;
++    Closeable = TRUE ;
++
++    OKButton BTN_OK
++    {
++        Pos = MAP_APPFONT ( 204, 6 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++        DefButton = TRUE ;
++    };
++
++    CancelButton BTN_CANCEL
++    {
++        Pos = MAP_APPFONT ( 204, 23 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++    };
++
++    HelpButton BTN_HELP
++    {
++        Pos = MAP_APPFONT ( 204, 43 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++    };
++
++    FixedText FT_DESC
++    {
++        Pos = MAP_APPFONT ( 6, 6 ) ;
++        Size = MAP_APPFONT ( 190, 36 );
++
++        WordBreak = TRUE ;
++
++        Text [ en-US ] = "The document you are about to export has one or more protected items with password that cannot be exported.  Please re-type your password to be able to export your document." ;
++    };
++
++    FixedLine FL_DOCUMENT
++    {
++        Pos = MAP_APPFONT ( 6, 48 );
++        Size = MAP_APPFONT ( 190, 8 );
++
++        Text [ en-US ] = "Document protection" ;
++    };
++
++    FixedText FT_DOCSTATUS
++    {
++        Pos = MAP_APPFONT ( 10, 62 );
++        Size = MAP_APPFONT ( 140, 8 );
++
++        Text [ en-US ] = "Status unknown" ;
++    };
++
++    PushButton BTN_RETYPE_DOC
++    {
++        Pos = MAP_APPFONT ( 158, 59 );
++        Size = MAP_APPFONT ( 30, 14 );
++
++        Text [ en-US ] = "Re-type" ;
++    };
++
++    FixedLine FL_SHEET
++    {
++        Pos = MAP_APPFONT ( 6, 83 );
++        Size = MAP_APPFONT ( 190, 8 );
++
++        Text [ en-US ] = "Sheet protection" ;
++    };
++
++    FixedText FT_SHEETNAME1
++    {
++        Pos = MAP_APPFONT ( 10, 97 );
++        Size = MAP_APPFONT ( 68, 8 );
++
++        Text [ en-US ] = "Sheet1 has a really long name" ;
++    };
++
++    FixedText FT_SHEETSTATUS1
++    {
++        Pos = MAP_APPFONT ( 82, 97 );
++        Size = MAP_APPFONT ( 72, 8 );
++
++        Text [ en-US ] = "Status unknown" ;
++    };
++
++    PushButton BTN_RETYPE_SHEET1
++    {
++        Pos = MAP_APPFONT ( 158, 94 );
++        Size = MAP_APPFONT ( 30, 14 );
++
++        Text [ en-US ] = "Re-type" ;
++    };
++
++    FixedText FT_SHEETNAME2
++    {
++        Pos = MAP_APPFONT ( 10, 113 );
++        Size = MAP_APPFONT ( 68, 8 );
++
++        Text [ en-US ] = "Sheet2" ;
++    };
++
++    FixedText FT_SHEETSTATUS2
++    {
++        Pos = MAP_APPFONT ( 82, 113 );
++        Size = MAP_APPFONT ( 72, 8 );
++
++        Text [ en-US ] = "Status unknown" ;
++    };
++
++    PushButton BTN_RETYPE_SHEET2
++    {
++        Pos = MAP_APPFONT ( 158, 110 );
++        Size = MAP_APPFONT ( 30, 14 );
++
++        Text [ en-US ] = "Re-type" ;
++    };
++
++    FixedText FT_SHEETNAME3
++    {
++        Pos = MAP_APPFONT ( 10, 129 );
++        Size = MAP_APPFONT ( 68, 8 );
++
++        Text [ en-US ] = "Sheet3" ;
++    };
++
++    FixedText FT_SHEETSTATUS3
++    {
++        Pos = MAP_APPFONT ( 82, 129 );
++        Size = MAP_APPFONT ( 72, 8 );
++
++        Text [ en-US ] = "Status unknown" ;
++    };
++
++    PushButton BTN_RETYPE_SHEET3
++    {
++        Pos = MAP_APPFONT ( 158, 126 );
++        Size = MAP_APPFONT ( 30, 14 );
++
++        Text [ en-US ] = "Re-type" ;
++    };
++
++    FixedText FT_SHEETNAME4
++    {
++        Pos = MAP_APPFONT ( 10, 145 );
++        Size = MAP_APPFONT ( 68, 8 );
++
++        Text [ en-US ] = "Sheet4" ;
++    };
++
++    FixedText FT_SHEETSTATUS4
++    {
++        Pos = MAP_APPFONT ( 82, 145 );
++        Size = MAP_APPFONT ( 72, 8 );
++
++        Text [ en-US ] = "Status unknown" ;
++    };
++
++    PushButton BTN_RETYPE_SHEET4
++    {
++        Pos = MAP_APPFONT ( 158, 142 );
++        Size = MAP_APPFONT ( 30, 14 );
++
++        Text [ en-US ] = "Re-type" ;
++    };
++
++    ScrollBar SB_SCROLL
++    {
++        Pos = MAP_APPFONT ( 190, 94 ) ;
++        Size = MAP_APPFONT (  8, 61 ) ;
++        VScroll = TRUE ;
++    };
++
++    String STR_NOT_PROTECTED
++    {
++        Text [ en-US ] = "Not protected" ;
++    };
++
++    String STR_NOT_PASS_PROTECTED
++    {
++        Text [ en-US ] = "Not password-protected" ;
++    };
++
++    String STR_HASH_BAD
++    {
++        Text [ en-US ] = "Hash incompatible" ;
++    };
++
++    String STR_HASH_GOOD
++    {
++        Text [ en-US ] = "Hash compatible" ;
++    };
++
++    String STR_HASH_REGENERATED
++    {
++        Text [ en-US ] = "Hash re-generated" ;
++    };
++};
++
++// ----------------------------------------------------------------------------
++
++ModalDialog RID_SCDLG_RETYPEPASS_INPUT
++{
++    Text [ en-US ] = "Re-type Password" ;
++    Size = MAP_APPFONT ( 230 , 110 ) ;
++    Moveable = TRUE ;
++    Closeable = TRUE ;
++
++    OKButton BTN_OK
++    {
++        Pos = MAP_APPFONT ( 174, 6 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++        DefButton = TRUE ;
++    };
++
++    CancelButton BTN_CANCEL
++    {
++        Pos = MAP_APPFONT ( 174, 23 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++    };
++
++    HelpButton BTN_HELP
++    {
++        Pos = MAP_APPFONT ( 174, 43 ) ;
++        Size = MAP_APPFONT ( 50, 14 ) ;
++    };
++
++    RadioButton BTN_RETYPE_PASSWORD
++    {
++        Pos = MAP_APPFONT ( 11, 10 );
++        Size = MAP_APPFONT ( 150, 10 );
++
++        Text [ en-US ] = "Re-type password" ;
++    };
++
++    FixedText FT_PASSWORD1
++    {
++        Pos = MAP_APPFONT ( 20, 30 );
++        Size = MAP_APPFONT ( 42, 10 );
++
++        Text [ en-US ] = "~Password" ;
++    };
++
++    Edit ED_PASSWORD1
++    {
++        Border = TRUE;
++        PassWord = TRUE;
++        Pos = MAP_APPFONT ( 65, 29 );
++        Size = MAP_APPFONT ( 75, 12 );
++    };
++
++    FixedText FT_PASSWORD2
++    {
++        Pos = MAP_APPFONT ( 20, 45 );
++        Size = MAP_APPFONT ( 42, 10 );
++
++        Text [ en-US ] = "~Confirm" ;
++    };
++
++    Edit ED_PASSWORD2
++    {
++        Border = TRUE;
++        PassWord = TRUE;
++        Pos = MAP_APPFONT ( 65, 44 );
++        Size = MAP_APPFONT ( 75, 12 );
++    };
++
++    CheckBox BTN_MATCH_OLD_PASSWORD
++    {
++        Pos = MAP_APPFONT ( 20, 65 );
++        Size = MAP_APPFONT ( 150, 10 );
++
++        Text [ en-US ] = "New password must match the original password." ;
++    };
++
++    RadioButton BTN_REMOVE_PASSWORD
++    {
++        Pos = MAP_APPFONT ( 11, 90 );
++        Size = MAP_APPFONT ( 150, 10 );
++
++        Text [ en-US ] = "Remove password from this protected item." ;
++    };
++};
++
++
+diff --git sc/source/ui/undo/undotab.cxx sc/source/ui/undo/undotab.cxx
+index 3585c74..0ac648d 100644
+--- sc/source/ui/undo/undotab.cxx
++++ sc/source/ui/undo/undotab.cxx
+@@ -61,6 +61,7 @@
+ #include "prnsave.hxx"
+ #include "printfun.hxx"
+ #include "chgtrack.hxx"
++#include "tabprotection.hxx"
+ 
+ // for ScUndoRenameObject - might me moved to another file later
+ #include <svx/svditer.hxx>
+@@ -72,6 +73,8 @@
+ extern BOOL bDrawIsInUndo;			//! irgendwo als Member !!!
+ 
+ using namespace com::sun::star;
++using ::com::sun::star::uno::Sequence;
++using ::std::auto_ptr;
+ 
+ // STATIC DATA -----------------------------------------------------------
+ 
+@@ -85,7 +88,6 @@ TYPEINIT1(ScUndoMakeScenario,	SfxUndoAction);
+ TYPEINIT1(ScUndoImportTab,		SfxUndoAction);
+ TYPEINIT1(ScUndoRemoveLink,		SfxUndoAction);
+ TYPEINIT1(ScUndoShowHideTab,	SfxUndoAction);
+-TYPEINIT1(ScUndoProtect,		SfxUndoAction);
+ TYPEINIT1(ScUndoPrintRange,		SfxUndoAction);
+ TYPEINIT1(ScUndoScenarioFlags,	SfxUndoAction);
+ TYPEINIT1(ScUndoRenameObject,	SfxUndoAction);
+@@ -112,12 +114,12 @@ ScUndoInsertTab::ScUndoInsertTab( ScDocShell* pNewDocShell,
+ 	SetChangeTrack();
+ }
+ 
+-__EXPORT ScUndoInsertTab::~ScUndoInsertTab()
++ScUndoInsertTab::~ScUndoInsertTab()
+ {
+ 	DeleteSdrUndoAction( pDrawUndo );
+ }
+ 
+-String __EXPORT ScUndoInsertTab::GetComment() const
++String ScUndoInsertTab::GetComment() const
+ {
+ 	if (bAppend)
+ 		return ScGlobal::GetRscString( STR_UNDO_APPEND_TAB );
+@@ -138,7 +140,7 @@ void ScUndoInsertTab::SetChangeTrack()
+ 		nEndChangeAction = 0;
+ }
+ 
+-void __EXPORT ScUndoInsertTab::Undo()
++void ScUndoInsertTab::Undo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 	pViewShell->SetTabNo(nTab);
+@@ -159,7 +161,7 @@ void __EXPORT ScUndoInsertTab::Undo()
+ 	pDocShell->Broadcast( SfxSimpleHint( SC_HINT_FORCESETTAB ) );
+ }
+ 
+-void __EXPORT ScUndoInsertTab::Redo()
++void ScUndoInsertTab::Redo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 
+@@ -180,14 +182,14 @@ void __EXPORT ScUndoInsertTab::Redo()
+ 	SetChangeTrack();
+ }
+ 
+-void __EXPORT ScUndoInsertTab::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoInsertTab::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 		((ScTabViewTarget&)rTarget).GetViewShell()->GetViewData()->GetDispatcher().
+ 			Execute(FID_INS_TABLE, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD);
+ }
+ 
+-BOOL __EXPORT ScUndoInsertTab::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoInsertTab::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+@@ -211,7 +213,7 @@ ScUndoInsertTables::ScUndoInsertTables( ScDocShell* pNewDocShell,
+ 	SetChangeTrack();
+ }
+ 
+-__EXPORT ScUndoInsertTables::~ScUndoInsertTables()
++ScUndoInsertTables::~ScUndoInsertTables()
+ {
+ 	String *pStr=NULL;
+ 	if(pNameList!=NULL)
+@@ -227,7 +229,7 @@ __EXPORT ScUndoInsertTables::~ScUndoInsertTables()
+ 	DeleteSdrUndoAction( pDrawUndo );
+ }
+ 
+-String __EXPORT ScUndoInsertTables::GetComment() const
++String ScUndoInsertTables::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_INSERT_TAB );
+ }
+@@ -252,7 +254,7 @@ void ScUndoInsertTables::SetChangeTrack()
+ 		nStartChangeAction = nEndChangeAction = 0;
+ }
+ 
+-void __EXPORT ScUndoInsertTables::Undo()
++void ScUndoInsertTables::Undo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 	pViewShell->SetTabNo(nTab);
+@@ -282,7 +284,7 @@ void __EXPORT ScUndoInsertTables::Undo()
+ 	pDocShell->Broadcast( SfxSimpleHint( SC_HINT_FORCESETTAB ) );
+ }
+ 
+-void __EXPORT ScUndoInsertTables::Redo()
++void ScUndoInsertTables::Redo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 
+@@ -299,14 +301,14 @@ void __EXPORT ScUndoInsertTables::Redo()
+ 	SetChangeTrack();
+ }
+ 
+-void __EXPORT ScUndoInsertTables::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoInsertTables::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 		((ScTabViewTarget&)rTarget).GetViewShell()->GetViewData()->GetDispatcher().
+ 			Execute(FID_INS_TABLE, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD);
+ }
+ 
+-BOOL __EXPORT ScUndoInsertTables::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoInsertTables::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+@@ -327,12 +329,12 @@ ScUndoDeleteTab::ScUndoDeleteTab( ScDocShell* pNewDocShell,const SvShorts &aTab,
+ 		SetChangeTrack();
+ }
+ 
+-__EXPORT ScUndoDeleteTab::~ScUndoDeleteTab()
++ScUndoDeleteTab::~ScUndoDeleteTab()
+ {
+ 	theTabs.Remove(0,theTabs.Count());
+ }
+ 
+-String __EXPORT ScUndoDeleteTab::GetComment() const
++String ScUndoDeleteTab::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_DELETE_TAB );
+ }
+@@ -366,7 +368,7 @@ SCTAB lcl_GetVisibleTabBefore( ScDocument& rDoc, SCTAB nTab )
+ 	return nTab;
+ }
+ 
+-void __EXPORT ScUndoDeleteTab::Undo()
++void ScUndoDeleteTab::Undo()
+ {
+ 	BeginUndo();
+ 	int i=0;
+@@ -414,7 +416,7 @@ void __EXPORT ScUndoDeleteTab::Undo()
+             pDoc->SetVisible( nTab, pRefUndoDoc->IsVisible( nTab ) );
+ 
+             if ( pRefUndoDoc->IsTabProtected( nTab ) )
+-                pDoc->SetTabProtection( nTab, TRUE, pRefUndoDoc->GetTabPassword( nTab ) );
++                pDoc->SetTabProtection(nTab, pRefUndoDoc->GetTabProtection(nTab));
+ 
+ 			//	Drawing-Layer passiert beim MoveUndo::EndUndo
+ 	//		pDoc->TransferDrawPage(pRefUndoDoc, nTab,nTab);
+@@ -450,7 +452,7 @@ void __EXPORT ScUndoDeleteTab::Undo()
+ //	EndUndo();
+ }
+ 
+-void __EXPORT ScUndoDeleteTab::Redo()
++void ScUndoDeleteTab::Redo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 	pViewShell->SetTabNo( lcl_GetVisibleTabBefore( *pDocShell->GetDocument(), theTabs[0] ) );
+@@ -469,7 +471,7 @@ void __EXPORT ScUndoDeleteTab::Redo()
+ 	pDocShell->Broadcast( SfxSimpleHint( SC_HINT_FORCESETTAB ) );
+ }
+ 
+-void __EXPORT ScUndoDeleteTab::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoDeleteTab::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 	{
+@@ -478,7 +480,7 @@ void __EXPORT ScUndoDeleteTab::Repeat(SfxRepeatTarget& rTarget)
+ 	}
+ }
+ 
+-BOOL __EXPORT ScUndoDeleteTab::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoDeleteTab::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+@@ -500,11 +502,11 @@ ScUndoRenameTab::ScUndoRenameTab( ScDocShell* pNewDocShell,
+ 	sNewName = rNewName;
+ }
+ 
+-__EXPORT ScUndoRenameTab::~ScUndoRenameTab()
++ScUndoRenameTab::~ScUndoRenameTab()
+ {
+ }
+ 
+-String __EXPORT ScUndoRenameTab::GetComment() const
++String ScUndoRenameTab::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_RENAME_TAB );
+ }
+@@ -526,22 +528,22 @@ void ScUndoRenameTab::DoChange( SCTAB nTabP, const String& rName ) const
+ 		pViewShell->UpdateInputHandler();
+ }
+ 
+-void __EXPORT ScUndoRenameTab::Undo()
++void ScUndoRenameTab::Undo()
+ {
+ 	DoChange(nTab, sOldName);
+ }
+ 
+-void __EXPORT ScUndoRenameTab::Redo()
++void ScUndoRenameTab::Redo()
+ {
+ 	DoChange(nTab, sNewName);
+ }
+ 
+-void __EXPORT ScUndoRenameTab::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoRenameTab::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 	//	Repeat macht keinen Sinn
+ }
+ 
+-BOOL __EXPORT ScUndoRenameTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoRenameTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;
+ }
+@@ -565,13 +567,13 @@ ScUndoMoveTab::ScUndoMoveTab( ScDocShell* pNewDocShell,
+         theNewTabs.Insert(aNewTab[sal::static_int_cast<USHORT>(i)],theNewTabs.Count());
+ }
+ 
+-__EXPORT ScUndoMoveTab::~ScUndoMoveTab()
++ScUndoMoveTab::~ScUndoMoveTab()
+ {
+ 	theNewTabs.Remove(0,theNewTabs.Count());
+ 	theOldTabs.Remove(0,theOldTabs.Count());
+ }
+ 
+-String __EXPORT ScUndoMoveTab::GetComment() const
++String ScUndoMoveTab::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_MOVE_TAB );
+ }
+@@ -618,22 +620,22 @@ void ScUndoMoveTab::DoChange( BOOL bUndo ) const
+ 	pDocShell->PostDataChanged();
+ }
+ 
+-void __EXPORT ScUndoMoveTab::Undo()
++void ScUndoMoveTab::Undo()
+ {
+ 	DoChange( TRUE );
+ }
+ 
+-void __EXPORT ScUndoMoveTab::Redo()
++void ScUndoMoveTab::Redo()
+ {
+ 	DoChange( FALSE );
+ }
+ 
+-void __EXPORT ScUndoMoveTab::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoMoveTab::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 		// kein Repeat ! ? !
+ }
+ 
+-BOOL __EXPORT ScUndoMoveTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoMoveTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;
+ }
+@@ -660,12 +662,12 @@ ScUndoCopyTab::ScUndoCopyTab( ScDocShell* pNewDocShell,
+         theNewTabs.Insert(aNewTab[sal::static_int_cast<USHORT>(i)],theNewTabs.Count());
+ }
+ 
+-__EXPORT ScUndoCopyTab::~ScUndoCopyTab()
++ScUndoCopyTab::~ScUndoCopyTab()
+ {
+ 	DeleteSdrUndoAction( pDrawUndo );
+ }
+ 
+-String __EXPORT ScUndoCopyTab::GetComment() const
++String ScUndoCopyTab::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_COPY_TAB );
+ }
+@@ -684,7 +686,7 @@ void ScUndoCopyTab::DoChange() const
+ 	pDocShell->PostDataChanged();
+ }
+ 
+-void __EXPORT ScUndoCopyTab::Undo()
++void ScUndoCopyTab::Undo()
+ {
+ 	ScDocument* pDoc = pDocShell->GetDocument();
+ 
+@@ -717,7 +719,7 @@ void __EXPORT ScUndoCopyTab::Undo()
+ 	DoChange();
+ }
+ 
+-void __EXPORT ScUndoCopyTab::Redo()
++void ScUndoCopyTab::Redo()
+ {
+ 	ScDocument* pDoc = pDocShell->GetDocument();
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+@@ -756,7 +758,7 @@ void __EXPORT ScUndoCopyTab::Redo()
+ 		}
+ 
+ 		if ( pDoc->IsTabProtected( nAdjSource ) )
+-			pDoc->SetTabProtection( nNewTab, TRUE, pDoc->GetTabPassword( nAdjSource ) );
++            pDoc->CopyTabProtection(nAdjSource, nNewTab);
+ 	}
+ 
+     RedoSdrUndoAction( pDrawUndo );             // after the sheets are inserted
+@@ -767,12 +769,12 @@ void __EXPORT ScUndoCopyTab::Redo()
+ 
+ }
+ 
+-void __EXPORT ScUndoCopyTab::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoCopyTab::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 		// kein Repeat ! ? !
+ }
+ 
+-BOOL __EXPORT ScUndoCopyTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoCopyTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;
+ }
+@@ -801,17 +803,17 @@ ScUndoMakeScenario::ScUndoMakeScenario( ScDocShell* pNewDocShell,
+     pDrawUndo = GetSdrUndoAction( pDocShell->GetDocument() );
+ }
+ 
+-__EXPORT ScUndoMakeScenario::~ScUndoMakeScenario()
++ScUndoMakeScenario::~ScUndoMakeScenario()
+ {
+     DeleteSdrUndoAction( pDrawUndo );
+ }
+ 
+-String __EXPORT ScUndoMakeScenario::GetComment() const
++String ScUndoMakeScenario::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_MAKESCENARIO );
+ }
+ 
+-void __EXPORT ScUndoMakeScenario::Undo()
++void ScUndoMakeScenario::Undo()
+ {
+ 	ScDocument* pDoc = pDocShell->GetDocument();
+ 
+@@ -836,7 +838,7 @@ void __EXPORT ScUndoMakeScenario::Undo()
+     pDocShell->Broadcast( SfxSimpleHint( SC_HINT_FORCESETTAB ) );
+ }
+ 
+-void __EXPORT ScUndoMakeScenario::Redo()
++void ScUndoMakeScenario::Redo()
+ {
+ 	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ 	if (pViewShell)
+@@ -858,7 +860,7 @@ void __EXPORT ScUndoMakeScenario::Redo()
+ 	SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
+ }
+ 
+-void __EXPORT ScUndoMakeScenario::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoMakeScenario::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 	{
+@@ -866,7 +868,7 @@ void __EXPORT ScUndoMakeScenario::Repeat(SfxRepeatTarget& rTarget)
+ 	}
+ }
+ 
+-BOOL __EXPORT ScUndoMakeScenario::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoMakeScenario::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+@@ -889,13 +891,13 @@ ScUndoImportTab::ScUndoImportTab( ScDocShell* pShell,
+ 	pDrawUndo = GetSdrUndoAction( pDocShell->GetDocument() );
+ }
+ 
+-__EXPORT ScUndoImportTab::~ScUndoImportTab()
++ScUndoImportTab::~ScUndoImportTab()
+ {
+ 	delete pRedoDoc;
+ 	DeleteSdrUndoAction( pDrawUndo );
+ }
+ 
+-String __EXPORT ScUndoImportTab::GetComment() const
++String ScUndoImportTab::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_INSERT_TAB );
+ }
+@@ -922,7 +924,7 @@ void ScUndoImportTab::DoChange() const
+ 								PAINT_GRID | PAINT_TOP | PAINT_LEFT | PAINT_EXTRAS );
+ }
+ 
+-void __EXPORT ScUndoImportTab::Undo()
++void ScUndoImportTab::Undo()
+ {
+ 	//!	eingefuegte Bereichsnamen etc.
+ 
+@@ -958,7 +960,7 @@ void __EXPORT ScUndoImportTab::Undo()
+ 			}
+ 
+ 			if ( pDoc->IsTabProtected( nTabPos ) )
+-				pRedoDoc->SetTabProtection( nTabPos, TRUE, pDoc->GetTabPassword( nTabPos ) );
++                pRedoDoc->SetTabProtection(nTabPos, pDoc->GetTabProtection(nTabPos));
+ 		}
+ 
+ 	}
+@@ -973,7 +975,7 @@ void __EXPORT ScUndoImportTab::Undo()
+ 	DoChange();
+ }
+ 
+-void __EXPORT ScUndoImportTab::Redo()
++void ScUndoImportTab::Redo()
+ {
+ 	if (!pRedoDoc)
+ 	{
+@@ -1012,7 +1014,7 @@ void __EXPORT ScUndoImportTab::Redo()
+ 		}
+ 
+ 		if ( pRedoDoc->IsTabProtected( nTabPos ) )
+-			pDoc->SetTabProtection( nTabPos, TRUE, pRedoDoc->GetTabPassword( nTabPos ) );
++            pDoc->SetTabProtection(nTabPos, pRedoDoc->GetTabProtection(nTabPos));
+ 	}
+ 
+     RedoSdrUndoAction( pDrawUndo );     // after the sheets are inserted
+@@ -1020,14 +1022,14 @@ void __EXPORT ScUndoImportTab::Redo()
+ 	DoChange();
+ }
+ 
+-void __EXPORT ScUndoImportTab::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoImportTab::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 		((ScTabViewTarget&)rTarget).GetViewShell()->GetViewData()->GetDispatcher().
+ 			Execute(FID_INS_TABLE, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD);
+ }
+ 
+-BOOL __EXPORT ScUndoImportTab::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoImportTab::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+@@ -1075,14 +1077,14 @@ ScUndoRemoveLink::ScUndoRemoveLink( ScDocShell* pShell, const String& rDoc ) :
+ 	}
+ }
+ 
+-__EXPORT ScUndoRemoveLink::~ScUndoRemoveLink()
++ScUndoRemoveLink::~ScUndoRemoveLink()
+ {
+ 	delete pTabs;
+ 	delete pModes;
+ 	delete[] pTabNames;
+ }
+ 
+-String __EXPORT ScUndoRemoveLink::GetComment() const
++String ScUndoRemoveLink::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_REMOVELINK );
+ }
+@@ -1099,22 +1101,22 @@ void ScUndoRemoveLink::DoChange( BOOL bLink ) const
+ 	pDocShell->UpdateLinks();
+ }
+ 
+-void __EXPORT ScUndoRemoveLink::Undo()
++void ScUndoRemoveLink::Undo()
+ {
+ 	DoChange( TRUE );
+ }
+ 
+-void __EXPORT ScUndoRemoveLink::Redo()
++void ScUndoRemoveLink::Redo()
+ {
+ 	DoChange( FALSE );
+ }
+ 
+-void __EXPORT ScUndoRemoveLink::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoRemoveLink::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 	//	gippsnich
+ }
+ 
+-BOOL __EXPORT ScUndoRemoveLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoRemoveLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;
+ }
+@@ -1132,7 +1134,7 @@ ScUndoShowHideTab::ScUndoShowHideTab( ScDocShell* pShell, SCTAB nNewTab, BOOL bN
+ {
+ }
+ 
+-__EXPORT ScUndoShowHideTab::~ScUndoShowHideTab()
++ScUndoShowHideTab::~ScUndoShowHideTab()
+ {
+ }
+ 
+@@ -1149,17 +1151,17 @@ void ScUndoShowHideTab::DoChange( BOOL bShowP ) const
+ 	pDocShell->SetDocumentModified();
+ }
+ 
+-void __EXPORT ScUndoShowHideTab::Undo()
++void ScUndoShowHideTab::Undo()
+ {
+ 	DoChange(!bShow);
+ }
+ 
+-void __EXPORT ScUndoShowHideTab::Redo()
++void ScUndoShowHideTab::Redo()
+ {
+ 	DoChange(bShow);
+ }
+ 
+-void __EXPORT ScUndoShowHideTab::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoShowHideTab::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 		((ScTabViewTarget&)rTarget).GetViewShell()->GetViewData()->GetDispatcher().
+@@ -1167,97 +1169,154 @@ void __EXPORT ScUndoShowHideTab::Repeat(SfxRepeatTarget& rTarget)
+ 								SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD);
+ }
+ 
+-BOOL __EXPORT ScUndoShowHideTab::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoShowHideTab::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+ 
+-String __EXPORT ScUndoShowHideTab::GetComment() const
++String ScUndoShowHideTab::GetComment() const
+ {
+ 	USHORT nId = bShow ? STR_UNDO_SHOWTAB : STR_UNDO_HIDETAB;
+ 	return ScGlobal::GetRscString( nId );
+ }
+ 
+-// -----------------------------------------------------------------------
+-//
+-//		Tabelle/Dokument schuetzen oder Schutz aufheben
+-//
++// ============================================================================
+ 
+-ScUndoProtect::ScUndoProtect( ScDocShell* pShell, SCTAB nNewTab,
+-							BOOL bNewProtect, const uno::Sequence<sal_Int8>& rNewPassword ) :
+-	ScSimpleUndo( pShell ),
+-	nTab( nNewTab ),
+-	bProtect( bNewProtect ),
+-	aPassword( rNewPassword )
++ScUndoDocProtect::ScUndoDocProtect(ScDocShell* pShell, auto_ptr<ScDocProtection> pProtectSettings) :
++    ScSimpleUndo(pShell),
++    mpProtectSettings(pProtectSettings)
+ {
+ }
+ 
+-__EXPORT ScUndoProtect::~ScUndoProtect()
++ScUndoDocProtect::~ScUndoDocProtect()
+ {
+ }
+ 
+-void ScUndoProtect::DoProtect( BOOL bDo )
++void ScUndoDocProtect::DoProtect(bool bProtect)
+ {
+-	ScDocument* pDoc = pDocShell->GetDocument();
++    ScDocument* pDoc = pDocShell->GetDocument();
+ 
+-	if (bDo)
+-	{
+-		if ( nTab == TABLEID_DOC )
+-			pDoc->SetDocProtection( TRUE, aPassword );
+-		else
+-			pDoc->SetTabProtection( nTab, TRUE, aPassword );
+-	}
+-	else
+-	{
+-		uno::Sequence<sal_Int8> aEmptyPass;
+-		if ( nTab == TABLEID_DOC )
+-			pDoc->SetDocProtection( FALSE, aEmptyPass );
+-		else
+-			pDoc->SetTabProtection( nTab, FALSE, aEmptyPass );
+-	}
++    if (bProtect)
++    {
++        // set protection.
++        auto_ptr<ScDocProtection> pCopy(new ScDocProtection(*mpProtectSettings));
++        pCopy->setProtected(true);
++        pDoc->SetDocProtection(pCopy.get());
++    }
++    else
++    {
++        // remove protection.
++        pDoc->SetDocProtection(NULL);
++    }
+ 
+-	ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+-	if (pViewShell)
+-	{
+-		pViewShell->UpdateLayerLocks();
+-		pViewShell->UpdateInputHandler(TRUE);	// damit sofort wieder eingegeben werden kann
+-	}
++    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
++    if (pViewShell)
++    {
++        pViewShell->UpdateLayerLocks();
++        pViewShell->UpdateInputHandler(TRUE);   // damit sofort wieder eingegeben werden kann
++    }
+ 
+-	pDocShell->PostPaintGridAll();
++    pDocShell->PostPaintGridAll();
+ }
+ 
+-void __EXPORT ScUndoProtect::Undo()
++void ScUndoDocProtect::Undo()
+ {
+-	BeginUndo();
+-	DoProtect( !bProtect );
+-	EndUndo();
++    BeginUndo();
++    DoProtect(!mpProtectSettings->isProtected());
++    EndUndo();
+ }
+ 
+-void __EXPORT ScUndoProtect::Redo()
++void ScUndoDocProtect::Redo()
+ {
+-	BeginRedo();
+-	DoProtect( bProtect );
+-	EndRedo();
++    BeginRedo();
++    DoProtect(mpProtectSettings->isProtected());
++    EndRedo();
+ }
+ 
+-void __EXPORT ScUndoProtect::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoDocProtect::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+-	//	gippsnich
++    //  gippsnich
+ }
+ 
+-BOOL __EXPORT ScUndoProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoDocProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+-	return FALSE;		// gippsnich
++    return FALSE;       // gippsnich
+ }
+ 
+-String __EXPORT ScUndoProtect::GetComment() const
++String ScUndoDocProtect::GetComment() const
+ {
+-	USHORT nId;
+-	if ( nTab == TABLEID_DOC )
+-		nId = bProtect ? STR_UNDO_PROTECT_DOC : STR_UNDO_UNPROTECT_DOC;
+-	else
+-		nId = bProtect ? STR_UNDO_PROTECT_TAB : STR_UNDO_UNPROTECT_TAB;
+-	return ScGlobal::GetRscString( nId );
++    USHORT nId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_DOC : STR_UNDO_UNPROTECT_DOC;
++    return ScGlobal::GetRscString( nId );
++}
++
++// ============================================================================
++
++ScUndoTabProtect::ScUndoTabProtect(ScDocShell* pShell, SCTAB nTab, auto_ptr<ScTableProtection> pProtectSettings) :
++    ScSimpleUndo(pShell),
++    mnTab(nTab),
++    mpProtectSettings(pProtectSettings)
++{
++}
++
++ScUndoTabProtect::~ScUndoTabProtect()
++{
++}
++
++void ScUndoTabProtect::DoProtect(bool bProtect)
++{
++    ScDocument* pDoc = pDocShell->GetDocument();
++
++    if (bProtect)
++    {
++        // set protection.
++        auto_ptr<ScTableProtection> pCopy(new ScTableProtection(*mpProtectSettings));
++        pCopy->setProtected(true);
++        pDoc->SetTabProtection(mnTab, pCopy.get());
++    }
++    else
++    {
++        // remove protection.
++        pDoc->SetTabProtection(mnTab, NULL);
++    }
++
++    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
++    if (pViewShell)
++    {
++        pViewShell->UpdateLayerLocks();
++        pViewShell->UpdateInputHandler(TRUE);   // damit sofort wieder eingegeben werden kann
++    }
++
++    pDocShell->PostPaintGridAll();
++}
++
++void ScUndoTabProtect::Undo()
++{
++    BeginUndo();
++    DoProtect(!mpProtectSettings->isProtected());
++    EndUndo();
++}
++
++void ScUndoTabProtect::Redo()
++{
++    BeginRedo();
++    DoProtect(mpProtectSettings->isProtected());
++    EndRedo();
++}
++
++void ScUndoTabProtect::Repeat(SfxRepeatTarget& /* rTarget */)
++{
++    //  gippsnich
++}
++
++BOOL ScUndoTabProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++{
++    return FALSE;       // gippsnich
++}
++
++String ScUndoTabProtect::GetComment() const
++{
++    USHORT nId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_TAB : STR_UNDO_UNPROTECT_TAB;
++    return ScGlobal::GetRscString( nId );
+ }
+ 
+ // -----------------------------------------------------------------------
+@@ -1274,7 +1333,7 @@ ScUndoPrintRange::ScUndoPrintRange( ScDocShell* pShell, SCTAB nNewTab,
+ {
+ }
+ 
+-__EXPORT ScUndoPrintRange::~ScUndoPrintRange()
++ScUndoPrintRange::~ScUndoPrintRange()
+ {
+ 	delete pOldRanges;
+ 	delete pNewRanges;
+@@ -1297,31 +1356,31 @@ void ScUndoPrintRange::DoChange(BOOL bUndo)
+ 	pDocShell->PostPaint( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab), PAINT_GRID );
+ }
+ 
+-void __EXPORT ScUndoPrintRange::Undo()
++void ScUndoPrintRange::Undo()
+ {
+ 	BeginUndo();
+ 	DoChange( TRUE );
+ 	EndUndo();
+ }
+ 
+-void __EXPORT ScUndoPrintRange::Redo()
++void ScUndoPrintRange::Redo()
+ {
+ 	BeginRedo();
+ 	DoChange( FALSE );
+ 	EndRedo();
+ }
+ 
+-void __EXPORT ScUndoPrintRange::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoPrintRange::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 	//	gippsnich
+ }
+ 
+-BOOL __EXPORT ScUndoPrintRange::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoPrintRange::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;		// gippsnich
+ }
+ 
+-String __EXPORT ScUndoPrintRange::GetComment() const
++String ScUndoPrintRange::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_PRINTRANGES );
+ }
+@@ -1350,16 +1409,16 @@ ScUndoScenarioFlags::ScUndoScenarioFlags( ScDocShell* pNewDocShell, SCTAB nT,
+ {
+ }
+ 
+-__EXPORT ScUndoScenarioFlags::~ScUndoScenarioFlags()
++ScUndoScenarioFlags::~ScUndoScenarioFlags()
+ {
+ }
+ 
+-String __EXPORT ScUndoScenarioFlags::GetComment() const
++String ScUndoScenarioFlags::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_EDITSCENARIO );
+ }
+ 
+-void __EXPORT ScUndoScenarioFlags::Undo()
++void ScUndoScenarioFlags::Undo()
+ {
+ 	ScDocument* pDoc = pDocShell->GetDocument();
+ 
+@@ -1376,7 +1435,7 @@ void __EXPORT ScUndoScenarioFlags::Undo()
+ 		SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
+ }
+ 
+-void __EXPORT ScUndoScenarioFlags::Redo()
++void ScUndoScenarioFlags::Redo()
+ {
+ 	ScDocument* pDoc = pDocShell->GetDocument();
+ 
+@@ -1393,12 +1452,12 @@ void __EXPORT ScUndoScenarioFlags::Redo()
+ 		SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
+ }
+ 
+-void __EXPORT ScUndoScenarioFlags::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoScenarioFlags::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ 	//	Repeat macht keinen Sinn
+ }
+ 
+-BOOL __EXPORT ScUndoScenarioFlags::CanRepeat(SfxRepeatTarget& /* rTarget */) const
++BOOL ScUndoScenarioFlags::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+ {
+ 	return FALSE;
+ }
+@@ -1498,7 +1557,7 @@ ScUndoLayoutRTL::ScUndoLayoutRTL( ScDocShell* pShell, SCTAB nNewTab, BOOL bNewRT
+ {
+ }
+ 
+-__EXPORT ScUndoLayoutRTL::~ScUndoLayoutRTL()
++ScUndoLayoutRTL::~ScUndoLayoutRTL()
+ {
+ }
+ 
+@@ -1518,29 +1577,29 @@ void ScUndoLayoutRTL::DoChange( BOOL bNew )
+ 	pDocShell->SetInUndo( FALSE );
+ }
+ 
+-void __EXPORT ScUndoLayoutRTL::Undo()
++void ScUndoLayoutRTL::Undo()
+ {
+ 	DoChange(!bRTL);
+ }
+ 
+-void __EXPORT ScUndoLayoutRTL::Redo()
++void ScUndoLayoutRTL::Redo()
+ {
+ 	DoChange(bRTL);
+ }
+ 
+-void __EXPORT ScUndoLayoutRTL::Repeat(SfxRepeatTarget& rTarget)
++void ScUndoLayoutRTL::Repeat(SfxRepeatTarget& rTarget)
+ {
+ 	if (rTarget.ISA(ScTabViewTarget))
+ 		((ScTabViewTarget&)rTarget).GetViewShell()->GetViewData()->GetDispatcher().
+ 			Execute( FID_TAB_RTL, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD);
+ }
+ 
+-BOOL __EXPORT ScUndoLayoutRTL::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoLayoutRTL::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+ 	return (rTarget.ISA(ScTabViewTarget));
+ }
+ 
+-String __EXPORT ScUndoLayoutRTL::GetComment() const
++String ScUndoLayoutRTL::GetComment() const
+ {
+ 	return ScGlobal::GetRscString( STR_UNDO_TAB_RTL );
+ }
+@@ -1560,7 +1619,7 @@ ScUndoSetGrammar::ScUndoSetGrammar( ScDocShell* pShell,
+     meOldGrammar = pDocShell->GetDocument()->GetGrammar();
+ }
+ 
+-__EXPORT ScUndoSetGrammar::~ScUndoSetGrammar()
++ScUndoSetGrammar::~ScUndoSetGrammar()
+ {
+ }
+ 
+@@ -1573,17 +1632,17 @@ void ScUndoSetGrammar::DoChange( ScGrammar::Grammar eGrammar )
+     pDocShell->SetInUndo( FALSE );
+ }
+ 
+-void __EXPORT ScUndoSetGrammar::Undo()
++void ScUndoSetGrammar::Undo()
+ {
+     DoChange( meOldGrammar );
+ }
+ 
+-void __EXPORT ScUndoSetGrammar::Redo()
++void ScUndoSetGrammar::Redo()
+ {
+     DoChange( meNewGrammar );
+ }
+ 
+-void __EXPORT ScUndoSetGrammar::Repeat(SfxRepeatTarget& /* rTarget */)
++void ScUndoSetGrammar::Repeat(SfxRepeatTarget& /* rTarget */)
+ {
+ #if 0
+ // erAck: 2006-09-07T23:00+0200  commented out in CWS scr1c1
+@@ -1593,12 +1652,12 @@ void __EXPORT ScUndoSetGrammar::Repeat(SfxRepeatTarget& /* rTarget */)
+ #endif
+ }
+ 
+-BOOL __EXPORT ScUndoSetGrammar::CanRepeat(SfxRepeatTarget& rTarget) const
++BOOL ScUndoSetGrammar::CanRepeat(SfxRepeatTarget& rTarget) const
+ {
+     return (rTarget.ISA(ScTabViewTarget));
+ }
+ 
+-String __EXPORT ScUndoSetGrammar::GetComment() const
++String ScUndoSetGrammar::GetComment() const
+ {
+     return ScGlobal::GetRscString( STR_UNDO_TAB_R1C1 );
+ }
+diff --git sc/source/ui/unoobj/warnpassword.cxx sc/source/ui/unoobj/warnpassword.cxx
+index 78f355d..11a00f7 100644
+--- sc/source/ui/unoobj/warnpassword.cxx
++++ sc/source/ui/unoobj/warnpassword.cxx
+@@ -95,3 +95,4 @@ bool ScWarnPassword::WarningOnPassword( SfxMedium& rMedium )
+     }
+     return bReturn;
+ }
++
+diff --git sc/source/ui/view/gridwin.cxx sc/source/ui/view/gridwin.cxx
+index 9989ad6..0f48c9c 100644
+--- sc/source/ui/view/gridwin.cxx
++++ sc/source/ui/view/gridwin.cxx
+@@ -140,6 +140,7 @@
+ #include "drwlayer.hxx"
+ #include "attrib.hxx"
+ #include "cellsh.hxx"
++#include "tabprotection.hxx"
+ 
+ // #114409#
+ #include <vcl/salbtype.hxx>		// FRound
+@@ -2037,8 +2038,9 @@ void __EXPORT ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt )
+ 		Point aPos = rMEvt.GetPosPixel();
+         SCsCOL nPosX;
+         SCsROW nPosY;
++        SCTAB nTab = pViewData->GetTabNo();
+         pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+-		ScDPObject*	pDPObj	= pDoc->GetDPAtCursor( nPosX, nPosY, pViewData->GetTabNo() );
++		ScDPObject*	pDPObj	= pDoc->GetDPAtCursor( nPosX, nPosY, nTab );
+ 		if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() )
+ 		{
+ 			ScAddress aCellPos( nPosX, nPosY, pViewData->GetTabNo() );
+@@ -2080,19 +2082,37 @@ void __EXPORT ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt )
+ 			return;
+ 		}
+ 
+-		//	edit cell contents
+-		pViewData->GetViewShell()->UpdateInputHandler();
+-		pScMod->SetInputMode( SC_INPUT_TABLE );
+-		if (pViewData->HasEditView(eWhich))
+-		{
+-			//	Text-Cursor gleich an die geklickte Stelle setzen
+-			EditView* pEditView = pViewData->GetEditView( eWhich );
+-			MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MOUSE_SYNTHETIC, MOUSE_LEFT, 0 );
+-			pEditView->MouseButtonDown( aEditEvt );
+-			pEditView->MouseButtonUp( aEditEvt );
+-		}
++        // Check for cell protection attribute.
++        ScTableProtection* pProtect = pDoc->GetTabProtection( nTab );
++        bool bEditAllowed = true;
++        if ( pProtect && pProtect->isProtected() )
++        {
++            bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED);
++            bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
++            bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
++
++            if ( bSkipProtected && bSkipUnprotected )
++                bEditAllowed = false;
++            else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
++                bEditAllowed = false;
++        }
++
++        if ( bEditAllowed )
++        {
++            //  edit cell contents
++            pViewData->GetViewShell()->UpdateInputHandler();
++            pScMod->SetInputMode( SC_INPUT_TABLE );
++            if (pViewData->HasEditView(eWhich))
++            {
++                //  Text-Cursor gleich an die geklickte Stelle setzen
++                EditView* pEditView = pViewData->GetEditView( eWhich );
++                MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MOUSE_SYNTHETIC, MOUSE_LEFT, 0 );
++                pEditView->MouseButtonDown( aEditEvt );
++                pEditView->MouseButtonUp( aEditEvt );
++            }
++        }
+         return;
+-	}
++    }
+ 
+ 			//
+ 			//		Links in edit cells
+diff --git sc/source/ui/view/scextopt.cxx sc/source/ui/view/scextopt.cxx
+index 8ac6382..586f934 100644
+--- sc/source/ui/view/scextopt.cxx
++++ sc/source/ui/view/scextopt.cxx
+@@ -42,9 +42,7 @@ ScExtDocSettings::ScExtDocSettings() :
+     maOleSize( ScAddress::INITIALIZE_INVALID ),
+     mfTabBarWidth( -1.0 ),
+     mnLinkCnt( 0 ),
+-    mnDisplTab( 0 ),
+-    mbWinProtected( false ),
+-    mbEncrypted( false )
++    mnDisplTab( 0 )
+ {
+ }
+ 
+diff --git sc/source/ui/view/select.cxx sc/source/ui/view/select.cxx
+index f6d5704..fdc4fc5 100644
+--- sc/source/ui/view/select.cxx
++++ sc/source/ui/view/select.cxx
+@@ -47,6 +47,7 @@
+ //#include "dataobj.hxx"
+ #include "transobj.hxx"
+ #include "docsh.hxx"
++#include "tabprotection.hxx"
+ 
+ extern USHORT nScFillModeMouseModifier;				// global.cxx
+ 
+@@ -322,6 +323,26 @@ BOOL ScViewFunctionSet::SetCursorAtCell( SCsCOL nPosX, SCsROW nPosY, BOOL bScrol
+ {
+ 	ScTabView* pView = pViewData->GetView();
+ 	SCTAB nTab = pViewData->GetTabNo();
++    ScDocument* pDoc = pViewData->GetDocument();
++
++    if ( pDoc->IsTabProtected(nTab) )
++    {
++        if (nPosX < 0 || nPosY < 0)
++            return false;
++
++        ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++        bool bSkipProtected   = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
++        bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
++
++        if ( bSkipProtected && bSkipUnprotected )
++            return FALSE;
++
++        bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED);
++        if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
++            // Don't select this cell!
++            return FALSE;
++    }
++
+ 	ScModule* pScMod = SC_MOD();
+     ScTabViewShell* pViewShell = pViewData->GetViewShell();
+     bool bRefMode = ( pViewShell ? pViewShell->IsRefInputMode() : false );
+@@ -375,7 +396,6 @@ BOOL ScViewFunctionSet::SetCursorAtCell( SCsCOL nPosX, SCsROW nPosY, BOOL bScrol
+ 
+ 		ScRange aDelRange;
+ 		BOOL bOldDelMark = pViewData->GetDelMark( aDelRange );
+-		ScDocument* pDoc = pViewData->GetDocument();
+ 
+ 		if ( nPosX+1 >= (SCsCOL) nStartX && nPosX <= (SCsCOL) nEndX &&
+ 			 nPosY+1 >= (SCsROW) nStartY && nPosY <= (SCsROW) nEndY &&
+@@ -511,7 +531,6 @@ BOOL ScViewFunctionSet::SetCursorAtCell( SCsCOL nPosX, SCsROW nPosY, BOOL bScrol
+ 		BYTE nMode = pViewData->GetFillMode();
+ 		if ( nMode == SC_FILL_EMBED_LT || nMode == SC_FILL_EMBED_RB )
+ 		{
+-			ScDocument* pDoc = pViewData->GetDocument();
+ 			DBG_ASSERT( pDoc->IsEmbedded(), "!pDoc->IsEmbedded()" );
+             ScRange aRange;
+ 			pDoc->GetEmbedded( aRange);
+diff --git sc/source/ui/view/tabview3.cxx sc/source/ui/view/tabview3.cxx
+index 959b320..4b864a9 100644
+--- sc/source/ui/view/tabview3.cxx
++++ sc/source/ui/view/tabview3.cxx
+@@ -79,6 +79,7 @@
+ #include "AccessibilityHints.hxx"
+ #include "rangeutl.hxx"
+ #include "client.hxx"
++#include "tabprotection.hxx"
+ 
+ #include <com/sun/star/chart2/data/HighlightedRange.hpp>
+ 
+@@ -942,6 +943,17 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 	ScDocument* pDoc = aViewData.GetDocument();
+ 	SCTAB nTab = aViewData.GetTabNo();
+ 
++    bool bSkipProtected = false, bSkipUnprotected = false;
++    ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++    if ( pProtect && pProtect->isProtected() )
++    {
++        bSkipProtected   = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
++        bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
++    }
++
++    if ( bSkipProtected && bSkipUnprotected )
++        return;
++
+ 	SCsCOL nOldX;
+ 	SCsROW nOldY;
+ 	SCsCOL nCurX;
+@@ -961,7 +973,7 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 		nCurY = (nMovY != 0) ? nOldY+nMovY : (SCsROW) aViewData.GetOldCurY();
+ 	}
+ 
+-	BOOL bHidden;
++	BOOL bSkipCell = FALSE;
+ 	aViewData.ResetOldCursor();
+ 
+ 	if (nMovX != 0 && VALIDCOLROW(nCurX,nCurY))
+@@ -970,15 +982,20 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 		do
+ 		{
+ 			BYTE nColFlags = pDoc->GetColFlags( nCurX, nTab );
+-			bHidden = (nColFlags & CR_HIDDEN) || pDoc->IsHorOverlapped( nCurX, nCurY, nTab );
+-			if (bHidden)
++            bSkipCell = (nColFlags & CR_HIDDEN) || pDoc->IsHorOverlapped( nCurX, nCurY, nTab );
++            if (bSkipProtected && !bSkipCell)
++                bSkipCell = pDoc->HasAttrib(nCurX, nCurY, nTab, nCurX, nCurY, nTab, HASATTR_PROTECTED);
++            if (bSkipUnprotected && !bSkipCell)
++                bSkipCell = !pDoc->HasAttrib(nCurX, nCurY, nTab, nCurX, nCurY, nTab, HASATTR_PROTECTED);
++
++			if (bSkipCell)
+ 			{
+ 				if ( nCurX<=0 || nCurX>=MAXCOL )
+ 				{
+ 					if (bHFlip)
+ 					{
+ 						nCurX = nOldX;
+-						bHidden = FALSE;
++						bSkipCell = FALSE;
+ 					}
+ 					else
+ 					{
+@@ -991,7 +1008,8 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 					if (nMovX > 0) ++nCurX; else --nCurX;
+ 			}
+ 		}
+-		while (bHidden);
++		while (bSkipCell);
++
+ 		if (pDoc->IsVerOverlapped( nCurX, nCurY, nTab ))
+ 		{
+ 			aViewData.SetOldCursor( nCurX,nCurY );
+@@ -1006,15 +1024,20 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 		do
+ 		{
+ 			BYTE nRowFlags = pDoc->GetRowFlags( nCurY, nTab );
+-			bHidden = (nRowFlags & CR_HIDDEN) || pDoc->IsVerOverlapped( nCurX, nCurY, nTab );
+-			if (bHidden)
++            bSkipCell = (nRowFlags & CR_HIDDEN) || pDoc->IsVerOverlapped( nCurX, nCurY, nTab );
++            if (bSkipProtected && !bSkipCell)
++                bSkipCell = pDoc->HasAttrib(nCurX, nCurY, nTab, nCurX, nCurY, nTab, HASATTR_PROTECTED);
++            if (bSkipUnprotected && !bSkipCell)
++                bSkipCell = !pDoc->HasAttrib(nCurX, nCurY, nTab, nCurX, nCurY, nTab, HASATTR_PROTECTED);
++
++			if (bSkipCell)
+ 			{
+ 				if ( nCurY<=0 || nCurY>=MAXROW )
+ 				{
+ 					if (bVFlip)
+ 					{
+ 						nCurY = nOldY;
+-						bHidden = FALSE;
++						bSkipCell = FALSE;
+ 					}
+ 					else
+ 					{
+@@ -1027,7 +1050,8 @@ void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
+ 					if (nMovY > 0) ++nCurY; else --nCurY;
+ 			}
+ 		}
+-		while (bHidden);
++		while (bSkipCell);
++
+ 		if (pDoc->IsHorOverlapped( nCurX, nCurY, nTab ))
+ 		{
+ 			aViewData.SetOldCursor( nCurX,nCurY );
+diff --git sc/source/ui/view/tabvwsh3.cxx sc/source/ui/view/tabvwsh3.cxx
+index 0d08cc7..03e4414 100644
+--- sc/source/ui/view/tabvwsh3.cxx
++++ sc/source/ui/view/tabvwsh3.cxx
+@@ -75,6 +75,8 @@
+ #include "autofmt.hxx"
+ #include "dwfunctr.hxx"
+ #include "shtabdlg.hxx"
++#include "tabprotection.hxx"
++#include "protectiondlg.hxx"
+ 
+ #include <svtools/ilstitem.hxx>
+ #define _SVSTDARR_ULONGS
+@@ -85,6 +87,10 @@
+ #include <svx/dialogs.hrc> //CHINA001
+ #include "scabstdlg.hxx" //CHINA001
+ 
++#include <memory>
++
++using ::std::auto_ptr;
++
+ #define IS_EDITMODE() GetViewData()->HasEditView( GetViewData()->GetActivePart() )
+ #define IS_AVAILABLE(WhichId,ppItem) \
+     (pReqArgs->GetItemState((WhichId), TRUE, ppItem ) == SFX_ITEM_SET)
+@@ -1002,12 +1008,13 @@ void ScTabViewShell::Execute( SfxRequest& rReq )
+                     }
+                 }
+ 
+-				if (pDoc->IsDocProtected())
++                ScDocProtection* pProtect = pDoc->GetDocProtection();
++                if (pProtect && pProtect->isProtected())
+ 				{
+ 					BOOL	bCancel = FALSE;
+ 					String	aPassword;
+ 
+-					if (pDoc->GetDocPassword().getLength())
++                    if (pProtect->isProtectedWithPass())
+ 					{
+ 						String	aText( ScResId(SCSTR_PASSWORD) );
+ 
+@@ -1057,89 +1064,164 @@ void ScTabViewShell::Execute( SfxRequest& rReq )
+ 
+ 
+ 		case FID_PROTECT_TABLE:
+-			{
+-				ScDocument* 		pDoc = GetViewData()->GetDocument();
+-				SCTAB				nTab = GetViewData()->GetTabNo();
+-				SfxPasswordDialog*	pDlg;
+-				String				aPassword;
+-				BOOL				bCancel = FALSE;
+-				BOOL				bOldProtection = pDoc->IsTabProtected(nTab);
+-				BOOL				bNewProtection = ! bOldProtection;
++        {
++            ScDocument* pDoc = GetViewData()->GetDocument();
++            SCTAB		nTab = GetViewData()->GetTabNo();
++            bool        bOldProtection = pDoc->IsTabProtected(nTab);
+ 
+-				if( pReqArgs )
+-				{
+-					const SfxPoolItem* pItem;
+-					if( IS_AVAILABLE( FID_PROTECT_TABLE, &pItem ) )
+-						bNewProtection = ((const SfxBoolItem*)pItem)->GetValue();
+-                    if( bNewProtection == bOldProtection )
++#if ENABLE_SHEET_PROTECTION
++
++            if( pReqArgs )
++            {
++                const SfxPoolItem* pItem;
++                bool bNewProtection = !bOldProtection;
++                if( IS_AVAILABLE( FID_PROTECT_TABLE, &pItem ) )
++                    bNewProtection = ((const SfxBoolItem*)pItem)->GetValue();
++                if( bNewProtection == bOldProtection )
++                {
++                    rReq.Ignore();
++                    break;
++                }
++            }
++
++            if (bOldProtection)
++            {
++                // Unprotect a protected sheet.
++
++                ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++                if (pProtect && pProtect->isProtectedWithPass())
++                {
++                    String aText( ScResId(SCSTR_PASSWORDOPT) );
++                    auto_ptr<SfxPasswordDialog> pDlg(new SfxPasswordDialog(GetDialogParent(), &aText));
++                    pDlg->SetText( ScResId(SCSTR_UNPROTECTTAB) );
++                    pDlg->SetMinLen( 0 );
++                    pDlg->SetHelpId( FID_PROTECT_TABLE );
++                    pDlg->SetEditHelpId( HID_PASSWD_TABLE );
++
++                    if (pDlg->Execute() == RET_OK)
+                     {
+-                        rReq.Ignore();
+-                        break;
++                        String aPassword = pDlg->GetPassword();
++                        Unprotect(nTab, aPassword);
+                     }
+                 }
++                else
++                    // this sheet is not password-protected.
++                    Unprotect(nTab, String());
+ 
+-                    if ( bOldProtection)
+-                    {
+-                        if (pDoc->GetTabPassword(nTab).getLength())
+-                        {
+-                            String  aText( ScResId(SCSTR_PASSWORD) );
++                if (!pReqArgs)
++                {
++                    rReq.AppendItem( SfxBoolItem(FID_PROTECT_TABLE, false) );
++                    rReq.Done();
++                }
++            }
++            else
++            {
++                // Protect a current sheet.
+ 
+-                            pDlg = new SfxPasswordDialog( GetDialogParent(), &aText );
+-                            pDlg->SetText( ScResId(SCSTR_UNPROTECTTAB) );
+-                            pDlg->SetMinLen( 0 );
+-                            pDlg->SetHelpId( FID_PROTECT_TABLE );
+-                            pDlg->SetEditHelpId( HID_PASSWD_TABLE );
++                auto_ptr<ScTableProtectionDlg> pDlg(new ScTableProtectionDlg(GetDialogParent()));
+ 
+-                            if (pDlg->Execute() == RET_OK)
+-                                aPassword = pDlg->GetPassword();
+-                            else
+-                                bCancel = TRUE;
++                ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++                if (pProtect)
++                    pDlg->SetDialogData(*pProtect);
+ 
+-                            delete pDlg;
+-                        }
+-                    }
+-                    else
++                if (pDlg->Execute() == RET_OK)
++                {
++                    pScMod->InputEnterHandler();
++
++                    ScTableProtection aNewProtect;
++                    pDlg->WriteData(aNewProtect);
++                    ProtectSheet(nTab, aNewProtect);
++                    if (!pReqArgs)
+                     {
+-                        String aText( ScResId(SCSTR_PASSWORDOPT) );
++                        rReq.AppendItem( SfxBoolItem(FID_PROTECT_TABLE, true) );
++                        rReq.Done();
++                    }
++                }
++            }
++#else
++            auto_ptr<SfxPasswordDialog> pDlg;
++            String				aPassword;
++            BOOL				bCancel = FALSE;
++            BOOL				bNewProtection = ! bOldProtection;
+ 
+-                        pDlg = new SfxPasswordDialog( GetDialogParent(), &aText );
+-                        pDlg->SetText( ScResId(SCSTR_PROTECTTAB) );
+-                        pDlg->SetMinLen( 0 );
+-                        pDlg->SetHelpId( FID_PROTECT_TABLE );
+-                        pDlg->SetEditHelpId( HID_PASSWD_TABLE );
+-                        pDlg->ShowExtras( SHOWEXTRAS_CONFIRM );
++            if( pReqArgs )
++            {
++                const SfxPoolItem* pItem;
++                if( IS_AVAILABLE( FID_PROTECT_TABLE, &pItem ) )
++                    bNewProtection = ((const SfxBoolItem*)pItem)->GetValue();
++                if( bNewProtection == bOldProtection )
++                {
++                    rReq.Ignore();
++                    break;
++                }
++            }
+ 
+-                        if (pDlg->Execute() == RET_OK)
+-                            aPassword = pDlg->GetPassword();
+-                        else
+-                            bCancel = TRUE;
++            if ( bOldProtection)
++            {
++                // Unprotect a protected sheet.
+ 
+-                        delete pDlg;
+-                    }
++                ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
++                if (pProtect && pProtect->isProtectedWithPass())
++                {
++                    String aText( ScResId(SCSTR_PASSWORDOPT) );
++                    pDlg.reset(new SfxPasswordDialog(GetDialogParent(), &aText));
++                    pDlg->SetText( ScResId(SCSTR_UNPROTECTTAB) );
++                    pDlg->SetMinLen( 0 );
++                    pDlg->SetHelpId( FID_PROTECT_TABLE );
++                    pDlg->SetEditHelpId( HID_PASSWD_TABLE );
++
++                    if (pDlg->Execute() == RET_OK)
++                        aPassword = pDlg->GetPassword();
++                    else
++                        bCancel = TRUE;
++                }
+ 
+-                if( !bCancel )
+-				{
+-                    if ( bOldProtection )
+-						Unprotect( nTab, aPassword );
+-					else
+-                    {
+-                        pScMod->InputEnterHandler();
++                if (!pReqArgs)
++                {
++                    rReq.AppendItem( SfxBoolItem(FID_PROTECT_TABLE, false) );
++                    rReq.Done();
++                }
++            }
++            else
++            {
++                String aText( ScResId(SCSTR_PASSWORDOPT) );
+ 
+-						Protect( nTab, aPassword );
+-                    }
++                pDlg.reset(new SfxPasswordDialog(GetDialogParent(), &aText));
++                pDlg->SetText( ScResId(SCSTR_PROTECTTAB) );
++                pDlg->SetMinLen( 0 );
++                pDlg->SetHelpId( FID_PROTECT_TABLE );
++                pDlg->SetEditHelpId( HID_PASSWD_TABLE );
++                pDlg->ShowExtras( SHOWEXTRAS_CONFIRM );
+ 
+-                    if( !pReqArgs )
+-					{
+-						rReq.AppendItem( SfxBoolItem( FID_PROTECT_TABLE, bNewProtection ) );
+-						rReq.Done();
+-					}
+-				}
++                if (pDlg->Execute() == RET_OK)
++                    aPassword = pDlg->GetPassword();
++                else
++                    bCancel = TRUE;
++            }
+ 
+-				TabChanged();
+-				UpdateInputHandler(TRUE);	// damit sofort wieder eingegeben werden kann
+-				SelectionChanged();
+-			}
+-			break;
++            if( !bCancel )
++            {
++                if ( bOldProtection )
++                    Unprotect( nTab, aPassword );
++                else
++                {
++                    pScMod->InputEnterHandler();
++
++                    Protect( nTab, aPassword );
++                }
++
++                if( !pReqArgs )
++                {
++                    rReq.AppendItem( SfxBoolItem( FID_PROTECT_TABLE, bNewProtection ) );
++                    rReq.Done();
++                }
++            }
++#endif
++            TabChanged();
++            UpdateInputHandler(true);   // damit sofort wieder eingegeben werden kann
++            SelectionChanged();
++        }
++        break;
+ 
+         case SID_OPT_LOCALE_CHANGED :
+             {   // locale changed, SYSTEM number formats changed => repaint cell contents
+diff --git sc/source/ui/view/tabvwshh.cxx sc/source/ui/view/tabvwshh.cxx
+index fb9408b..52c8fc4 100644
+--- sc/source/ui/view/tabvwshh.cxx
++++ sc/source/ui/view/tabvwshh.cxx
+@@ -43,6 +43,7 @@
+ #include <sfx2/request.hxx>
+ #include <basic/sbxcore.hxx>
+ #include <svtools/whiter.hxx>
++#include <vcl/msgbox.hxx>
+ 
+ #include "tabvwsh.hxx"
+ #include "client.hxx"
+@@ -50,6 +51,10 @@
+ #include "docsh.hxx"
+ #include "sc.hrc"
+ #include "drwlayer.hxx"		// GetVisibleName
++#include "retypepassdlg.hxx"
++#include "tabprotection.hxx"
++
++#include <memory>
+ 
+ using namespace com::sun::star;
+ 
+@@ -270,6 +275,22 @@ BOOL ScTabViewShell::HasAccessibilityObjects()
+ 	return pAccessibilityBroadcaster != NULL;
+ }
+ 
++bool ScTabViewShell::ExecuteRetypePassDlg(ScPasswordHash eDesiredHash)
++{
++    using ::std::auto_ptr;
++
++    ScDocument* pDoc = GetViewData()->GetDocument();
++
++    auto_ptr<ScRetypePassDlg> pDlg(new ScRetypePassDlg(GetDialogParent()));
++    pDlg->SetData(*pDoc);
++    pDlg->SetDesiredHash(eDesiredHash);
++    if (pDlg->Execute() != RET_OK)
++        return false;
++
++    pDlg->WriteNewDataToDocument(*pDoc);
++    return true;
++}
++
+ 
+ 
+ 
+diff --git sc/source/ui/view/viewfun2.cxx sc/source/ui/view/viewfun2.cxx
+index a060e8d..5c27c7b 100644
+--- sc/source/ui/view/viewfun2.cxx
++++ sc/source/ui/view/viewfun2.cxx
+@@ -2150,7 +2150,7 @@ BOOL ScViewFunc::DeleteTables(const SvShorts &TheTabs, BOOL bRecord )
+ 			pUndoDoc->SetVisible( nTab, pDoc->IsVisible( nTab ) );
+ 
+ 			if ( pDoc->IsTabProtected( nTab ) )
+-				pUndoDoc->SetTabProtection( nTab, TRUE, pDoc->GetTabPassword( nTab ) );
++                pUndoDoc->SetTabProtection(nTab, pDoc->GetTabProtection(nTab));
+ 
+ 			//	Drawing-Layer muss sein Undo selbst in der Hand behalten !!!
+ 			//		pUndoDoc->TransferDrawPage(pDoc, nTab,nTab);
+@@ -2565,7 +2565,7 @@ void ScViewFunc::MoveTable( USHORT nDestDocNo, SCTAB nDestTab, BOOL bCopy )
+ 				}
+ 
+ 				if ( nErrVal > 0 && pDoc->IsTabProtected( TheTabs[i] ) )
+-					pDestDoc->SetTabProtection( nDestTab1, TRUE, pDoc->GetTabPassword( TheTabs[i] ) );
++                    pDestDoc->SetTabProtection(nDestTab1, pDoc->GetTabProtection(TheTabs[i]));
+ 
+ 				nDestTab1++;
+ 			}
+diff --git sc/source/ui/view/viewfunc.cxx sc/source/ui/view/viewfunc.cxx
+index b00d762..ef0e0a0 100644
+--- sc/source/ui/view/viewfunc.cxx
++++ sc/source/ui/view/viewfunc.cxx
+@@ -2403,6 +2403,36 @@ void ScViewFunc::ModifyCellSize( ScDirection eDir, BOOL bOptimal )
+ 	ShowAllCursors();
+ }
+ 
++void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
++{
++    if (nTab == TABLEID_DOC)
++        return;
++
++	ScMarkData& rMark = GetViewData()->GetMarkData();
++	ScDocShell* pDocSh = GetViewData()->GetDocShell();
++	ScDocument* pDoc = pDocSh->GetDocument();
++	ScDocFunc aFunc(*pDocSh);
++	bool bUndo(pDoc->IsUndoEnabled());
++
++    //	modifying several tables is handled here
++
++    if (bUndo)
++    {
++        String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
++        pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
++    }
++
++    SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
++    for ( SCTAB i=0; i<nCount; i++ )
++        if ( rMark.GetTableSelect(i) )
++            aFunc.ProtectSheet(i, rProtect);
++
++    if (bUndo)
++        pDocSh->GetUndoManager()->LeaveListAction();
++
++	UpdateLayerLocks();			//!	broadcast to all views
++}
++
+ void ScViewFunc::Protect( SCTAB nTab, const String& rPassword )
+ {
+ 	ScMarkData& rMark = GetViewData()->GetMarkData();

Added: trunk/patches/dev300/cws-scsheetprotection02-sfx2.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/cws-scsheetprotection02-sfx2.diff	Mon Dec 29 16:42:06 2008
@@ -0,0 +1,74 @@
+diff --git sfx2/inc/sfx2/passwd.hxx sfx2/inc/sfx2/passwd.hxx
+index a9b176b..15aeb1f 100644
+--- sfx2/inc/sfx2/passwd.hxx
++++ sfx2/inc/sfx2/passwd.hxx
+@@ -86,6 +86,7 @@ public:
+ 	String			GetConfirm() const { return maConfirmED.GetText(); }
+ 
+ 	void 			SetMinLen( USHORT Len );
++    void            SetMaxLen( USHORT Len );
+ 	void			SetEditHelpId( ULONG nId ) { maPasswordED.SetHelpId( nId ); }
+ 	void			ShowExtras( USHORT nExtras ) { mnExtras = nExtras; }
+ 
+diff --git sfx2/source/dialog/filedlghelper.cxx sfx2/source/dialog/filedlghelper.cxx
+index 42976cd..37f2426 100644
+--- sfx2/source/dialog/filedlghelper.cxx
++++ sfx2/source/dialog/filedlghelper.cxx
+@@ -559,9 +559,20 @@ struct CheckPasswordCapability
+ {
+ 	sal_Bool operator() ( const SfxFilter* _pFilter )
+ 	{
+-        return  _pFilter && _pFilter->IsOwnFormat()
+-			&&	_pFilter->UsesStorage()
+-			&&	( SOFFICE_FILEFORMAT_60 <= _pFilter->GetVersion() );
++        if (!_pFilter)
++            return false;
++
++#if 0 // to be enabled in the future
++        if (_pFilter->GetFilterName().EqualsAscii("MS Excel 97"))
++            // For now, we eanble password protection for Excel 97 as a 
++            // special case.  If we start having more filters supporting
++            // export encryption with password, we should probably switch to
++            // using a filter flag instead.
++            return true;
++#endif
++
++        return _pFilter->IsOwnFormat() && _pFilter->UsesStorage()
++            && ( SOFFICE_FILEFORMAT_60 <= _pFilter->GetVersion() );
+ 	}
+ };
+ 
+@@ -1617,11 +1628,12 @@ ErrCode FileDialogHelper_Impl::execute( SvStringsDtor*& rpURLList,
+ 				sal_Bool bPassWord = sal_False;
+ 				if ( ( aValue >>= bPassWord ) && bPassWord )
+ 				{
+-					// ask for the password
++					// ask for a password
+                     uno::Reference < ::com::sun::star::task::XInteractionHandler > xInteractionHandler( ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.comp.uui.UUIInteractionHandler")), UNO_QUERY );
+ 
+                     if( xInteractionHandler.is() )
+                     {
++                        // TODO: find out a way to set the 1-15 char limits on MS Excel 97 filter.
+                         RequestDocumentPassword* pPasswordRequest = new RequestDocumentPassword(
+                             ::com::sun::star::task::PasswordRequestMode_PASSWORD_CREATE, *(rpURLList->GetObject(0)) );
+  
+diff --git sfx2/source/dialog/passwd.cxx sfx2/source/dialog/passwd.cxx
+index f49467f..062fb9c 100644
+--- sfx2/source/dialog/passwd.cxx
++++ sfx2/source/dialog/passwd.cxx
+@@ -136,6 +136,15 @@ void SfxPasswordDialog::SetMinLen( USHORT nLen )
+ 
+ // -----------------------------------------------------------------------
+ 
++void SfxPasswordDialog::SetMaxLen( USHORT nLen )
++{
++    maPasswordED.SetMaxTextLen( nLen );
++    maConfirmED.SetMaxTextLen( nLen );
++	EditModifyHdl( NULL );
++}
++
++// -----------------------------------------------------------------------
++
+ short SfxPasswordDialog::Execute()
+ {
+ 	if ( mnExtras < SHOWEXTRAS_ALL )

Added: trunk/patches/dev300/cws-scsheetprotection02-svx.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/cws-scsheetprotection02-svx.diff	Mon Dec 29 16:42:06 2008
@@ -0,0 +1,261 @@
+diff --git svx/inc/mscodec.hxx svx/inc/mscodec.hxx
+index 66dcf5d..be67b46 100644
+--- svx/inc/mscodec.hxx
++++ svx/inc/mscodec.hxx
+@@ -235,6 +235,14 @@ public:
+      */
+     bool                InitCipher( sal_uInt32 nCounter );
+ 
++    /** Creates an MD5 digest of salt digest. */
++    bool                CreateSaltDigest( 
++                            const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] );
++
++    bool                Encode(
++                            const void* pData, sal_Size nDatLen,
++                            sal_uInt8* pBuffer, sal_Size nBufLen );
++
+     /** Decodes a block of memory.
+ 
+         @see rtl_cipher_decode()
+@@ -276,6 +284,9 @@ public:
+     bool                Skip( sal_Size nDatLen );
+ 
+ private:
++    void                GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] );
++
++private:
+                         SVX_DLLPRIVATE MSCodec_Std97( const MSCodec_Std97& );
+     SVX_DLLPRIVATE MSCodec_Std97&      operator=( const MSCodec_Std97& );
+ 
+diff --git svx/source/msfilter/mscodec.cxx svx/source/msfilter/mscodec.cxx
+index 30baed5..d086754 100644
+--- svx/source/msfilter/mscodec.cxx
++++ svx/source/msfilter/mscodec.cxx
+@@ -37,6 +37,13 @@
+ #include <string.h>
+ #include <tools/solar.h>
+ 
++#define DEBUG_MSO_ENCRYPTION_STD97 0
++
++#if DEBUG_MSO_ENCRYPTION_STD97
++#include <stdio.h>
++#endif
++
++
+ namespace svx {
+ 
+ // ============================================================================
+@@ -241,15 +248,50 @@ MSCodec_Std97::~MSCodec_Std97 ()
+     rtl_cipher_destroy (m_hCipher);
+ }
+ 
++#if DEBUG_MSO_ENCRYPTION_STD97    
++static void lcl_PrintKeyData(const sal_uInt8* pKeyData, const char* msg)
++{
++    printf("pKeyData: (%s)\n", msg);
++    for (int j = 0; j < 4; ++j)
++    {
++        for (int i = 0; i < 16; ++i)
++            printf("%2.2x ", pKeyData[j*16+i]);
++        printf("\n");
++    }
++}
++#else
++static void lcl_PrintKeyData(const sal_uInt8* /*pKeyData*/, const char* /*msg*/)
++{
++}
++#endif    
++
++#if DEBUG_MSO_ENCRYPTION_STD97    
++static void lcl_PrintDigest(const sal_uInt8* pDigest, const char* msg)
++{
++    printf("digest: (%s)\n", msg);
++    for (int i = 0; i < 16; ++i)
++        printf("%2.2x ", pDigest[i]);
++    printf("\n");
++}
++#else
++static void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*msg*/)
++{
++}
++#endif    
++
+ void MSCodec_Std97::InitKey (
+     const sal_uInt16 pPassData[16],
+     const sal_uInt8  pUnique[16])
+ {
++#if DEBUG_MSO_ENCRYPTION_STD97    
++    fprintf(stdout, "MSCodec_Std97::InitKey: --begin\n");fflush(stdout);
++#endif    
+     sal_uInt8 pKeyData[64];
+     int       i, n;
+ 
+     // Fill PassData into KeyData.
+     (void)memset (pKeyData, 0, sizeof(pKeyData));
++    lcl_PrintKeyData(pKeyData, "initial");
+     for (i = 0, n = 16; (i < n) && pPassData[i]; i++)
+     {
+         pKeyData[2*i    ] = sal::static_int_cast< sal_uInt8 >(
+@@ -260,12 +302,16 @@ void MSCodec_Std97::InitKey (
+     pKeyData[2*i] = 0x80;
+     pKeyData[ 56] = sal::static_int_cast< sal_uInt8 >(i << 4);
+ 
++    lcl_PrintKeyData(pKeyData, "password data");
++
+     // Fill raw digest of KeyData into KeyData.
+     (void)rtl_digest_updateMD5 (
+         m_hDigest, pKeyData, sizeof(pKeyData));
+     (void)rtl_digest_rawMD5 (
+         m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
+ 
++    lcl_PrintKeyData(pKeyData, "raw digest of key data");
++
+     // Update digest with KeyData and Unique.
+     for (i = 0; i < 16; i++)
+     {
+@@ -279,6 +325,8 @@ void MSCodec_Std97::InitKey (
+     pKeyData[56] = 0x80;
+     pKeyData[57] = 0x0a;
+ 
++    lcl_PrintKeyData(pKeyData, "update digest with padding");
++
+     rtl_digest_updateMD5 (
+         m_hDigest, &(pKeyData[16]), sizeof(pKeyData) - 16);
+ 
+@@ -286,6 +334,8 @@ void MSCodec_Std97::InitKey (
+     rtl_digest_rawMD5 (
+         m_hDigest, m_pDigestValue, sizeof(m_pDigestValue));
+ 
++    lcl_PrintDigest(m_pDigestValue, "digest value");
++
+     // Erase KeyData array and leave.
+     (void)memset (pKeyData, 0, sizeof(pKeyData));
+ }
+@@ -294,27 +344,21 @@ bool MSCodec_Std97::VerifyKey (
+     const sal_uInt8 pSaltData[16],
+     const sal_uInt8 pSaltDigest[16])
+ {
++    // both the salt data and salt digest (hash) come from the document being imported.
++
++#if DEBUG_MSO_ENCRYPTION_STD97    
++    fprintf(stdout, "MSCodec_Std97::VerifyKey: \n");
++    lcl_PrintDigest(pSaltData, "salt data");
++    lcl_PrintDigest(pSaltDigest, "salt hash");
++#endif    
+     bool result = false;
+ 
+     if (InitCipher(0))
+     {
+         sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
+-        sal_uInt8 pBuffer[64];
+-
+-        // Decode SaltData into Buffer.
+-        rtl_cipher_decode (
+-            m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer));
+-
+-        pBuffer[16] = 0x80;
+-        (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
+-        pBuffer[56] = 0x80;
+-
+-        // Fill raw digest of Buffer into Digest.
+-        rtl_digest_updateMD5 (
+-            m_hDigest, pBuffer, sizeof(pBuffer));
+-        rtl_digest_rawMD5 (
+-            m_hDigest, pDigest, sizeof(pDigest));
++        GetDigestFromSalt(pSaltData, pDigest);
+ 
++        sal_uInt8 pBuffer[16];
+         // Decode original SaltDigest into Buffer.
+         rtl_cipher_decode (
+             m_hCipher, pSaltDigest, 16, pBuffer, sizeof(pBuffer));
+@@ -333,7 +377,7 @@ bool MSCodec_Std97::VerifyKey (
+ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
+ {
+     rtlCipherError result;
+-    sal_uInt8      pKeyData[64];
++    sal_uInt8      pKeyData[64]; // 512-bit message block
+ 
+     // Initialize KeyData array.
+     (void)memset (pKeyData, 0, sizeof(pKeyData));
+@@ -358,7 +402,7 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
+ 
+     // Initialize Cipher with KeyData (for decoding).
+     result = rtl_cipher_init (
+-        m_hCipher, rtl_Cipher_DirectionDecode,
++        m_hCipher, rtl_Cipher_DirectionBoth,
+         pKeyData, RTL_DIGEST_LENGTH_MD5, 0, 0);
+ 
+     // Erase KeyData array and leave.
+@@ -367,6 +411,38 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
+     return (result == rtl_Cipher_E_None);
+ }
+ 
++bool MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
++{
++#if DEBUG_MSO_ENCRYPTION_STD97
++    lcl_PrintDigest(pSaltData, "salt data");
++#endif    
++    bool result = false;
++
++    if (InitCipher(0))
++    {
++        sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
++        GetDigestFromSalt(nSaltData, pDigest);
++
++        rtl_cipher_decode (
++            m_hCipher, pDigest, 16, pDigest, sizeof(pDigest));
++
++        (void)memcpy(nSaltDigest, pDigest, 16);
++    }
++
++    return (result);
++}
++
++bool MSCodec_Std97::Encode(
++    const void *pData,   sal_Size nDatLen,
++    sal_uInt8  *pBuffer, sal_Size nBufLen)
++{
++    rtlCipherError result;
++    result = rtl_cipher_encode (
++        m_hCipher, pData, nDatLen, pBuffer, nBufLen);
++
++    return (result == rtl_Cipher_E_None);
++}
++
+ bool MSCodec_Std97::Decode (
+     const void *pData,   sal_Size nDatLen,
+     sal_uInt8  *pBuffer, sal_Size nBufLen)
+@@ -395,6 +471,33 @@ bool MSCodec_Std97::Skip( sal_Size nDatLen )
+     return bResult;
+ }
+ 
++void MSCodec_Std97::GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] )
++{
++    sal_uInt8 pBuffer[64];
++    sal_uInt8 pDigestLocal[16];
++
++    // Decode SaltData into Buffer.
++    rtl_cipher_decode (
++        m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer));
++
++    // set the 129th bit to make the buffer 128-bit in length.
++    pBuffer[16] = 0x80;
++
++    // erase the rest of the buffer with zeros.
++    (void)memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
++
++    // set the 441st bit.
++    pBuffer[56] = 0x80;
++
++    // Fill raw digest of Buffer into Digest.
++    rtl_digest_updateMD5 (
++        m_hDigest, pBuffer, sizeof(pBuffer));
++    rtl_digest_rawMD5 (
++        m_hDigest, pDigestLocal, sizeof(pDigestLocal));
++
++    memcpy(pDigest, pDigestLocal, 16);
++}
++
+ // ============================================================================
+ 
+ } // namespace svx



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]