Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / dialog / securitypage.cxx
blob46f33f5edfa404a326b70606620c38ed39ea8f46
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
49 namespace
51 enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC };
52 enum RedlineFunc { RF_ON, RF_PROTECT };
54 bool QueryState( sal_uInt16 _nSlot, bool& _rValue )
56 bool bRet = false;
57 SfxViewShell* pViewSh = SfxViewShell::Current();
58 if (pViewSh)
60 const SfxPoolItem* pItem;
61 SfxDispatcher* pDisp = pViewSh->GetDispatcher();
62 SfxItemState nState = pDisp->QueryState( _nSlot, pItem );
63 bRet = SFX_ITEM_AVAILABLE <= nState;
64 if (bRet)
65 _rValue = ( static_cast< const SfxBoolItem* >( pItem ) )->GetValue();
67 return bRet;
71 bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue )
73 bool bRet = false;
74 if (_eMode != RL_NONE)
76 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT;
77 bRet = QueryState( nSlot, _rValue );
79 return bRet;
83 bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue )
85 bool bRet = false;
86 if (_eMode != RL_NONE)
88 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD;
89 bRet = QueryState( nSlot, _rValue );
91 return bRet;
96 static short lcl_GetPassword(
97 Window *pParent,
98 bool bProtect,
99 /*out*/String &rPassword )
101 bool bRes = false;
102 SfxPasswordDialog aPasswdDlg( pParent );
103 aPasswdDlg.SetMinLen( 1 );
104 if (bProtect)
105 aPasswdDlg.ShowExtras( SHOWEXTRAS_CONFIRM );
106 if (RET_OK == aPasswdDlg.Execute() && aPasswdDlg.GetPassword().Len() > 0)
108 rPassword = aPasswdDlg.GetPassword();
109 bRes = true;
111 return bRes;
115 static bool lcl_IsPasswordCorrect( const String &rPassword )
117 bool bRes = false;
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
128 else
129 InfoBox( NULL, SFX2_RESSTR(RID_SVXSTR_INCORRECT_PASSWORD) ).Execute();
131 return bRes;
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();
203 // sanity checks
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" );
209 // change recording
210 if (bDoRecordChanges != pCurDocShell->IsChangeRecording())
212 pCurDocShell->SetChangeRecording( bDoRecordChanges );
213 bModified = true;
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 );
223 bModified = true;
227 // open read-only?
228 const sal_Bool bDoOpenReadonly = m_pOpenReadonlyCB->IsChecked();
229 if (pCurDocShell->HasSecurityOptOpenReadOnly() &&
230 bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly())
232 pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly );
233 bModified = true;
237 return bModified;
241 void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet & )
243 SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
245 if (!pCurDocShell)
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();
255 else
257 bool bIsHTMLDoc = false;
258 bool bProtect = true, bUnProtect = false;
259 SfxViewShell* pViewSh = SfxViewShell::Current();
260 if (pViewSh)
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 );
277 else
278 m_pOpenReadonlyCB->Disable();
280 bool bRecordChanges;
281 if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc)
282 m_eRedlingMode = RL_WRITER;
283 else if (QueryRecordChangesState( RL_CALC, bRecordChanges ))
284 m_eRedlingMode = RL_CALC;
285 else
286 m_eRedlingMode = RL_NONE;
288 if (m_eRedlingMode != RL_NONE)
290 bool bProtection;
291 QueryRecordChangesProtectionState( m_eRedlingMode, bProtection );
293 m_pProtectPB->Enable( !bIsReadonly );
294 m_pUnProtectPB->Enable( !bIsReadonly );
295 // set the right text
296 if (bProtection)
298 bProtect = false;
299 bUnProtect = true;
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
312 else
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)
342 bAlreadyDone = true;
343 else
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 ))
355 bAlreadyDone = true;
357 // ask for password and if dialog is canceled or no password provided return
358 if (lcl_IsPasswordCorrect( aPasswordText ))
359 m_bOrigPasswordIsConfirmed = true;
360 else
361 bAlreadyDone = true;
364 if (bAlreadyDone)
365 m_pRecordChangesCB->Check( true ); // restore original state
366 else
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();
377 return 0;
381 IMPL_LINK_NOARG(SfxSecurityPage_Impl, ChangeProtectionPBHdl)
383 if (m_eRedlingMode == RL_NONE)
384 return 0;
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;
393 if (bNeedPassword)
395 // ask for password and if dialog is canceled or no password provided return
396 if (!lcl_GetPassword( m_rMyTabPage.GetParent(), bNewProtection, aPasswordText ))
397 return 0;
399 // provided password still needs to be checked?
400 if (!bNewProtection && !m_bOrigPasswordIsConfirmed)
402 if (lcl_IsPasswordCorrect( aPasswordText ))
403 m_bOrigPasswordIsConfirmed = true;
404 else
405 return 0;
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);
420 return 0;
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 );
448 return bModified;
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: */