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 .
20 #include <comphelper/string.hxx>
21 #include <comphelper/processfactory.hxx>
23 #include <config_gpgme.h>
24 #if HAVE_FEATURE_GPGME
25 # include <com/sun/star/xml/crypto/GPGSEInitializer.hpp>
26 # include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
29 #include <i18nlangtag/languagetag.hxx>
30 #include <i18nlangtag/mslangid.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <vcl/svapp.hxx>
33 #include <svl/intitem.hxx>
34 #include <vcl/settings.hxx>
36 #include <officecfg/Office/Common.hxx>
37 #include <unotools/useroptions.hxx>
38 #include <cuioptgenrl.hxx>
39 #include <svx/svxids.hrc>
40 #include <svx/optgenrl.hxx>
69 unsigned const Others
= 1;
70 unsigned const Russian
= 2;
71 unsigned const Eastern
= 4;
72 unsigned const US
= 8;
73 unsigned const All
= static_cast<unsigned>(-1);
77 // vRowInfo[] -- rows (text + one or more edit boxes)
78 // The order is the same as in RowType above, which is up to down.
84 // language flags (see Lang above):
85 // which language is this row for?
90 { "companyft", Lang::All
},
91 { "nameft", Lang::All
& ~Lang::Russian
& ~Lang::Eastern
},
92 { "rusnameft", Lang::Russian
},
93 { "eastnameft", Lang::Eastern
},
94 { "streetft", Lang::All
& ~Lang::Russian
},
95 { "russtreetft", Lang::Russian
},
96 { "icityft", Lang::All
& ~Lang::US
},
97 { "cityft", Lang::US
},
98 { "countryft", Lang::All
},
99 { "titleft", Lang::All
},
100 { "phoneft", Lang::All
},
101 { "faxft", Lang::All
},
105 // vFieldInfo[] -- edit boxes
106 // The order is up to down, and then left to right.
112 // id of the edit box
114 // id for SvtUserOptions in unotools/useroptions.hxx
115 UserOptToken nUserOptionsId
;
116 // id for settings the focus (defined in svx/optgenrl.hxx)
117 EditPosition nGrabFocusId
;
122 { Row_Company
, "company", UserOptToken::Company
, EditPosition::COMPANY
},
124 { Row_Name
, "firstname", UserOptToken::FirstName
, EditPosition::FIRSTNAME
},
125 { Row_Name
, "lastname", UserOptToken::LastName
, EditPosition::LASTNAME
},
126 { Row_Name
, "shortname", UserOptToken::ID
, EditPosition::SHORTNAME
},
128 { Row_Name_Russian
, "ruslastname", UserOptToken::LastName
, EditPosition::LASTNAME
},
129 { Row_Name_Russian
, "rusfirstname", UserOptToken::FirstName
, EditPosition::FIRSTNAME
},
130 { Row_Name_Russian
, "rusfathersname", UserOptToken::FathersName
, EditPosition::UNKNOWN
},
131 { Row_Name_Russian
, "russhortname", UserOptToken::ID
, EditPosition::SHORTNAME
},
132 // Name (eastern: reversed name ord
133 { Row_Name_Eastern
, "eastlastname", UserOptToken::LastName
, EditPosition::LASTNAME
},
134 { Row_Name_Eastern
, "eastfirstname", UserOptToken::FirstName
, EditPosition::FIRSTNAME
},
135 { Row_Name_Eastern
, "eastshortname", UserOptToken::ID
, EditPosition::SHORTNAME
},
137 { Row_Street
, "street", UserOptToken::Street
, EditPosition::STREET
},
139 { Row_Street_Russian
, "russtreet", UserOptToken::Street
, EditPosition::STREET
},
140 { Row_Street_Russian
, "apartnum", UserOptToken::Apartment
, EditPosition::UNKNOWN
},
142 { Row_City
, "izip", UserOptToken::Zip
, EditPosition::PLZ
},
143 { Row_City
, "icity", UserOptToken::City
, EditPosition::CITY
},
145 { Row_City_US
, "city", UserOptToken::City
, EditPosition::CITY
},
146 { Row_City_US
, "state", UserOptToken::State
, EditPosition::STATE
},
147 { Row_City_US
, "zip", UserOptToken::Zip
, EditPosition::PLZ
},
149 { Row_Country
, "country", UserOptToken::Country
, EditPosition::COUNTRY
},
151 { Row_TitlePos
, "title", UserOptToken::Title
, EditPosition::TITLE
},
152 { Row_TitlePos
, "position", UserOptToken::Position
, EditPosition::POSITION
},
154 { Row_Phone
, "home", UserOptToken::TelephoneHome
, EditPosition::TELPRIV
},
155 { Row_Phone
, "work", UserOptToken::TelephoneWork
, EditPosition::TELCOMPANY
},
157 { Row_FaxMail
, "fax", UserOptToken::Fax
, EditPosition::FAX
},
158 { Row_FaxMail
, "email", UserOptToken::Email
, EditPosition::EMAIL
},
167 struct SvxGeneralTabPage::Row
170 std::unique_ptr
<weld::Label
> xLabel
;
171 // first and last field in the row (last is exclusive)
172 unsigned nFirstField
, nLastField
;
175 explicit Row (std::unique_ptr
<weld::Label
> xLabel_
)
176 : xLabel(std::move(xLabel_
))
187 struct SvxGeneralTabPage::Field
189 // which field is this? (in vFieldInfo[] above)
192 std::unique_ptr
<weld::Entry
> xEdit
;
193 std::unique_ptr
<weld::Container
> xParent
;
196 Field (std::unique_ptr
<weld::Entry
> xEdit_
, unsigned iField_
)
198 , xEdit(std::move(xEdit_
))
199 , xParent(xEdit
->weld_parent())
201 //We want all widgets inside a container, so each row of the toplevel
202 //grid has another container in it. To avoid adding spacing to these
203 //empty grids they all default to invisible, so show them if their
204 //children are visible
210 SvxGeneralTabPage::SvxGeneralTabPage(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
& rCoreSet
)
211 : SfxTabPage(pPage
, pController
, "cui/ui/optuserpage.ui", "OptUserPage", &rCoreSet
)
212 , m_xUseDataCB(m_xBuilder
->weld_check_button("usefordocprop"))
213 , m_xCryptoFrame(m_xBuilder
->weld_widget( "cryptography"))
214 , m_xSigningKeyLB(m_xBuilder
->weld_combo_box("signingkey"))
215 , m_xEncryptionKeyLB(m_xBuilder
->weld_combo_box("encryptionkey"))
216 , m_xEncryptToSelfCB(m_xBuilder
->weld_check_button("encrypttoself"))
219 #if HAVE_FEATURE_GPGME
222 m_xCryptoFrame
->hide();
225 SetExchangeSupport(); // this page needs ExchangeSupport
229 SvxGeneralTabPage::~SvxGeneralTabPage()
233 // Initializes the titles and the edit boxes,
234 // according to vRowInfo[] and vFieldInfo[] above.
235 void SvxGeneralTabPage::InitControls ()
237 // which language bit do we use? (see Lang and vRowInfo[] above)
239 LanguageType l
= Application::GetSettings().GetUILanguageTag().getLanguageType();
240 if (l
== LANGUAGE_ENGLISH_US
)
242 else if (l
== LANGUAGE_RUSSIAN
)
243 LangBit
= Lang::Russian
;
246 if (MsLangId::isFamilyNameFirst(l
))
247 LangBit
= Lang::Eastern
;
249 LangBit
= Lang::Others
;
254 for (unsigned iRow
= 0; iRow
!= nRowCount
; ++iRow
)
256 RowType
const eRow
= static_cast<RowType
>(iRow
);
257 // is the row visible?
258 if (!(vRowInfo
[iRow
].nLangFlags
& LangBit
))
261 vRows
.push_back(std::make_shared
<Row
>(
262 m_xBuilder
->weld_label(vRowInfo
[iRow
].pTextId
)));
263 Row
& rRow
= *vRows
.back();
265 static unsigned const nFieldCount
= std::size(vFieldInfo
);
266 // skipping other (invisible) rows
267 while (iField
!= nFieldCount
&& vFieldInfo
[iField
].eRow
!= eRow
)
270 rRow
.nFirstField
= vFields
.size();
271 for ( ; iField
!= nFieldCount
&& vFieldInfo
[iField
].eRow
== eRow
; ++iField
)
273 // creating edit field
274 vFields
.push_back(std::make_shared
<Field
>(
275 m_xBuilder
->weld_entry(vFieldInfo
[iField
].pEditId
), iField
));
276 // "short name" field?
277 if (vFieldInfo
[iField
].nUserOptionsId
== UserOptToken::ID
)
279 nNameRow
= vRows
.size() - 1;
280 nShortNameField
= vFields
.size() - 1;
283 rRow
.nLastField
= vFields
.size();
287 void SvxGeneralTabPage::InitCryptography()
289 #if HAVE_FEATURE_GPGME
290 m_xCryptoFrame
->show();
292 uno::Reference
< xml::crypto::XSEInitializer
> xSEInitializer
;
295 xSEInitializer
= xml::crypto::GPGSEInitializer::create( comphelper::getProcessComponentContext() );
296 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSC
= xSEInitializer
->createSecurityContext( OUString() );
299 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSE
= xSC
->getSecurityEnvironment();
300 uno::Sequence
<uno::Reference
<security::XCertificate
>> xCertificates
= xSE
->getPersonalCertificates();
302 if (xCertificates
.hasElements())
304 for (auto& xCert
: asNonConstRange(xCertificates
))
306 m_xSigningKeyLB
->append_text( xCert
->getIssuerName());
307 m_xEncryptionKeyLB
->append_text( xCert
->getIssuerName());
311 //tdf#115015: wrap checkbox text and listboxes if necessary
312 int nPrefWidth(m_xEncryptToSelfCB
->get_preferred_size().Width());
313 int nMaxWidth
= m_xEncryptToSelfCB
->get_approximate_digit_width() * 40;
314 if (nPrefWidth
> nMaxWidth
)
316 m_xSigningKeyLB
->set_size_request(nMaxWidth
, -1);
317 m_xEncryptionKeyLB
->set_size_request(nMaxWidth
, -1);
318 m_xEncryptToSelfCB
->set_label_wrap(true);
319 m_xEncryptToSelfCB
->set_size_request(nMaxWidth
, -1);
323 catch ( uno::Exception
const & )
329 void SvxGeneralTabPage::SetLinks ()
331 // link for updating the initials
332 Link
<weld::Entry
&,void> aLink
= LINK( this, SvxGeneralTabPage
, ModifyHdl_Impl
);
333 Row
& rNameRow
= *vRows
[nNameRow
];
334 for (unsigned i
= rNameRow
.nFirstField
; i
!= rNameRow
.nLastField
- 1; ++i
)
335 vFields
[i
]->xEdit
->connect_changed(aLink
);
339 std::unique_ptr
<SfxTabPage
> SvxGeneralTabPage::Create( weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
* rAttrSet
)
341 return std::make_unique
<SvxGeneralTabPage
>( pPage
, pController
, *rAttrSet
);
344 bool SvxGeneralTabPage::FillItemSet( SfxItemSet
* )
346 // remove leading and trailing whitespaces
347 for (auto const & i
: vFields
)
348 i
->xEdit
->set_text(comphelper::string::strip(i
->xEdit
->get_text(), ' '));
350 bool bModified
= false;
351 bModified
|= GetData_Impl();
352 if (m_xUseDataCB
->get_active() != officecfg::Office::Common::Save::Document::UseUserData::get())
354 auto xChanges
= comphelper::ConfigurationChanges::create();
355 officecfg::Office::Common::Save::Document::UseUserData::set(m_xUseDataCB
->get_active(), xChanges
);
362 void SvxGeneralTabPage::Reset( const SfxItemSet
* rSet
)
366 if (rSet
->GetItemState(SID_FIELD_GRABFOCUS
) == SfxItemState::SET
)
368 EditPosition nField
= static_cast<EditPosition
>(rSet
->Get(SID_FIELD_GRABFOCUS
).GetValue());
369 if (nField
!= EditPosition::UNKNOWN
)
371 for (auto const & i
: vFields
)
372 if (nField
== vFieldInfo
[i
->iField
].nGrabFocusId
)
373 i
->xEdit
->grab_focus();
376 vFields
.front()->xEdit
->grab_focus();
379 m_xUseDataCB
->set_active(officecfg::Office::Common::Save::Document::UseUserData::get());
384 // This handler updates the initials (short name)
385 // when one of the name fields was updated.
386 IMPL_LINK( SvxGeneralTabPage
, ModifyHdl_Impl
, weld::Entry
&, rEdit
, void )
388 // short name field and row
389 Field
& rShortName
= *vFields
[nShortNameField
];
390 Row
& rNameRow
= *vRows
[nNameRow
];
391 // number of initials
392 unsigned const nInits
= rNameRow
.nLastField
- rNameRow
.nFirstField
- 1;
393 // which field was updated? (in rNameRow)
394 unsigned nField
= nInits
;
395 for (unsigned i
= 0; i
!= nInits
; ++i
)
397 if (vFields
[rNameRow
.nFirstField
+ i
]->xEdit
.get() == &rEdit
)
400 // updating the initial
401 if (!(nField
< nInits
&& rShortName
.xEdit
->get_sensitive()))
404 OUString sShortName
= rShortName
.xEdit
->get_text();
405 // clear short name if it contains more characters than the number of initials
406 if (o3tl::make_unsigned(sShortName
.getLength()) > nInits
)
408 rShortName
.xEdit
->set_text(OUString());
410 while (o3tl::make_unsigned(sShortName
.getLength()) < nInits
)
412 OUString sName
= rEdit
.get_text();
413 OUString sLetter
= sName
.isEmpty()
414 ? OUString(u
' ') : sName
.copy(0, 1);
415 rShortName
.xEdit
->set_text(sShortName
.replaceAt(nField
, 1, sLetter
).trim());
419 bool SvxGeneralTabPage::GetData_Impl()
422 SvtUserOptions aUserOpt
;
423 for (auto const & i
: vFields
)
425 vFieldInfo
[i
->iField
].nUserOptionsId
,
430 bool bModified
= false;
431 for (auto const & i
: vFields
)
433 if (i
->xEdit
->get_value_changed_from_saved())
440 #if HAVE_FEATURE_GPGME
441 OUString aSK
= m_xSigningKeyLB
->get_active() == 0 ? OUString() //i.e. no key
442 : m_xSigningKeyLB
->get_active_text();
443 OUString aEK
= m_xEncryptionKeyLB
->get_active() == 0 ? OUString()
444 : m_xEncryptionKeyLB
->get_active_text();
446 aUserOpt
.SetToken( UserOptToken::SigningKey
, aSK
);
447 aUserOpt
.SetToken( UserOptToken::EncryptionKey
, aEK
);
448 aUserOpt
.SetBoolValue( UserOptToken::EncryptToSelf
, m_xEncryptToSelfCB
->get_active() );
450 bModified
|= m_xSigningKeyLB
->get_value_changed_from_saved() ||
451 m_xEncryptionKeyLB
->get_value_changed_from_saved() ||
452 m_xEncryptToSelfCB
->get_state_changed_from_saved();
459 void SvxGeneralTabPage::SetData_Impl()
461 // updating and disabling edit boxes
462 SvtUserOptions aUserOpt
;
463 for (auto const & i
: vRows
)
466 // the label is enabled if any of its edit fields are enabled
467 bool bEnableLabel
= false;
468 for (unsigned iField
= rRow
.nFirstField
; iField
!= rRow
.nLastField
; ++iField
)
470 Field
& rField
= *vFields
[iField
];
472 UserOptToken
const nToken
= vFieldInfo
[rField
.iField
].nUserOptionsId
;
473 rField
.xEdit
->set_text(aUserOpt
.GetToken(nToken
));
475 bool const bEnableEdit
= !aUserOpt
.IsTokenReadonly(nToken
);
476 rField
.xEdit
->set_sensitive(bEnableEdit
);
477 bEnableLabel
= bEnableLabel
|| bEnableEdit
;
479 rRow
.xLabel
->set_sensitive(bEnableLabel
);
483 for (auto const & i
: vFields
)
484 i
->xEdit
->save_value();
486 #if HAVE_FEATURE_GPGME
487 OUString aSK
= aUserOpt
.GetToken(UserOptToken::SigningKey
);
488 aSK
.isEmpty() ? m_xSigningKeyLB
->set_active( 0 ) //i.e. 'No Key'
489 : m_xSigningKeyLB
->set_active_text( aSK
);
491 OUString aEK
= aUserOpt
.GetToken(UserOptToken::EncryptionKey
);
492 aEK
.isEmpty() ? m_xEncryptionKeyLB
->set_active( 0 ) //i.e. 'No Key'
493 : m_xEncryptionKeyLB
->set_active_text( aEK
);
495 m_xEncryptToSelfCB
->set_active( aUserOpt
.GetEncryptToSelf() );
500 DeactivateRC
SvxGeneralTabPage::DeactivatePage( SfxItemSet
* pSet_
)
503 FillItemSet( pSet_
);
504 return DeactivateRC::LeavePage
;
507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */