1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "sfx2/securitypage.hxx"
32 #include "securitypage.hrc"
33 #include "sfxresid.hxx"
35 #include <sfx2/sfx.hrc>
36 #include <sfx2/sfxsids.hrc>
37 #include <sfx2/objsh.hxx>
38 #include <sfx2/viewsh.hxx>
39 #include <sfx2/dispatch.hxx>
40 #include <sfx2/passwd.hxx>
42 #include <vcl/button.hxx>
43 #include <vcl/edit.hxx>
44 #include <vcl/fixed.hxx>
45 #include <vcl/msgbox.hxx>
46 #include <svl/eitem.hxx>
47 #include <svl/poolitem.hxx>
48 #include <svl/intitem.hxx>
49 #include <svl/PasswordHelper.hxx>
50 #include <svtools/xwindowitem.hxx>
53 using namespace ::com::sun::star
;
59 enum RedliningMode
{ RL_NONE
, RL_WRITER
, RL_CALC
};
60 enum RedlineFunc
{ RF_ON
, RF_PROTECT
};
62 bool QueryState( sal_uInt16 _nSlot
, bool& _rValue
)
65 SfxViewShell
* pViewSh
= SfxViewShell::Current();
68 const SfxPoolItem
* pItem
;
69 SfxDispatcher
* pDisp
= pViewSh
->GetDispatcher();
70 SfxItemState nState
= pDisp
->QueryState( _nSlot
, pItem
);
71 bRet
= SFX_ITEM_AVAILABLE
<= nState
;
73 _rValue
= ( static_cast< const SfxBoolItem
* >( pItem
) )->GetValue();
79 bool QueryRecordChangesProtectionState( RedliningMode _eMode
, bool& _rValue
)
82 if (_eMode
!= RL_NONE
)
84 sal_uInt16 nSlot
= _eMode
== RL_WRITER
? FN_REDLINE_PROTECT
: SID_CHG_PROTECT
;
85 bRet
= QueryState( nSlot
, _rValue
);
91 bool QueryRecordChangesState( RedliningMode _eMode
, bool& _rValue
)
94 if (_eMode
!= RL_NONE
)
96 sal_uInt16 nSlot
= _eMode
== RL_WRITER
? FN_REDLINE_ON
: FID_CHG_RECORD
;
97 bRet
= QueryState( nSlot
, _rValue
);
104 static short lcl_GetPassword(
107 /*out*/String
&rPassword
)
110 SfxPasswordDialog
aPasswdDlg( pParent
);
111 aPasswdDlg
.SetMinLen( 1 );
113 aPasswdDlg
.ShowExtras( SHOWEXTRAS_CONFIRM
);
114 if (RET_OK
== aPasswdDlg
.Execute() && aPasswdDlg
.GetPassword().Len() > 0)
116 rPassword
= aPasswdDlg
.GetPassword();
123 static bool lcl_IsPasswordCorrect( const String
&rPassword
)
127 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
128 uno::Sequence
< sal_Int8
> aPasswordHash
;
129 pCurDocShell
->GetProtectionHash( aPasswordHash
);
131 // check if supplied password was correct
132 uno::Sequence
< sal_Int8
> aNewPasswd( aPasswordHash
);
133 SvPasswordHelper::GetHashPassword( aNewPasswd
, rPassword
);
134 if (SvPasswordHelper::CompareHashPassword( aPasswordHash
, rPassword
))
135 bRes
= true; // password was correct
137 InfoBox( NULL
, String( SfxResId( RID_SFX_INCORRECT_PASSWORD
) ) ).Execute();
143 struct SfxSecurityPage_Impl
145 SfxSecurityPage
& m_rMyTabPage
;
147 FixedLine m_aNewPasswordToOpenFL
;
148 FixedText m_aNewPasswordToOpenFT
;
149 Edit m_aNewPasswordToOpenED
;
150 FixedText m_aConfirmPasswordToOpenFT
;
151 Edit m_aConfirmPasswordToOpenED
;
152 FixedText m_aNewPasswordInfoFT
;
154 FixedLine m_aNewPasswordToModifyFL
;
155 FixedText m_aNewPasswordToModifyFT
;
156 Edit m_aNewPasswordToModifyED
;
157 FixedText m_aConfirmPasswordToModifyFT
;
158 Edit m_aConfirmPasswordToModifyED
;
160 FixedLine m_aOptionsFL
;
161 CheckBox m_aOpenReadonlyCB
;
162 CheckBox m_aRecordChangesCB
; // for record changes
163 PushButton m_aChangeProtectionPB
; // for record changes
164 String m_aProtectSTR
; // for record changes
165 String m_aUnProtectSTR
; // for record changes
166 RedliningMode m_eRedlingMode
; // for record changes
168 bool m_bOrigPasswordIsConfirmed
;
169 bool m_bNewPasswordIsValid
;
170 String m_aNewPassword
;
172 String m_aEndRedliningWarning
;
173 bool m_bEndRedliningWarningDone
;
175 DECL_LINK( RecordChangesCBToggleHdl
, void* );
176 DECL_LINK( ChangeProtectionPBHdl
, void* );
178 SfxSecurityPage_Impl( SfxSecurityPage
&rDlg
, const SfxItemSet
&rItemSet
);
179 ~SfxSecurityPage_Impl();
181 sal_Bool
FillItemSet_Impl( SfxItemSet
& );
182 void Reset_Impl( const SfxItemSet
& );
186 SfxSecurityPage_Impl::SfxSecurityPage_Impl( SfxSecurityPage
&rTabPage
, const SfxItemSet
& ) :
187 m_rMyTabPage (rTabPage
),
188 m_aNewPasswordToOpenFL (&rTabPage
, SfxResId( PASSWORD_TO_OPEN_FL
) ),
189 m_aNewPasswordToOpenFT (&rTabPage
, SfxResId( PASSWORD_TO_OPEN_FT
) ),
190 m_aNewPasswordToOpenED (&rTabPage
, SfxResId( PASSWORD_TO_OPEN_ED
) ),
191 m_aConfirmPasswordToOpenFT (&rTabPage
, SfxResId( CONFIRM_PASSWORD_TO_OPEN_FT
) ),
192 m_aConfirmPasswordToOpenED (&rTabPage
, SfxResId( CONFIRM_PASSWORD_TO_OPEN_ED
) ),
193 m_aNewPasswordInfoFT (&rTabPage
, SfxResId( PASSWORD_INFO_FT
) ),
194 m_aNewPasswordToModifyFL (&rTabPage
, SfxResId( PASSWORD_TO_MODIFY_FL
) ),
195 m_aNewPasswordToModifyFT (&rTabPage
, SfxResId( PASSWORD_TO_MODIFY_FT
) ),
196 m_aNewPasswordToModifyED (&rTabPage
, SfxResId( PASSWORD_TO_MODIFY_ED
) ),
197 m_aConfirmPasswordToModifyFT (&rTabPage
, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_FT
) ),
198 m_aConfirmPasswordToModifyED (&rTabPage
, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_ED
) ),
199 m_aOptionsFL (&rTabPage
, SfxResId( OPTIONS_FL
) ),
200 m_aOpenReadonlyCB (&rTabPage
, SfxResId( OPEN_READONLY_CB
) ),
201 m_aRecordChangesCB (&rTabPage
, SfxResId( RECORD_CHANGES_CB
) ),
202 m_aChangeProtectionPB (&rTabPage
, SfxResId( CHANGE_PROTECTION_PB
) ),
203 m_aProtectSTR ( SfxResId( STR_PROTECT
) ),
204 m_aUnProtectSTR ( SfxResId( STR_UNPROTECT
) ),
205 m_eRedlingMode ( RL_NONE
),
206 m_bOrigPasswordIsConfirmed ( false ),
207 m_bNewPasswordIsValid ( false ),
208 m_aEndRedliningWarning ( SfxResId( STR_END_REDLINING_WARNING
) ),
209 m_bEndRedliningWarningDone ( false )
211 m_aChangeProtectionPB
.SetText( m_aProtectSTR
);
212 // adjust button width if necessary
213 long nBtnTextWidth
= 0;
214 long nTemp
= m_aChangeProtectionPB
.GetCtrlTextWidth( m_aChangeProtectionPB
.GetText() );
215 if (nTemp
> nBtnTextWidth
)
216 nBtnTextWidth
= nTemp
;
218 // force toggle hdl called before visual change of checkbox
219 m_aRecordChangesCB
.SetStyle( m_aRecordChangesCB
.GetStyle() | WB_EARLYTOGGLE
);
220 m_aRecordChangesCB
.SetToggleHdl( LINK( this, SfxSecurityPage_Impl
, RecordChangesCBToggleHdl
) );
221 m_aChangeProtectionPB
.SetClickHdl( LINK( this, SfxSecurityPage_Impl
, ChangeProtectionPBHdl
) );
224 // #i112277: for the time being (OOO 3.3) the following options should not
225 // be available. In the long run however it is planned to implement the yet
226 // missing functionality. Thus now we hide them and move the remaining ones up.
227 m_aNewPasswordToOpenFL
.Hide();
228 m_aNewPasswordToOpenFT
.Hide();
229 m_aNewPasswordToOpenED
.Hide();
230 m_aConfirmPasswordToOpenFT
.Hide();
231 m_aConfirmPasswordToOpenED
.Hide();
232 m_aNewPasswordInfoFT
.Hide();
233 m_aNewPasswordToModifyFL
.Hide();
234 m_aNewPasswordToModifyFT
.Hide();
235 m_aNewPasswordToModifyED
.Hide();
236 m_aConfirmPasswordToModifyFT
.Hide();
237 m_aConfirmPasswordToModifyED
.Hide();
238 const long nDelta
= m_aOptionsFL
.GetPosPixel().Y() - m_aNewPasswordToOpenFL
.GetPosPixel().Y();
240 aPos
= m_aOptionsFL
.GetPosPixel();
242 m_aOptionsFL
.SetPosPixel( aPos
);
243 aPos
= m_aOpenReadonlyCB
.GetPosPixel();
245 m_aOpenReadonlyCB
.SetPosPixel( aPos
);
246 aPos
= m_aRecordChangesCB
.GetPosPixel();
248 m_aRecordChangesCB
.SetPosPixel( aPos
);
249 aPos
= m_aChangeProtectionPB
.GetPosPixel();
251 m_aChangeProtectionPB
.SetPosPixel( aPos
);
255 SfxSecurityPage_Impl::~SfxSecurityPage_Impl()
260 sal_Bool
SfxSecurityPage_Impl::FillItemSet_Impl( SfxItemSet
& )
262 bool bModified
= false;
264 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
265 if (pCurDocShell
&& !pCurDocShell
->IsReadOnly())
267 if (m_eRedlingMode
!= RL_NONE
)
269 const bool bDoRecordChanges
= m_aRecordChangesCB
.IsChecked();
270 const bool bDoChangeProtection
= m_aChangeProtectionPB
.GetText() != m_aProtectSTR
;
273 DBG_ASSERT( bDoRecordChanges
|| !bDoChangeProtection
, "no change recording should imply no change protection" );
274 DBG_ASSERT( bDoChangeProtection
|| !bDoRecordChanges
, "no change protection should imply no change recording" );
275 DBG_ASSERT( !bDoChangeProtection
|| m_aNewPassword
.Len() > 0, "change protection should imply password length is > 0" );
276 DBG_ASSERT( bDoChangeProtection
|| m_aNewPassword
.Len() == 0, "no change protection should imply password length is 0" );
279 if (bDoRecordChanges
!= pCurDocShell
->IsChangeRecording())
281 pCurDocShell
->SetChangeRecording( bDoRecordChanges
);
285 // change record protection
286 if (m_bNewPasswordIsValid
&&
287 bDoChangeProtection
!= pCurDocShell
->HasChangeRecordProtection())
289 DBG_ASSERT( !bDoChangeProtection
|| bDoRecordChanges
,
290 "change protection requires record changes to be active!" );
291 pCurDocShell
->SetProtectionPassword( m_aNewPassword
);
297 const sal_Bool bDoOpenReadonly
= m_aOpenReadonlyCB
.IsChecked();
298 if (pCurDocShell
->HasSecurityOptOpenReadOnly() &&
299 bDoOpenReadonly
!= pCurDocShell
->IsSecurityOptOpenReadOnly())
301 pCurDocShell
->SetSecurityOptOpenReadOnly( bDoOpenReadonly
);
310 void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet
& )
312 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
314 String sNewText
= m_aProtectSTR
;
317 // no doc -> hide document settings
318 m_aOpenReadonlyCB
.Disable();
319 m_aRecordChangesCB
.Disable();
320 m_aChangeProtectionPB
.Disable();
324 bool bIsHTMLDoc
= false;
325 SfxViewShell
* pViewSh
= SfxViewShell::Current();
328 const SfxPoolItem
* pItem
;
329 SfxDispatcher
* pDisp
= pViewSh
->GetDispatcher();
330 if (SFX_ITEM_AVAILABLE
<= pDisp
->QueryState( SID_HTML_MODE
, pItem
))
332 sal_uInt16 nMode
= static_cast< const SfxUInt16Item
* >( pItem
)->GetValue();
333 bIsHTMLDoc
= ( ( nMode
& HTMLMODE_ON
) != 0 );
337 sal_Bool bIsReadonly
= pCurDocShell
->IsReadOnly();
338 if (pCurDocShell
->HasSecurityOptOpenReadOnly() && !bIsHTMLDoc
)
340 m_aOpenReadonlyCB
.Check( pCurDocShell
->IsSecurityOptOpenReadOnly() );
341 m_aOpenReadonlyCB
.Enable( !bIsReadonly
);
344 m_aOpenReadonlyCB
.Disable();
347 if (QueryRecordChangesState( RL_WRITER
, bRecordChanges
) && !bIsHTMLDoc
)
348 m_eRedlingMode
= RL_WRITER
;
349 else if (QueryRecordChangesState( RL_CALC
, bRecordChanges
))
350 m_eRedlingMode
= RL_CALC
;
352 m_eRedlingMode
= RL_NONE
;
354 if (m_eRedlingMode
!= RL_NONE
)
357 QueryRecordChangesProtectionState( m_eRedlingMode
, bProtection
);
359 m_aChangeProtectionPB
.Enable( !bIsReadonly
);
360 // set the right text
362 sNewText
= m_aUnProtectSTR
;
364 m_aRecordChangesCB
.Check( bRecordChanges
);
365 m_aRecordChangesCB
.Enable( /*!bProtection && */!bIsReadonly
);
367 m_bOrigPasswordIsConfirmed
= true; // default case if no password is set
368 uno::Sequence
< sal_Int8
> aPasswordHash
;
369 // check if password is available
370 if (pCurDocShell
->GetProtectionHash( aPasswordHash
) &&
371 aPasswordHash
.getLength() > 0)
372 m_bOrigPasswordIsConfirmed
= false; // password found, needs to be confirmed later on
376 // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE'
377 // In shared documents change recording and protection must be disabled,
378 // similar to documents that do not support change recording at all.
379 m_aRecordChangesCB
.Check( sal_False
);
380 m_aRecordChangesCB
.Disable();
381 m_aChangeProtectionPB
.Check( sal_False
);
382 m_aChangeProtectionPB
.Disable();
386 m_aChangeProtectionPB
.SetText( sNewText
);
390 IMPL_LINK_NOARG(SfxSecurityPage_Impl
, RecordChangesCBToggleHdl
)
392 // when change recording gets disabled protection must be disabled as well
393 if (!m_aRecordChangesCB
.IsChecked()) // the new check state is already present, thus the '!'
395 bool bAlreadyDone
= false;
396 if (!m_bEndRedliningWarningDone
)
398 WarningBox
aBox( m_rMyTabPage
.GetParent(), WinBits(WB_YES_NO
| WB_DEF_NO
),
399 m_aEndRedliningWarning
);
400 if (aBox
.Execute() != RET_YES
)
403 m_bEndRedliningWarningDone
= true;
406 const bool bNeedPasssword
= !m_bOrigPasswordIsConfirmed
407 && m_aChangeProtectionPB
.GetText() != m_aProtectSTR
;
408 if (!bAlreadyDone
&& bNeedPasssword
)
410 String aPasswordText
;
412 // dialog canceled or no password provided
413 if (!lcl_GetPassword( m_rMyTabPage
.GetParent(), false, aPasswordText
))
416 // ask for password and if dialog is canceled or no password provided return
417 if (lcl_IsPasswordCorrect( aPasswordText
))
418 m_bOrigPasswordIsConfirmed
= true;
424 m_aRecordChangesCB
.Check( true ); // restore original state
427 // remember required values to change protection and change recording in
428 // FillItemSet_Impl later on if password was correct.
429 m_bNewPasswordIsValid
= true;
430 m_aNewPassword
= String();
432 m_aChangeProtectionPB
.SetText( m_aProtectSTR
);
440 IMPL_LINK_NOARG(SfxSecurityPage_Impl
, ChangeProtectionPBHdl
)
442 if (m_eRedlingMode
== RL_NONE
)
445 // the push button text is always the opposite of the current state. Thus:
446 const bool bCurrentProtection
= m_aChangeProtectionPB
.GetText() != m_aProtectSTR
;
448 // ask user for password (if still necessary)
449 String aPasswordText
;
450 bool bNewProtection
= !bCurrentProtection
;
451 const bool bNeedPassword
= bNewProtection
|| !m_bOrigPasswordIsConfirmed
;
454 // ask for password and if dialog is canceled or no password provided return
455 if (!lcl_GetPassword( m_rMyTabPage
.GetParent(), bNewProtection
, aPasswordText
))
458 // provided password still needs to be checked?
459 if (!bNewProtection
&& !m_bOrigPasswordIsConfirmed
)
461 if (lcl_IsPasswordCorrect( aPasswordText
))
462 m_bOrigPasswordIsConfirmed
= true;
467 DBG_ASSERT( m_bOrigPasswordIsConfirmed
, "ooops... this should not have happened!" );
469 // remember required values to change protection and change recording in
470 // FillItemSet_Impl later on if password was correct.
471 m_bNewPasswordIsValid
= true;
472 m_aNewPassword
= bNewProtection
? aPasswordText
: String();
474 m_aRecordChangesCB
.Check( bNewProtection
);
475 // toggle text of button "Protect" <-> "Unprotect"
476 m_aChangeProtectionPB
.SetText( bNewProtection
? m_aUnProtectSTR
: m_aProtectSTR
);
482 SfxTabPage
* SfxSecurityPage::Create( Window
* pParent
, const SfxItemSet
& rItemSet
)
484 return new SfxSecurityPage( pParent
, rItemSet
);
488 SfxSecurityPage::SfxSecurityPage( Window
* pParent
, const SfxItemSet
& rItemSet
) :
489 SfxTabPage( pParent
, SfxResId( TP_DOCINFOSECURITY
), rItemSet
)
491 m_pImpl
= std::auto_ptr
< SfxSecurityPage_Impl
>(new SfxSecurityPage_Impl( *this, rItemSet
));
497 SfxSecurityPage::~SfxSecurityPage()
502 sal_Bool
SfxSecurityPage::FillItemSet( SfxItemSet
& rItemSet
)
504 bool bModified
= false;
505 DBG_ASSERT( m_pImpl
.get(), "implementation pointer is 0. Still in c-tor?" );
506 if (m_pImpl
.get() != 0)
507 bModified
= m_pImpl
->FillItemSet_Impl( rItemSet
);
512 void SfxSecurityPage::Reset( const SfxItemSet
& rItemSet
)
514 DBG_ASSERT( m_pImpl
.get(), "implementation pointer is 0. Still in c-tor?" );
515 if (m_pImpl
.get() != 0)
516 m_pImpl
->Reset_Impl( rItemSet
);
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */