1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sfx2.hxx" 26 27 #include "sfx2/securitypage.hxx" 28 29 #include "securitypage.hrc" 30 #include "sfxresid.hxx" 31 32 #include <sfx2/sfx.hrc> 33 #include <sfx2/sfxsids.hrc> 34 #include <sfx2/objsh.hxx> 35 #include <sfx2/viewsh.hxx> 36 #include <sfx2/dispatch.hxx> 37 #include <sfx2/passwd.hxx> 38 39 #include <vcl/button.hxx> 40 #include <vcl/edit.hxx> 41 #include <vcl/fixed.hxx> 42 #include <vcl/msgbox.hxx> 43 #include <svl/eitem.hxx> 44 #include <svl/poolitem.hxx> 45 #include <svl/intitem.hxx> 46 #include <svl/PasswordHelper.hxx> 47 #include <svtools/xwindowitem.hxx> 48 49 50 using namespace ::com::sun::star; 51 52 ////////////////////////////////////////////////////////////////////// 53 54 55 namespace 56 { 57 enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC }; 58 enum RedlineFunc { RF_ON, RF_PROTECT }; 59 60 /* 61 bool QueryIsEnabled( sal_uInt16 _nSlot ) 62 { 63 bool bRes = false; 64 SfxViewShell* pViewSh = SfxViewShell::Current(); 65 if (pViewSh) 66 { 67 const SfxPoolItem* pItem; 68 SfxDispatcher* pDisp = pViewSh->GetDispatcher(); 69 SfxItemState eState = pDisp->QueryState( _nSlot, pItem ); 70 bRes = (eState & SFX_ITEM_DISABLED) == 0; 71 } 72 return bRes; 73 } 74 */ 75 76 bool QueryState( sal_uInt16 _nSlot, bool& _rValue ) 77 { 78 bool bRet = false; 79 SfxViewShell* pViewSh = SfxViewShell::Current(); 80 if (pViewSh) 81 { 82 const SfxPoolItem* pItem; 83 SfxDispatcher* pDisp = pViewSh->GetDispatcher(); 84 SfxItemState nState = pDisp->QueryState( _nSlot, pItem ); 85 bRet = SFX_ITEM_AVAILABLE <= nState; 86 if (bRet) 87 _rValue = ( static_cast< const SfxBoolItem* >( pItem ) )->GetValue(); 88 } 89 return bRet; 90 } 91 92 93 bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue ) 94 { 95 bool bRet = false; 96 if (_eMode != RL_NONE) 97 { 98 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT; 99 bRet = QueryState( nSlot, _rValue ); 100 } 101 return bRet; 102 } 103 104 105 bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue ) 106 { 107 bool bRet = false; 108 if (_eMode != RL_NONE) 109 { 110 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD; 111 bRet = QueryState( nSlot, _rValue ); 112 } 113 return bRet; 114 } 115 } 116 117 118 ////////////////////////////////////////////////////////////////////// 119 120 121 static short lcl_GetPassword( 122 Window *pParent, 123 bool bProtect, 124 /*out*/String &rPassword ) 125 { 126 bool bRes = false; 127 SfxPasswordDialog aPasswdDlg( pParent ); 128 const String aTitle( SfxResId( bProtect ? RID_SFX_PROTECT_RECORDS : RID_SFX_UNPROTECT_RECORDS ) ); 129 aPasswdDlg.SetText( aTitle ); 130 aPasswdDlg.SetMinLen( 1 ); 131 if (bProtect) 132 aPasswdDlg.ShowExtras( SHOWEXTRAS_CONFIRM ); 133 if (RET_OK == aPasswdDlg.Execute() && aPasswdDlg.GetPassword().Len() > 0) 134 { 135 rPassword = aPasswdDlg.GetPassword(); 136 bRes = true; 137 } 138 return bRes; 139 } 140 141 142 static bool lcl_IsPasswordCorrect( const String &rPassword ) 143 { 144 bool bRes = false; 145 146 SfxObjectShell* pCurDocShell = SfxObjectShell::Current(); 147 uno::Sequence< sal_Int8 > aPasswordHash; 148 pCurDocShell->GetProtectionHash( aPasswordHash ); 149 150 // check if supplied password was correct 151 uno::Sequence< sal_Int8 > aNewPasswd( aPasswordHash ); 152 SvPasswordHelper::GetHashPassword( aNewPasswd, rPassword ); 153 if (SvPasswordHelper::CompareHashPassword( aPasswordHash, rPassword )) 154 bRes = true; // password was correct 155 else 156 InfoBox( NULL, String( SfxResId( RID_SFX_INCORRECT_PASSWORD ) ) ).Execute(); 157 158 return bRes; 159 } 160 161 162 ////////////////////////////////////////////////////////////////////// 163 164 165 struct SfxSecurityPage_Impl 166 { 167 SfxSecurityPage & m_rMyTabPage; 168 169 FixedLine m_aNewPasswordToOpenFL; 170 FixedText m_aNewPasswordToOpenFT; 171 Edit m_aNewPasswordToOpenED; 172 FixedText m_aConfirmPasswordToOpenFT; 173 Edit m_aConfirmPasswordToOpenED; 174 FixedText m_aNewPasswordInfoFT; 175 176 FixedLine m_aNewPasswordToModifyFL; 177 FixedText m_aNewPasswordToModifyFT; 178 Edit m_aNewPasswordToModifyED; 179 FixedText m_aConfirmPasswordToModifyFT; 180 Edit m_aConfirmPasswordToModifyED; 181 182 FixedLine m_aOptionsFL; 183 CheckBox m_aOpenReadonlyCB; 184 CheckBox m_aRecordChangesCB; // for record changes 185 PushButton m_aChangeProtectionPB; // for record changes 186 String m_aProtectSTR; // for record changes 187 String m_aUnProtectSTR; // for record changes 188 RedliningMode m_eRedlingMode; // for record changes 189 190 bool m_bOrigPasswordIsConfirmed; 191 bool m_bNewPasswordIsValid; 192 String m_aNewPassword; 193 194 String m_aEndRedliningWarning; 195 bool m_bEndRedliningWarningDone; 196 197 DECL_LINK( RecordChangesCBToggleHdl, void* ); 198 DECL_LINK( ChangeProtectionPBHdl, void* ); 199 200 SfxSecurityPage_Impl( SfxSecurityPage &rDlg, const SfxItemSet &rItemSet ); 201 ~SfxSecurityPage_Impl(); 202 203 sal_Bool FillItemSet_Impl( SfxItemSet & ); 204 void Reset_Impl( const SfxItemSet & ); 205 }; 206 207 208 SfxSecurityPage_Impl::SfxSecurityPage_Impl( SfxSecurityPage &rTabPage, const SfxItemSet & ) : 209 m_rMyTabPage (rTabPage), 210 m_aNewPasswordToOpenFL (&rTabPage, SfxResId( PASSWORD_TO_OPEN_FL ) ), 211 m_aNewPasswordToOpenFT (&rTabPage, SfxResId( PASSWORD_TO_OPEN_FT ) ), 212 m_aNewPasswordToOpenED (&rTabPage, SfxResId( PASSWORD_TO_OPEN_ED ) ), 213 m_aConfirmPasswordToOpenFT (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_OPEN_FT ) ), 214 m_aConfirmPasswordToOpenED (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_OPEN_ED ) ), 215 m_aNewPasswordInfoFT (&rTabPage, SfxResId( PASSWORD_INFO_FT ) ), 216 m_aNewPasswordToModifyFL (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_FL ) ), 217 m_aNewPasswordToModifyFT (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_FT ) ), 218 m_aNewPasswordToModifyED (&rTabPage, SfxResId( PASSWORD_TO_MODIFY_ED ) ), 219 m_aConfirmPasswordToModifyFT (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_FT ) ), 220 m_aConfirmPasswordToModifyED (&rTabPage, SfxResId( CONFIRM_PASSWORD_TO_MODIFY_ED ) ), 221 m_aOptionsFL (&rTabPage, SfxResId( OPTIONS_FL ) ), 222 m_aOpenReadonlyCB (&rTabPage, SfxResId( OPEN_READONLY_CB ) ), 223 m_aRecordChangesCB (&rTabPage, SfxResId( RECORD_CHANGES_CB ) ), 224 m_aChangeProtectionPB (&rTabPage, SfxResId( CHANGE_PROTECTION_PB ) ), 225 m_aProtectSTR ( SfxResId( STR_PROTECT ) ), 226 m_aUnProtectSTR ( SfxResId( STR_UNPROTECT ) ), 227 m_eRedlingMode ( RL_NONE ), 228 m_bOrigPasswordIsConfirmed ( false ), 229 m_bNewPasswordIsValid ( false ), 230 m_aEndRedliningWarning ( SfxResId( STR_END_REDLINING_WARNING ) ), 231 m_bEndRedliningWarningDone ( false ) 232 { 233 m_aChangeProtectionPB.SetText( m_aProtectSTR ); 234 // adjust button width if necessary 235 long nBtnTextWidth = 0; 236 long nTemp = m_aChangeProtectionPB.GetCtrlTextWidth( m_aChangeProtectionPB.GetText() ); 237 if (nTemp > nBtnTextWidth) 238 nBtnTextWidth = nTemp; 239 240 // force toggle hdl called before visual change of checkbox 241 m_aRecordChangesCB.SetStyle( m_aRecordChangesCB.GetStyle() | WB_EARLYTOGGLE ); 242 m_aRecordChangesCB.SetToggleHdl( LINK( this, SfxSecurityPage_Impl, RecordChangesCBToggleHdl ) ); 243 m_aChangeProtectionPB.SetClickHdl( LINK( this, SfxSecurityPage_Impl, ChangeProtectionPBHdl ) ); 244 245 246 // #i112277: for the time being (OOO 3.3) the following options should not 247 // be available. In the long run however it is planned to implement the yet 248 // missing functionality. Thus now we hide them and move the remaining ones up. 249 m_aNewPasswordToOpenFL.Hide(); 250 m_aNewPasswordToOpenFT.Hide(); 251 m_aNewPasswordToOpenED.Hide(); 252 m_aConfirmPasswordToOpenFT.Hide(); 253 m_aConfirmPasswordToOpenED.Hide(); 254 m_aNewPasswordInfoFT.Hide(); 255 m_aNewPasswordToModifyFL.Hide(); 256 m_aNewPasswordToModifyFT.Hide(); 257 m_aNewPasswordToModifyED.Hide(); 258 m_aConfirmPasswordToModifyFT.Hide(); 259 m_aConfirmPasswordToModifyED.Hide(); 260 const long nDelta = m_aOptionsFL.GetPosPixel().Y() - m_aNewPasswordToOpenFL.GetPosPixel().Y(); 261 Point aPos; 262 aPos = m_aOptionsFL.GetPosPixel(); 263 aPos.Y() -= nDelta; 264 m_aOptionsFL.SetPosPixel( aPos ); 265 aPos = m_aOpenReadonlyCB.GetPosPixel(); 266 aPos.Y() -= nDelta; 267 m_aOpenReadonlyCB.SetPosPixel( aPos ); 268 aPos = m_aRecordChangesCB.GetPosPixel(); 269 aPos.Y() -= nDelta; 270 m_aRecordChangesCB.SetPosPixel( aPos ); 271 aPos = m_aChangeProtectionPB.GetPosPixel(); 272 aPos.Y() -= nDelta; 273 m_aChangeProtectionPB.SetPosPixel( aPos ); 274 } 275 276 277 SfxSecurityPage_Impl::~SfxSecurityPage_Impl() 278 { 279 } 280 281 282 sal_Bool SfxSecurityPage_Impl::FillItemSet_Impl( SfxItemSet & ) 283 { 284 bool bModified = false; 285 286 SfxObjectShell* pCurDocShell = SfxObjectShell::Current(); 287 if (pCurDocShell&& !pCurDocShell->IsReadOnly()) 288 { 289 if (m_eRedlingMode != RL_NONE ) 290 { 291 const bool bDoRecordChanges = m_aRecordChangesCB.IsChecked(); 292 const bool bDoChangeProtection = m_aChangeProtectionPB.GetText() != m_aProtectSTR; 293 294 // sanity checks 295 DBG_ASSERT( bDoRecordChanges || !bDoChangeProtection, "no change recording should imply no change protection" ); 296 DBG_ASSERT( bDoChangeProtection || !bDoRecordChanges, "no change protection should imply no change recording" ); 297 DBG_ASSERT( !bDoChangeProtection || m_aNewPassword.Len() > 0, "change protection should imply password length is > 0" ); 298 DBG_ASSERT( bDoChangeProtection || m_aNewPassword.Len() == 0, "no change protection should imply password length is 0" ); 299 300 // change recording 301 if (bDoRecordChanges != pCurDocShell->IsChangeRecording()) 302 { 303 pCurDocShell->SetChangeRecording( bDoRecordChanges ); 304 bModified = true; 305 } 306 307 // change record protection 308 if (m_bNewPasswordIsValid && 309 bDoChangeProtection != pCurDocShell->HasChangeRecordProtection()) 310 { 311 DBG_ASSERT( !bDoChangeProtection || bDoRecordChanges, 312 "change protection requires record changes to be active!" ); 313 pCurDocShell->SetProtectionPassword( m_aNewPassword ); 314 bModified = true; 315 } 316 } 317 318 // open read-only? 319 const sal_Bool bDoOpenReadonly = m_aOpenReadonlyCB.IsChecked(); 320 if (pCurDocShell->HasSecurityOptOpenReadOnly() && 321 bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly()) 322 { 323 pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly ); 324 bModified = true; 325 } 326 } 327 328 return bModified; 329 } 330 331 332 void SfxSecurityPage_Impl::Reset_Impl( const SfxItemSet & ) 333 { 334 SfxObjectShell* pCurDocShell = SfxObjectShell::Current(); 335 336 String sNewText = m_aProtectSTR; 337 if (!pCurDocShell) 338 { 339 // no doc -> hide document settings 340 m_aOpenReadonlyCB.Disable(); 341 m_aRecordChangesCB.Disable(); 342 m_aChangeProtectionPB.Disable(); 343 } 344 else 345 { 346 bool bIsHTMLDoc = false; 347 SfxViewShell* pViewSh = SfxViewShell::Current(); 348 if (pViewSh) 349 { 350 const SfxPoolItem* pItem; 351 SfxDispatcher* pDisp = pViewSh->GetDispatcher(); 352 if (SFX_ITEM_AVAILABLE <= pDisp->QueryState( SID_HTML_MODE, pItem )) 353 { 354 sal_uInt16 nMode = static_cast< const SfxUInt16Item* >( pItem )->GetValue(); 355 bIsHTMLDoc = ( ( nMode & HTMLMODE_ON ) != 0 ); 356 } 357 } 358 359 sal_Bool bIsReadonly = pCurDocShell->IsReadOnly(); 360 if (pCurDocShell->HasSecurityOptOpenReadOnly() && !bIsHTMLDoc) 361 { 362 m_aOpenReadonlyCB.Check( pCurDocShell->IsSecurityOptOpenReadOnly() ); 363 m_aOpenReadonlyCB.Enable( !bIsReadonly ); 364 } 365 else 366 m_aOpenReadonlyCB.Disable(); 367 368 bool bRecordChanges; 369 if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc) 370 m_eRedlingMode = RL_WRITER; 371 else if (QueryRecordChangesState( RL_CALC, bRecordChanges )) 372 m_eRedlingMode = RL_CALC; 373 else 374 m_eRedlingMode = RL_NONE; 375 376 if (m_eRedlingMode != RL_NONE) 377 { 378 bool bProtection; 379 QueryRecordChangesProtectionState( m_eRedlingMode, bProtection ); 380 381 m_aChangeProtectionPB.Enable( !bIsReadonly ); 382 // set the right text 383 if (bProtection) 384 sNewText = m_aUnProtectSTR; 385 386 m_aRecordChangesCB.Check( bRecordChanges ); 387 m_aRecordChangesCB.Enable( /*!bProtection && */!bIsReadonly ); 388 389 m_bOrigPasswordIsConfirmed = true; // default case if no password is set 390 uno::Sequence< sal_Int8 > aPasswordHash; 391 // check if password is available 392 if (pCurDocShell->GetProtectionHash( aPasswordHash ) && 393 aPasswordHash.getLength() > 0) 394 m_bOrigPasswordIsConfirmed = false; // password found, needs to be confirmed later on 395 } 396 else 397 { 398 // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE' 399 // In shared documents change recording and protection must be disabled, 400 // similar to documents that do not support change recording at all. 401 m_aRecordChangesCB.Check( sal_False ); 402 m_aRecordChangesCB.Disable(); 403 m_aChangeProtectionPB.Check( sal_False ); 404 m_aChangeProtectionPB.Disable(); 405 } 406 } 407 408 m_aChangeProtectionPB.SetText( sNewText ); 409 } 410 411 412 IMPL_LINK( SfxSecurityPage_Impl, RecordChangesCBToggleHdl, void*, EMPTYARG ) 413 { 414 // when change recording gets disabled protection must be disabled as well 415 if (!m_aRecordChangesCB.IsChecked()) // the new check state is already present, thus the '!' 416 { 417 bool bAlreadyDone = false; 418 if (!m_bEndRedliningWarningDone) 419 { 420 WarningBox aBox( m_rMyTabPage.GetParent(), WinBits(WB_YES_NO | WB_DEF_NO), 421 m_aEndRedliningWarning ); 422 if (aBox.Execute() != RET_YES) 423 bAlreadyDone = true; 424 else 425 m_bEndRedliningWarningDone = true; 426 } 427 428 const bool bNeedPasssword = !m_bOrigPasswordIsConfirmed 429 && m_aChangeProtectionPB.GetText() != m_aProtectSTR; 430 if (!bAlreadyDone && bNeedPasssword) 431 { 432 String aPasswordText; 433 434 // dialog canceled or no password provided 435 if (!lcl_GetPassword( m_rMyTabPage.GetParent(), false, aPasswordText )) 436 bAlreadyDone = true; 437 438 // ask for password and if dialog is canceled or no password provided return 439 if (lcl_IsPasswordCorrect( aPasswordText )) 440 m_bOrigPasswordIsConfirmed = true; 441 else 442 bAlreadyDone = true; 443 } 444 445 if (bAlreadyDone) 446 m_aRecordChangesCB.Check( true ); // restore original state 447 else 448 { 449 // remember required values to change protection and change recording in 450 // FillItemSet_Impl later on if password was correct. 451 m_bNewPasswordIsValid = true; 452 m_aNewPassword = String(); 453 454 m_aChangeProtectionPB.SetText( m_aProtectSTR ); 455 } 456 } 457 458 return 0; 459 } 460 461 462 IMPL_LINK( SfxSecurityPage_Impl, ChangeProtectionPBHdl, void*, EMPTYARG ) 463 { 464 if (m_eRedlingMode == RL_NONE) 465 return 0; 466 467 // the push button text is always the opposite of the current state. Thus: 468 const bool bCurrentProtection = m_aChangeProtectionPB.GetText() != m_aProtectSTR; 469 470 // ask user for password (if still necessary) 471 String aPasswordText; 472 bool bNewProtection = !bCurrentProtection; 473 const bool bNeedPassword = bNewProtection || !m_bOrigPasswordIsConfirmed; 474 if (bNeedPassword) 475 { 476 // ask for password and if dialog is canceled or no password provided return 477 if (!lcl_GetPassword( m_rMyTabPage.GetParent(), bNewProtection, aPasswordText )) 478 return 0; 479 480 // provided password still needs to be checked? 481 if (!bNewProtection && !m_bOrigPasswordIsConfirmed) 482 { 483 if (lcl_IsPasswordCorrect( aPasswordText )) 484 m_bOrigPasswordIsConfirmed = true; 485 else 486 return 0; 487 } 488 } 489 DBG_ASSERT( m_bOrigPasswordIsConfirmed, "ooops... this should not have happened!" ); 490 491 // remember required values to change protection and change recording in 492 // FillItemSet_Impl later on if password was correct. 493 m_bNewPasswordIsValid = true; 494 m_aNewPassword = bNewProtection? aPasswordText : String(); 495 496 // // RecordChangesCB is enabled if protection is off 497 // m_aRecordChangesCB.Enable( !bNewProtection ); 498 m_aRecordChangesCB.Check( bNewProtection ); 499 // toggle text of button "Protect" <-> "Unprotect" 500 m_aChangeProtectionPB.SetText( bNewProtection ? m_aUnProtectSTR : m_aProtectSTR ); 501 502 return 0; 503 } 504 505 506 ////////////////////////////////////////////////////////////////////// 507 508 509 SfxTabPage* SfxSecurityPage::Create( Window * pParent, const SfxItemSet & rItemSet ) 510 { 511 return new SfxSecurityPage( pParent, rItemSet ); 512 } 513 514 515 SfxSecurityPage::SfxSecurityPage( Window* pParent, const SfxItemSet& rItemSet ) : 516 SfxTabPage( pParent, SfxResId( TP_DOCINFOSECURITY ), rItemSet ) 517 { 518 m_pImpl = std::auto_ptr< SfxSecurityPage_Impl >(new SfxSecurityPage_Impl( *this, rItemSet )); 519 520 FreeResource(); 521 } 522 523 524 SfxSecurityPage::~SfxSecurityPage() 525 { 526 } 527 528 529 sal_Bool SfxSecurityPage::FillItemSet( SfxItemSet & rItemSet ) 530 { 531 bool bModified = false; 532 DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" ); 533 if (m_pImpl.get() != 0) 534 bModified = m_pImpl->FillItemSet_Impl( rItemSet ); 535 return bModified; 536 } 537 538 539 void SfxSecurityPage::Reset( const SfxItemSet & rItemSet ) 540 { 541 DBG_ASSERT( m_pImpl.get(), "implementation pointer is 0. Still in c-tor?" ); 542 if (m_pImpl.get() != 0) 543 m_pImpl->Reset_Impl( rItemSet ); 544 } 545 546 547 ////////////////////////////////////////////////////////////////////// 548 549 550