Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / dialog / securitypage.cxx
blob22efcf333ebbd66c81ee7a6043075fff958de820
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;
57 namespace
59 enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC };
60 enum RedlineFunc { RF_ON, RF_PROTECT };
62 bool QueryState( sal_uInt16 _nSlot, bool& _rValue )
64 bool bRet = false;
65 SfxViewShell* pViewSh = SfxViewShell::Current();
66 if (pViewSh)
68 const SfxPoolItem* pItem;
69 SfxDispatcher* pDisp = pViewSh->GetDispatcher();
70 SfxItemState nState = pDisp->QueryState( _nSlot, pItem );
71 bRet = SFX_ITEM_AVAILABLE <= nState;
72 if (bRet)
73 _rValue = ( static_cast< const SfxBoolItem* >( pItem ) )->GetValue();
75 return bRet;
79 bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue )
81 bool bRet = false;
82 if (_eMode != RL_NONE)
84 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT;
85 bRet = QueryState( nSlot, _rValue );
87 return bRet;
91 bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue )
93 bool bRet = false;
94 if (_eMode != RL_NONE)
96 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD;
97 bRet = QueryState( nSlot, _rValue );
99 return bRet;
104 static short lcl_GetPassword(
105 Window *pParent,
106 bool bProtect,
107 /*out*/String &rPassword )
109 bool bRes = false;
110 SfxPasswordDialog aPasswdDlg( pParent );
111 aPasswdDlg.SetMinLen( 1 );
112 if (bProtect)
113 aPasswdDlg.ShowExtras( SHOWEXTRAS_CONFIRM );
114 if (RET_OK == aPasswdDlg.Execute() && aPasswdDlg.GetPassword().Len() > 0)
116 rPassword = aPasswdDlg.GetPassword();
117 bRes = true;
119 return bRes;
123 static bool lcl_IsPasswordCorrect( const String &rPassword )
125 bool bRes = false;
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
136 else
137 InfoBox( NULL, String( SfxResId( RID_SFX_INCORRECT_PASSWORD ) ) ).Execute();
139 return bRes;
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();
239 Point aPos;
240 aPos = m_aOptionsFL.GetPosPixel();
241 aPos.Y() -= nDelta;
242 m_aOptionsFL.SetPosPixel( aPos );
243 aPos = m_aOpenReadonlyCB.GetPosPixel();
244 aPos.Y() -= nDelta;
245 m_aOpenReadonlyCB.SetPosPixel( aPos );
246 aPos = m_aRecordChangesCB.GetPosPixel();
247 aPos.Y() -= nDelta;
248 m_aRecordChangesCB.SetPosPixel( aPos );
249 aPos = m_aChangeProtectionPB.GetPosPixel();
250 aPos.Y() -= nDelta;
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;
272 // sanity checks
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" );
278 // change recording
279 if (bDoRecordChanges != pCurDocShell->IsChangeRecording())
281 pCurDocShell->SetChangeRecording( bDoRecordChanges );
282 bModified = true;
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 );
292 bModified = true;
296 // open read-only?
297 const sal_Bool bDoOpenReadonly = m_aOpenReadonlyCB.IsChecked();
298 if (pCurDocShell->HasSecurityOptOpenReadOnly() &&
299 bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly())
301 pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly );
302 bModified = true;
306 return bModified;
310 void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet & )
312 SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
314 String sNewText = m_aProtectSTR;
315 if (!pCurDocShell)
317 // no doc -> hide document settings
318 m_aOpenReadonlyCB.Disable();
319 m_aRecordChangesCB.Disable();
320 m_aChangeProtectionPB.Disable();
322 else
324 bool bIsHTMLDoc = false;
325 SfxViewShell* pViewSh = SfxViewShell::Current();
326 if (pViewSh)
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 );
343 else
344 m_aOpenReadonlyCB.Disable();
346 bool bRecordChanges;
347 if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc)
348 m_eRedlingMode = RL_WRITER;
349 else if (QueryRecordChangesState( RL_CALC, bRecordChanges ))
350 m_eRedlingMode = RL_CALC;
351 else
352 m_eRedlingMode = RL_NONE;
354 if (m_eRedlingMode != RL_NONE)
356 bool bProtection;
357 QueryRecordChangesProtectionState( m_eRedlingMode, bProtection );
359 m_aChangeProtectionPB.Enable( !bIsReadonly );
360 // set the right text
361 if (bProtection)
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
374 else
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)
401 bAlreadyDone = true;
402 else
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 ))
414 bAlreadyDone = true;
416 // ask for password and if dialog is canceled or no password provided return
417 if (lcl_IsPasswordCorrect( aPasswordText ))
418 m_bOrigPasswordIsConfirmed = true;
419 else
420 bAlreadyDone = true;
423 if (bAlreadyDone)
424 m_aRecordChangesCB.Check( true ); // restore original state
425 else
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 );
436 return 0;
440 IMPL_LINK_NOARG(SfxSecurityPage_Impl, ChangeProtectionPBHdl)
442 if (m_eRedlingMode == RL_NONE)
443 return 0;
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;
452 if (bNeedPassword)
454 // ask for password and if dialog is canceled or no password provided return
455 if (!lcl_GetPassword( m_rMyTabPage.GetParent(), bNewProtection, aPasswordText ))
456 return 0;
458 // provided password still needs to be checked?
459 if (!bNewProtection && !m_bOrigPasswordIsConfirmed)
461 if (lcl_IsPasswordCorrect( aPasswordText ))
462 m_bOrigPasswordIsConfirmed = true;
463 else
464 return 0;
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 );
478 return 0;
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 ));
493 FreeResource();
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 );
508 return bModified;
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: */