1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "sfx2/securitypage.hxx"
23 #include "sfxresid.hxx"
25 #include <sfx2/sfx.hrc>
26 #include <sfx2/sfxsids.hrc>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/viewsh.hxx>
29 #include <sfx2/dispatch.hxx>
30 #include <sfx2/passwd.hxx>
32 #include <vcl/button.hxx>
33 #include <vcl/edit.hxx>
34 #include <vcl/fixed.hxx>
35 #include <vcl/msgbox.hxx>
36 #include <svl/eitem.hxx>
37 #include <svl/poolitem.hxx>
38 #include <svl/intitem.hxx>
39 #include <svl/PasswordHelper.hxx>
40 #include <svtools/xwindowitem.hxx>
42 #include "../appl/app.hrc"
45 using namespace ::com::sun::star
;
51 enum RedliningMode
{ RL_NONE
, RL_WRITER
, RL_CALC
};
52 enum RedlineFunc
{ RF_ON
, RF_PROTECT
};
54 bool QueryState( sal_uInt16 _nSlot
, bool& _rValue
)
57 SfxViewShell
* pViewSh
= SfxViewShell::Current();
60 const SfxPoolItem
* pItem
;
61 SfxDispatcher
* pDisp
= pViewSh
->GetDispatcher();
62 SfxItemState nState
= pDisp
->QueryState( _nSlot
, pItem
);
63 bRet
= SFX_ITEM_AVAILABLE
<= nState
;
65 _rValue
= ( static_cast< const SfxBoolItem
* >( pItem
) )->GetValue();
71 bool QueryRecordChangesProtectionState( RedliningMode _eMode
, bool& _rValue
)
74 if (_eMode
!= RL_NONE
)
76 sal_uInt16 nSlot
= _eMode
== RL_WRITER
? FN_REDLINE_PROTECT
: SID_CHG_PROTECT
;
77 bRet
= QueryState( nSlot
, _rValue
);
83 bool QueryRecordChangesState( RedliningMode _eMode
, bool& _rValue
)
86 if (_eMode
!= RL_NONE
)
88 sal_uInt16 nSlot
= _eMode
== RL_WRITER
? FN_REDLINE_ON
: FID_CHG_RECORD
;
89 bRet
= QueryState( nSlot
, _rValue
);
96 static short lcl_GetPassword(
99 /*out*/String
&rPassword
)
102 SfxPasswordDialog
aPasswdDlg( pParent
);
103 aPasswdDlg
.SetMinLen( 1 );
105 aPasswdDlg
.ShowExtras( SHOWEXTRAS_CONFIRM
);
106 if (RET_OK
== aPasswdDlg
.Execute() && aPasswdDlg
.GetPassword().Len() > 0)
108 rPassword
= aPasswdDlg
.GetPassword();
115 static bool lcl_IsPasswordCorrect( const String
&rPassword
)
119 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
120 uno::Sequence
< sal_Int8
> aPasswordHash
;
121 pCurDocShell
->GetProtectionHash( aPasswordHash
);
123 // check if supplied password was correct
124 uno::Sequence
< sal_Int8
> aNewPasswd( aPasswordHash
);
125 SvPasswordHelper::GetHashPassword( aNewPasswd
, rPassword
);
126 if (SvPasswordHelper::CompareHashPassword( aPasswordHash
, rPassword
))
127 bRes
= true; // password was correct
129 InfoBox( NULL
, SFX2_RESSTR(RID_SVXSTR_INCORRECT_PASSWORD
) ).Execute();
135 struct SfxSecurityPage_Impl
137 SfxSecurityPage
& m_rMyTabPage
;
139 CheckBox
* m_pOpenReadonlyCB
;
140 CheckBox
* m_pRecordChangesCB
; // for record changes
141 PushButton
* m_pProtectPB
; // for record changes
142 PushButton
* m_pUnProtectPB
; // for record changes
143 RedliningMode m_eRedlingMode
; // for record changes
145 bool m_bOrigPasswordIsConfirmed
;
146 bool m_bNewPasswordIsValid
;
147 String m_aNewPassword
;
149 String m_aEndRedliningWarning
;
150 bool m_bEndRedliningWarningDone
;
152 DECL_LINK( RecordChangesCBToggleHdl
, void* );
153 DECL_LINK( ChangeProtectionPBHdl
, void* );
155 SfxSecurityPage_Impl( SfxSecurityPage
&rDlg
, const SfxItemSet
&rItemSet
);
156 ~SfxSecurityPage_Impl();
158 sal_Bool
FillItemSet_Impl( SfxItemSet
& );
159 void Reset_Impl( const SfxItemSet
& );
163 SfxSecurityPage_Impl::SfxSecurityPage_Impl( SfxSecurityPage
&rTabPage
, const SfxItemSet
& ) :
164 m_rMyTabPage (rTabPage
),
165 m_eRedlingMode ( RL_NONE
),
166 m_bOrigPasswordIsConfirmed ( false ),
167 m_bNewPasswordIsValid ( false ),
168 m_aEndRedliningWarning ( SFX2_RESSTR(RID_SVXSTR_END_REDLINING_WARNING
) ),
169 m_bEndRedliningWarningDone ( false )
171 rTabPage
.get(m_pOpenReadonlyCB
, "readonly");
172 rTabPage
.get(m_pRecordChangesCB
, "recordchanges");
173 rTabPage
.get(m_pProtectPB
, "protect");
174 rTabPage
.get(m_pUnProtectPB
, "unprotect");
175 m_pProtectPB
->Show();
176 m_pUnProtectPB
->Hide();
178 // force toggle hdl called before visual change of checkbox
179 m_pRecordChangesCB
->SetStyle( m_pRecordChangesCB
->GetStyle() | WB_EARLYTOGGLE
);
180 m_pRecordChangesCB
->SetToggleHdl( LINK( this, SfxSecurityPage_Impl
, RecordChangesCBToggleHdl
) );
181 m_pProtectPB
->SetClickHdl( LINK( this, SfxSecurityPage_Impl
, ChangeProtectionPBHdl
) );
182 m_pUnProtectPB
->SetClickHdl( LINK( this, SfxSecurityPage_Impl
, ChangeProtectionPBHdl
) );
186 SfxSecurityPage_Impl::~SfxSecurityPage_Impl()
191 sal_Bool
SfxSecurityPage_Impl::FillItemSet_Impl( SfxItemSet
& )
193 bool bModified
= false;
195 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
196 if (pCurDocShell
&& !pCurDocShell
->IsReadOnly())
198 if (m_eRedlingMode
!= RL_NONE
)
200 const bool bDoRecordChanges
= m_pRecordChangesCB
->IsChecked();
201 const bool bDoChangeProtection
= m_pUnProtectPB
->IsVisible();
204 DBG_ASSERT( bDoRecordChanges
|| !bDoChangeProtection
, "no change recording should imply no change protection" );
205 DBG_ASSERT( bDoChangeProtection
|| !bDoRecordChanges
, "no change protection should imply no change recording" );
206 DBG_ASSERT( !bDoChangeProtection
|| m_aNewPassword
.Len() > 0, "change protection should imply password length is > 0" );
207 DBG_ASSERT( bDoChangeProtection
|| m_aNewPassword
.Len() == 0, "no change protection should imply password length is 0" );
210 if (bDoRecordChanges
!= pCurDocShell
->IsChangeRecording())
212 pCurDocShell
->SetChangeRecording( bDoRecordChanges
);
216 // change record protection
217 if (m_bNewPasswordIsValid
&&
218 bDoChangeProtection
!= pCurDocShell
->HasChangeRecordProtection())
220 DBG_ASSERT( !bDoChangeProtection
|| bDoRecordChanges
,
221 "change protection requires record changes to be active!" );
222 pCurDocShell
->SetProtectionPassword( m_aNewPassword
);
228 const sal_Bool bDoOpenReadonly
= m_pOpenReadonlyCB
->IsChecked();
229 if (pCurDocShell
->HasSecurityOptOpenReadOnly() &&
230 bDoOpenReadonly
!= pCurDocShell
->IsSecurityOptOpenReadOnly())
232 pCurDocShell
->SetSecurityOptOpenReadOnly( bDoOpenReadonly
);
241 void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet
& )
243 SfxObjectShell
* pCurDocShell
= SfxObjectShell::Current();
247 // no doc -> hide document settings
248 m_pOpenReadonlyCB
->Disable();
249 m_pRecordChangesCB
->Disable();
250 m_pProtectPB
->Show();
251 m_pProtectPB
->Disable();
252 m_pUnProtectPB
->Hide();
253 m_pUnProtectPB
->Disable();
257 bool bIsHTMLDoc
= false;
258 bool bProtect
= true, bUnProtect
= false;
259 SfxViewShell
* pViewSh
= SfxViewShell::Current();
262 const SfxPoolItem
* pItem
;
263 SfxDispatcher
* pDisp
= pViewSh
->GetDispatcher();
264 if (SFX_ITEM_AVAILABLE
<= pDisp
->QueryState( SID_HTML_MODE
, pItem
))
266 sal_uInt16 nMode
= static_cast< const SfxUInt16Item
* >( pItem
)->GetValue();
267 bIsHTMLDoc
= ( ( nMode
& HTMLMODE_ON
) != 0 );
271 sal_Bool bIsReadonly
= pCurDocShell
->IsReadOnly();
272 if (pCurDocShell
->HasSecurityOptOpenReadOnly() && !bIsHTMLDoc
)
274 m_pOpenReadonlyCB
->Check( pCurDocShell
->IsSecurityOptOpenReadOnly() );
275 m_pOpenReadonlyCB
->Enable( !bIsReadonly
);
278 m_pOpenReadonlyCB
->Disable();
281 if (QueryRecordChangesState( RL_WRITER
, bRecordChanges
) && !bIsHTMLDoc
)
282 m_eRedlingMode
= RL_WRITER
;
283 else if (QueryRecordChangesState( RL_CALC
, bRecordChanges
))
284 m_eRedlingMode
= RL_CALC
;
286 m_eRedlingMode
= RL_NONE
;
288 if (m_eRedlingMode
!= RL_NONE
)
291 QueryRecordChangesProtectionState( m_eRedlingMode
, bProtection
);
293 m_pProtectPB
->Enable( !bIsReadonly
);
294 m_pUnProtectPB
->Enable( !bIsReadonly
);
295 // set the right text
302 m_pRecordChangesCB
->Check( bRecordChanges
);
303 m_pRecordChangesCB
->Enable( /*!bProtection && */!bIsReadonly
);
305 m_bOrigPasswordIsConfirmed
= true; // default case if no password is set
306 uno::Sequence
< sal_Int8
> aPasswordHash
;
307 // check if password is available
308 if (pCurDocShell
->GetProtectionHash( aPasswordHash
) &&
309 aPasswordHash
.getLength() > 0)
310 m_bOrigPasswordIsConfirmed
= false; // password found, needs to be confirmed later on
314 // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE'
315 // In shared documents change recording and protection must be disabled,
316 // similar to documents that do not support change recording at all.
317 m_pRecordChangesCB
->Check( sal_False
);
318 m_pRecordChangesCB
->Disable();
319 m_pProtectPB
->Check( sal_False
);
320 m_pUnProtectPB
->Check( sal_False
);
321 m_pProtectPB
->Disable();
322 m_pUnProtectPB
->Disable();
325 m_pProtectPB
->Show(bProtect
);
326 m_pUnProtectPB
->Show(bUnProtect
);
331 IMPL_LINK_NOARG(SfxSecurityPage_Impl
, RecordChangesCBToggleHdl
)
333 // when change recording gets disabled protection must be disabled as well
334 if (!m_pRecordChangesCB
->IsChecked()) // the new check state is already present, thus the '!'
336 bool bAlreadyDone
= false;
337 if (!m_bEndRedliningWarningDone
)
339 WarningBox
aBox( m_rMyTabPage
.GetParent(), WinBits(WB_YES_NO
| WB_DEF_NO
),
340 m_aEndRedliningWarning
);
341 if (aBox
.Execute() != RET_YES
)
344 m_bEndRedliningWarningDone
= true;
347 const bool bNeedPasssword
= !m_bOrigPasswordIsConfirmed
348 && m_pProtectPB
->IsVisible();
349 if (!bAlreadyDone
&& bNeedPasssword
)
351 String aPasswordText
;
353 // dialog canceled or no password provided
354 if (!lcl_GetPassword( m_rMyTabPage
.GetParent(), false, aPasswordText
))
357 // ask for password and if dialog is canceled or no password provided return
358 if (lcl_IsPasswordCorrect( aPasswordText
))
359 m_bOrigPasswordIsConfirmed
= true;
365 m_pRecordChangesCB
->Check( true ); // restore original state
368 // remember required values to change protection and change recording in
369 // FillItemSet_Impl later on if password was correct.
370 m_bNewPasswordIsValid
= true;
371 m_aNewPassword
= String();
372 m_pProtectPB
->Show();
373 m_pUnProtectPB
->Hide();
381 IMPL_LINK_NOARG(SfxSecurityPage_Impl
, ChangeProtectionPBHdl
)
383 if (m_eRedlingMode
== RL_NONE
)
386 // the push button text is always the opposite of the current state. Thus:
387 const bool bCurrentProtection
= m_pUnProtectPB
->IsVisible();
389 // ask user for password (if still necessary)
390 String aPasswordText
;
391 bool bNewProtection
= !bCurrentProtection
;
392 const bool bNeedPassword
= bNewProtection
|| !m_bOrigPasswordIsConfirmed
;
395 // ask for password and if dialog is canceled or no password provided return
396 if (!lcl_GetPassword( m_rMyTabPage
.GetParent(), bNewProtection
, aPasswordText
))
399 // provided password still needs to be checked?
400 if (!bNewProtection
&& !m_bOrigPasswordIsConfirmed
)
402 if (lcl_IsPasswordCorrect( aPasswordText
))
403 m_bOrigPasswordIsConfirmed
= true;
408 DBG_ASSERT( m_bOrigPasswordIsConfirmed
, "ooops... this should not have happened!" );
410 // remember required values to change protection and change recording in
411 // FillItemSet_Impl later on if password was correct.
412 m_bNewPasswordIsValid
= true;
413 m_aNewPassword
= bNewProtection
? aPasswordText
: String();
415 m_pRecordChangesCB
->Check( bNewProtection
);
417 m_pUnProtectPB
->Show(bNewProtection
);
418 m_pProtectPB
->Show(!bNewProtection
);
424 SfxTabPage
* SfxSecurityPage::Create( Window
* pParent
, const SfxItemSet
& rItemSet
)
426 return new SfxSecurityPage( pParent
, rItemSet
);
430 SfxSecurityPage::SfxSecurityPage( Window
* pParent
, const SfxItemSet
& rItemSet
)
431 : SfxTabPage(pParent
, "SecurityInfoPage", "sfx/ui/securityinfopage.ui", rItemSet
)
433 m_pImpl
= std::auto_ptr
< SfxSecurityPage_Impl
>(new SfxSecurityPage_Impl( *this, rItemSet
));
437 SfxSecurityPage::~SfxSecurityPage()
442 sal_Bool
SfxSecurityPage::FillItemSet( SfxItemSet
& rItemSet
)
444 bool bModified
= false;
445 DBG_ASSERT( m_pImpl
.get(), "implementation pointer is 0. Still in c-tor?" );
446 if (m_pImpl
.get() != 0)
447 bModified
= m_pImpl
->FillItemSet_Impl( rItemSet
);
452 void SfxSecurityPage::Reset( const SfxItemSet
& rItemSet
)
454 DBG_ASSERT( m_pImpl
.get(), "implementation pointer is 0. Still in c-tor?" );
455 if (m_pImpl
.get() != 0)
456 m_pImpl
->Reset_Impl( rItemSet
);
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */