LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / dialog / securitypage.cxx
blob7441e47c17465511581f1543c7fab1e3e29e822a
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 .
20 #include <sfx2/htmlmode.hxx>
22 #include <sfx2/sfxresid.hxx>
24 #include <sfx2/sfxsids.hrc>
25 #include <sfx2/objsh.hxx>
26 #include <sfx2/viewsh.hxx>
27 #include <sfx2/dispatch.hxx>
28 #include <sfx2/passwd.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/weld.hxx>
32 #include <svl/eitem.hxx>
33 #include <svl/poolitem.hxx>
34 #include <svl/intitem.hxx>
35 #include <svl/PasswordHelper.hxx>
37 #include <sfx2/strings.hrc>
39 #include "securitypage.hxx"
41 using namespace ::com::sun::star;
43 namespace
45 enum RedliningMode { RL_NONE, RL_WRITER, RL_CALC };
47 bool QueryState( sal_uInt16 _nSlot, bool& _rValue )
49 bool bRet = false;
50 SfxViewShell* pViewSh = SfxViewShell::Current();
51 if (pViewSh)
53 const SfxPoolItem* pItem;
54 SfxDispatcher* pDisp = pViewSh->GetDispatcher();
55 SfxItemState nState = pDisp->QueryState( _nSlot, pItem );
56 bRet = SfxItemState::DEFAULT <= nState;
57 if (bRet)
58 _rValue = static_cast< const SfxBoolItem* >( pItem )->GetValue();
60 return bRet;
64 bool QueryRecordChangesProtectionState( RedliningMode _eMode, bool& _rValue )
66 bool bRet = false;
67 if (_eMode != RL_NONE)
69 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_PROTECT : SID_CHG_PROTECT;
70 bRet = QueryState( nSlot, _rValue );
72 return bRet;
76 bool QueryRecordChangesState( RedliningMode _eMode, bool& _rValue )
78 bool bRet = false;
79 if (_eMode != RL_NONE)
81 sal_uInt16 nSlot = _eMode == RL_WRITER ? FN_REDLINE_ON : FID_CHG_RECORD;
82 bRet = QueryState( nSlot, _rValue );
84 return bRet;
89 static bool lcl_GetPassword(
90 weld::Window *pParent,
91 bool bProtect,
92 /*out*/OUString &rPassword )
94 bool bRes = false;
95 SfxPasswordDialog aPasswdDlg(pParent);
96 aPasswdDlg.SetMinLen(1);
97 if (bProtect)
98 aPasswdDlg.ShowExtras( SfxShowExtras::CONFIRM );
99 if (RET_OK == aPasswdDlg.run() && !aPasswdDlg.GetPassword().isEmpty())
101 rPassword = aPasswdDlg.GetPassword();
102 bRes = true;
104 return bRes;
108 static bool lcl_IsPasswordCorrect( const OUString &rPassword )
110 bool bRes = false;
112 SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
113 uno::Sequence< sal_Int8 > aPasswordHash;
114 pCurDocShell->GetProtectionHash( aPasswordHash );
116 // check if supplied password was correct
117 uno::Sequence< sal_Int8 > aNewPasswd( aPasswordHash );
118 SvPasswordHelper::GetHashPassword( aNewPasswd, rPassword );
119 if (SvPasswordHelper::CompareHashPassword( aPasswordHash, rPassword ))
120 bRes = true; // password was correct
121 else
123 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
124 VclMessageType::Info, VclButtonsType::Ok,
125 SfxResId(RID_SVXSTR_INCORRECT_PASSWORD)));
126 xInfoBox->run();
129 return bRes;
132 struct SfxSecurityPage_Impl
134 SfxSecurityPage & m_rMyTabPage;
136 RedliningMode m_eRedlingMode; // for record changes
138 bool m_bOrigPasswordIsConfirmed;
139 bool m_bNewPasswordIsValid;
140 OUString m_aNewPassword;
142 OUString m_aEndRedliningWarning;
143 bool m_bEndRedliningWarningDone;
145 std::unique_ptr<weld::CheckButton> m_xOpenReadonlyCB;
146 std::unique_ptr<weld::CheckButton> m_xRecordChangesCB; // for record changes
147 std::unique_ptr<weld::Button> m_xProtectPB; // for record changes
148 std::unique_ptr<weld::Button> m_xUnProtectPB; // for record changes
150 DECL_LINK(RecordChangesCBToggleHdl, weld::Toggleable&, void);
151 DECL_LINK(ChangeProtectionPBHdl, weld::Button&, void);
153 SfxSecurityPage_Impl( SfxSecurityPage &rDlg );
155 bool FillItemSet_Impl();
156 void Reset_Impl();
159 SfxSecurityPage_Impl::SfxSecurityPage_Impl(SfxSecurityPage &rTabPage)
160 : m_rMyTabPage(rTabPage)
161 , m_eRedlingMode(RL_NONE)
162 , m_bOrigPasswordIsConfirmed(false)
163 , m_bNewPasswordIsValid(false)
164 , m_aEndRedliningWarning(SfxResId(RID_SVXSTR_END_REDLINING_WARNING))
165 , m_bEndRedliningWarningDone(false)
166 , m_xOpenReadonlyCB(rTabPage.GetBuilder().weld_check_button("readonly"))
167 , m_xRecordChangesCB(rTabPage.GetBuilder().weld_check_button("recordchanges"))
168 , m_xProtectPB(rTabPage.GetBuilder().weld_button("protect"))
169 , m_xUnProtectPB(rTabPage.GetBuilder().weld_button("unprotect"))
171 m_xProtectPB->show();
172 m_xUnProtectPB->hide();
174 m_xRecordChangesCB->connect_toggled(LINK(this, SfxSecurityPage_Impl, RecordChangesCBToggleHdl));
175 m_xProtectPB->connect_clicked(LINK(this, SfxSecurityPage_Impl, ChangeProtectionPBHdl));
176 m_xUnProtectPB->connect_clicked(LINK(this, SfxSecurityPage_Impl, ChangeProtectionPBHdl));
179 bool SfxSecurityPage_Impl::FillItemSet_Impl()
181 bool bModified = false;
183 SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
184 if (pCurDocShell&& !pCurDocShell->IsReadOnly())
186 if (m_eRedlingMode != RL_NONE )
188 const bool bDoRecordChanges = m_xRecordChangesCB->get_active();
189 const bool bDoChangeProtection = m_xUnProtectPB->get_visible();
191 // sanity checks
192 DBG_ASSERT( bDoRecordChanges || !bDoChangeProtection, "no change recording should imply no change protection" );
193 DBG_ASSERT( bDoChangeProtection || !bDoRecordChanges, "no change protection should imply no change recording" );
194 DBG_ASSERT( !bDoChangeProtection || !m_aNewPassword.isEmpty(), "change protection should imply password length is > 0" );
195 DBG_ASSERT( bDoChangeProtection || m_aNewPassword.isEmpty(), "no change protection should imply password length is 0" );
197 // change recording
198 if (bDoRecordChanges != pCurDocShell->IsChangeRecording())
200 pCurDocShell->SetChangeRecording( bDoRecordChanges );
201 bModified = true;
204 // change record protection
205 if (m_bNewPasswordIsValid &&
206 bDoChangeProtection != pCurDocShell->HasChangeRecordProtection())
208 DBG_ASSERT( !bDoChangeProtection || bDoRecordChanges,
209 "change protection requires record changes to be active!" );
210 pCurDocShell->SetProtectionPassword( m_aNewPassword );
211 bModified = true;
215 // open read-only?
216 const bool bDoOpenReadonly = m_xOpenReadonlyCB->get_active();
217 if (bDoOpenReadonly != pCurDocShell->IsSecurityOptOpenReadOnly())
219 pCurDocShell->SetSecurityOptOpenReadOnly( bDoOpenReadonly );
220 bModified = true;
224 return bModified;
228 void SfxSecurityPage_Impl::Reset_Impl()
230 SfxObjectShell* pCurDocShell = SfxObjectShell::Current();
232 if (!pCurDocShell)
234 // no doc -> hide document settings
235 m_xOpenReadonlyCB->set_sensitive(false);
236 m_xRecordChangesCB->set_sensitive(false);
237 m_xProtectPB->show();
238 m_xProtectPB->set_sensitive(false);
239 m_xUnProtectPB->hide();
240 m_xUnProtectPB->set_sensitive(false);
242 else
244 bool bIsHTMLDoc = false;
245 bool bProtect = true, bUnProtect = false;
246 SfxViewShell* pViewSh = SfxViewShell::Current();
247 if (pViewSh)
249 const SfxPoolItem* pItem;
250 SfxDispatcher* pDisp = pViewSh->GetDispatcher();
251 if (SfxItemState::DEFAULT <= pDisp->QueryState( SID_HTML_MODE, pItem ))
253 sal_uInt16 nMode = static_cast< const SfxUInt16Item* >( pItem )->GetValue();
254 bIsHTMLDoc = ( ( nMode & HTMLMODE_ON ) != 0 );
258 bool bIsReadonly = pCurDocShell->IsReadOnly();
259 if (!bIsHTMLDoc)
261 m_xOpenReadonlyCB->set_active(pCurDocShell->IsSecurityOptOpenReadOnly());
262 m_xOpenReadonlyCB->set_sensitive(!bIsReadonly);
264 else
265 m_xOpenReadonlyCB->set_sensitive(false);
267 bool bRecordChanges;
268 if (QueryRecordChangesState( RL_WRITER, bRecordChanges ) && !bIsHTMLDoc)
269 m_eRedlingMode = RL_WRITER;
270 else if (QueryRecordChangesState( RL_CALC, bRecordChanges ))
271 m_eRedlingMode = RL_CALC;
272 else
273 m_eRedlingMode = RL_NONE;
275 if (m_eRedlingMode != RL_NONE)
277 bool bProtection(false);
278 QueryRecordChangesProtectionState( m_eRedlingMode, bProtection );
280 m_xProtectPB->set_sensitive(!bIsReadonly);
281 m_xUnProtectPB->set_sensitive(!bIsReadonly);
282 // set the right text
283 if (bProtection)
285 bProtect = false;
286 bUnProtect = true;
289 m_xRecordChangesCB->set_active(bRecordChanges);
290 m_xRecordChangesCB->set_sensitive(/*!bProtection && */!bIsReadonly);
292 m_bOrigPasswordIsConfirmed = true; // default case if no password is set
293 uno::Sequence< sal_Int8 > aPasswordHash;
294 // check if password is available
295 if (pCurDocShell->GetProtectionHash( aPasswordHash ) &&
296 aPasswordHash.hasElements())
297 m_bOrigPasswordIsConfirmed = false; // password found, needs to be confirmed later on
299 else
301 // A Calc document that is shared will have 'm_eRedlingMode == RL_NONE'
302 // In shared documents change recording and protection must be disabled,
303 // similar to documents that do not support change recording at all.
304 m_xRecordChangesCB->set_active(false);
305 m_xRecordChangesCB->set_sensitive(false);
306 m_xProtectPB->set_sensitive(false);
307 m_xUnProtectPB->set_sensitive(false);
310 m_xProtectPB->set_visible(bProtect);
311 m_xUnProtectPB->set_visible(bUnProtect);
315 IMPL_LINK_NOARG(SfxSecurityPage_Impl, RecordChangesCBToggleHdl, weld::Toggleable&, void)
317 // when change recording gets disabled protection must be disabled as well
318 if (m_xRecordChangesCB->get_active()) // the new check state is already present, thus the '!'
319 return;
321 bool bAlreadyDone = false;
322 if (!m_bEndRedliningWarningDone)
324 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_rMyTabPage.GetFrameWeld(),
325 VclMessageType::Warning, VclButtonsType::YesNo,
326 m_aEndRedliningWarning));
327 xWarn->set_default_response(RET_NO);
328 if (xWarn->run() != RET_YES)
329 bAlreadyDone = true;
330 else
331 m_bEndRedliningWarningDone = true;
334 const bool bNeedPassword = !m_bOrigPasswordIsConfirmed
335 && m_xUnProtectPB->get_visible(); // tdf#128230 Require password if the Unprotect button is visible
336 if (!bAlreadyDone && bNeedPassword)
338 OUString aPasswordText;
340 // dialog canceled or no password provided
341 if (!lcl_GetPassword( m_rMyTabPage.GetFrameWeld(), false, aPasswordText ))
342 bAlreadyDone = true;
344 // ask for password and if dialog is canceled or no password provided return
345 if (lcl_IsPasswordCorrect( aPasswordText ))
346 m_bOrigPasswordIsConfirmed = true;
347 else
348 bAlreadyDone = true;
351 if (bAlreadyDone)
352 m_xRecordChangesCB->set_active(true); // restore original state
353 else
355 // remember required values to change protection and change recording in
356 // FillItemSet_Impl later on if password was correct.
357 m_bNewPasswordIsValid = true;
358 m_aNewPassword.clear();
359 m_xProtectPB->show();
360 m_xUnProtectPB->hide();
364 IMPL_LINK_NOARG(SfxSecurityPage_Impl, ChangeProtectionPBHdl, weld::Button&, void)
366 if (m_eRedlingMode == RL_NONE)
367 return;
369 // the push button text is always the opposite of the current state. Thus:
370 const bool bCurrentProtection = m_xUnProtectPB->get_visible();
372 // ask user for password (if still necessary)
373 OUString aPasswordText;
374 bool bNewProtection = !bCurrentProtection;
375 const bool bNeedPassword = bNewProtection || !m_bOrigPasswordIsConfirmed;
376 if (bNeedPassword)
378 // ask for password and if dialog is canceled or no password provided return
379 if (!lcl_GetPassword(m_rMyTabPage.GetFrameWeld(), bNewProtection, aPasswordText))
380 return;
382 // provided password still needs to be checked?
383 if (!bNewProtection && !m_bOrigPasswordIsConfirmed)
385 if (lcl_IsPasswordCorrect( aPasswordText ))
386 m_bOrigPasswordIsConfirmed = true;
387 else
388 return;
391 DBG_ASSERT( m_bOrigPasswordIsConfirmed, "ooops... this should not have happened!" );
393 // remember required values to change protection and change recording in
394 // FillItemSet_Impl later on if password was correct.
395 m_bNewPasswordIsValid = true;
396 m_aNewPassword = bNewProtection? aPasswordText : OUString();
398 m_xRecordChangesCB->set_active(bNewProtection);
400 m_xUnProtectPB->set_visible(bNewProtection);
401 m_xProtectPB->set_visible(!bNewProtection);
404 std::unique_ptr<SfxTabPage> SfxSecurityPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet * rItemSet)
406 return std::make_unique<SfxSecurityPage>(pPage, pController, *rItemSet);
409 SfxSecurityPage::SfxSecurityPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
410 : SfxTabPage(pPage, pController, "sfx/ui/securityinfopage.ui", "SecurityInfoPage", &rItemSet)
412 m_pImpl.reset(new SfxSecurityPage_Impl( *this ));
415 bool SfxSecurityPage::FillItemSet( SfxItemSet * /*rItemSet*/ )
417 bool bModified = false;
418 DBG_ASSERT(m_pImpl, "implementation pointer is 0. Still in c-tor?");
419 if (m_pImpl != nullptr)
420 bModified = m_pImpl->FillItemSet_Impl();
421 return bModified;
424 void SfxSecurityPage::Reset( const SfxItemSet * /*rItemSet*/ )
426 DBG_ASSERT(m_pImpl, "implementation pointer is 0. Still in c-tor?");
427 if (m_pImpl != nullptr)
428 m_pImpl->Reset_Impl();
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */