LibreOffice Module cui (master)  1
optgenrl.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <comphelper/string.hxx>
22 
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>
27 #endif
28 
30 #include <i18nlangtag/mslangid.hxx>
31 #include <o3tl/safeint.hxx>
32 #include <vcl/svapp.hxx>
33 #include <unotools/saveopt.hxx>
34 #include <svl/intitem.hxx>
35 #include <vcl/settings.hxx>
36 
37 #include <officecfg/Office/Common.hxx>
38 #include <unotools/useroptions.hxx>
39 #include <cuioptgenrl.hxx>
40 #include <svx/svxids.hrc>
41 #include <svx/optgenrl.hxx>
42 
43 using namespace css;
44 
45 namespace
46 {
47 
48 // rows
49 enum RowType
50 {
51  Row_Company,
52  Row_Name,
53  Row_Name_Russian,
54  Row_Name_Eastern,
55  Row_Street,
56  Row_Street_Russian,
57  Row_City,
58  Row_City_US,
59  Row_Country,
60  Row_TitlePos,
61  Row_Phone,
62  Row_FaxMail,
63 
64  nRowCount
65 };
66 
67 // language flags
68 namespace Lang
69 {
70  unsigned const Others = 1;
71  unsigned const Russian = 2;
72  unsigned const Eastern = 4;
73  unsigned const US = 8;
74  unsigned const All = static_cast<unsigned>(-1);
75 }
76 
77 
78 // vRowInfo[] -- rows (text + one or more edit boxes)
79 // The order is the same as in RowType above, which is up to down.
80 
81 struct
82 {
83  // id of the text
84  const char *pTextId;
85  // language flags (see Lang above):
86  // which language is this row for?
87  unsigned nLangFlags;
88 }
89 const vRowInfo[] =
90 {
91  { "companyft", Lang::All },
92  { "nameft", Lang::All & ~Lang::Russian & ~Lang::Eastern },
93  { "rusnameft", Lang::Russian },
94  { "eastnameft", Lang::Eastern },
95  { "streetft", Lang::All & ~Lang::Russian },
96  { "russtreetft", Lang::Russian },
97  { "icityft", Lang::All & ~Lang::US },
98  { "cityft", Lang::US },
99  { "countryft", Lang::All },
100  { "titleft", Lang::All },
101  { "phoneft", Lang::All },
102  { "faxft", Lang::All },
103 };
104 
105 
106 // vFieldInfo[] -- edit boxes
107 // The order is up to down, and then left to right.
108 
109 struct
110 {
111  // in which row?
112  RowType eRow;
113  // id of the edit box
114  const char *pEditId;
115  // id for SvtUserOptions in unotools/useroptions.hxx
116  UserOptToken nUserOptionsId;
117  // id for settings the focus (defined in svx/optgenrl.hxx)
118  EditPosition nGrabFocusId;
119 }
120 const vFieldInfo[] =
121 {
122  // Company
123  { Row_Company, "company", UserOptToken::Company, EditPosition::COMPANY },
124  // Name
125  { Row_Name, "firstname", UserOptToken::FirstName, EditPosition::FIRSTNAME },
126  { Row_Name, "lastname", UserOptToken::LastName, EditPosition::LASTNAME },
127  { Row_Name, "shortname", UserOptToken::ID, EditPosition::SHORTNAME },
128  // Name (russian)
129  { Row_Name_Russian, "ruslastname", UserOptToken::LastName, EditPosition::LASTNAME },
130  { Row_Name_Russian, "rusfirstname", UserOptToken::FirstName, EditPosition::FIRSTNAME },
131  { Row_Name_Russian, "rusfathersname", UserOptToken::FathersName, EditPosition::UNKNOWN },
132  { Row_Name_Russian, "russhortname", UserOptToken::ID, EditPosition::SHORTNAME },
133  // Name (eastern: reversed name ord
134  { Row_Name_Eastern, "eastlastname", UserOptToken::LastName, EditPosition::LASTNAME },
135  { Row_Name_Eastern, "eastfirstname", UserOptToken::FirstName, EditPosition::FIRSTNAME },
136  { Row_Name_Eastern, "eastshortname", UserOptToken::ID, EditPosition::SHORTNAME },
137  // Street
138  { Row_Street, "street", UserOptToken::Street, EditPosition::STREET },
139  // Street (russian)
140  { Row_Street_Russian, "russtreet", UserOptToken::Street, EditPosition::STREET },
141  { Row_Street_Russian, "apartnum", UserOptToken::Apartment, EditPosition::UNKNOWN },
142  // City
143  { Row_City, "izip", UserOptToken::Zip, EditPosition::PLZ },
144  { Row_City, "icity", UserOptToken::City, EditPosition::CITY },
145  // City (US)
146  { Row_City_US, "city", UserOptToken::City, EditPosition::CITY },
147  { Row_City_US, "state", UserOptToken::State, EditPosition::STATE },
148  { Row_City_US, "zip", UserOptToken::Zip, EditPosition::PLZ },
149  // Country
150  { Row_Country, "country", UserOptToken::Country, EditPosition::COUNTRY },
151  // Title/Position
152  { Row_TitlePos, "title", UserOptToken::Title, EditPosition::TITLE },
153  { Row_TitlePos, "position", UserOptToken::Position, EditPosition::POSITION },
154  // Phone
155  { Row_Phone, "home", UserOptToken::TelephoneHome, EditPosition::TELPRIV },
156  { Row_Phone, "work", UserOptToken::TelephoneWork, EditPosition::TELCOMPANY },
157  // Fax/Mail
158  { Row_FaxMail, "fax", UserOptToken::Fax, EditPosition::FAX },
159  { Row_FaxMail, "email", UserOptToken::Email, EditPosition::EMAIL },
160 };
161 
162 
163 } // namespace
164 
165 
166 // Row
167 
169 {
170  // row label
171  std::unique_ptr<weld::Label> xLabel;
172  // first and last field in the row (last is exclusive)
173  unsigned nFirstField, nLastField;
174 
175 public:
176  explicit Row (std::unique_ptr<weld::Label> xLabel_)
177  : xLabel(std::move(xLabel_))
178  , nFirstField(0)
179  , nLastField(0)
180  {
181  xLabel->show();
182  }
183 };
184 
185 
186 // Field
187 
189 {
190  // which field is this? (in vFieldInfo[] above)
191  unsigned iField;
192  // edit box
193  std::unique_ptr<weld::Entry> xEdit;
194  std::unique_ptr<weld::Container> xParent;
195 
196 public:
197  Field (std::unique_ptr<weld::Entry> xEdit_, unsigned iField_)
198  : iField(iField_)
199  , xEdit(std::move(xEdit_))
200  , xParent(xEdit->weld_parent())
201  {
202  //We want all widgets inside a container, so each row of the toplevel
203  //grid has another container in it. To avoid adding spacing to these
204  //empty grids they all default to invisible, so show them if their
205  //children are visible
206  xParent->show();
207  xEdit->show();
208  }
209 };
210 
212  : SfxTabPage(pPage, pController, "cui/ui/optuserpage.ui", "OptUserPage", &rCoreSet)
213  , m_xUseDataCB(m_xBuilder->weld_check_button("usefordocprop"))
214  , m_xCryptoFrame(m_xBuilder->weld_widget( "cryptography"))
215  , m_xSigningKeyLB(m_xBuilder->weld_combo_box("signingkey"))
216  , m_xEncryptionKeyLB(m_xBuilder->weld_combo_box("encryptionkey"))
217  , m_xEncryptToSelfCB(m_xBuilder->weld_check_button("encrypttoself"))
218 {
219  InitControls();
220 #if HAVE_FEATURE_GPGME
222 #else
223  m_xCryptoFrame->hide();
224 #endif
225 
226  SetExchangeSupport(); // this page needs ExchangeSupport
227  SetLinks();
228 }
229 
231 {
232 }
233 
234 // Initializes the titles and the edit boxes,
235 // according to vRowInfo[] and vFieldInfo[] above.
237 {
238  // which language bit do we use? (see Lang and vRowInfo[] above)
239  unsigned LangBit;
241  if (l == LANGUAGE_ENGLISH_US)
242  LangBit = Lang::US;
243  else if (l == LANGUAGE_RUSSIAN)
244  LangBit = Lang::Russian;
245  else
246  {
248  LangBit = Lang::Eastern;
249  else
250  LangBit = Lang::Others;
251  }
252 
253  // creating rows
254  unsigned iField = 0;
255  for (unsigned iRow = 0; iRow != nRowCount; ++iRow)
256  {
257  RowType const eRow = static_cast<RowType>(iRow);
258  // is the row visible?
259  if (!(vRowInfo[iRow].nLangFlags & LangBit))
260  continue;
261  // creating row
262  vRows.push_back(std::make_shared<Row>(
263  m_xBuilder->weld_label(vRowInfo[iRow].pTextId)));
264  Row& rRow = *vRows.back();
265  // fields in the row
266  static unsigned const nFieldCount = SAL_N_ELEMENTS(vFieldInfo);
267  // skipping other (invisible) rows
268  while (iField != nFieldCount && vFieldInfo[iField].eRow != eRow)
269  ++iField;
270  // fields in the row
271  rRow.nFirstField = vFields.size();
272  for ( ; iField != nFieldCount && vFieldInfo[iField].eRow == eRow; ++iField)
273  {
274  // creating edit field
275  vFields.push_back(std::make_shared<Field>(
276  m_xBuilder->weld_entry(vFieldInfo[iField].pEditId), iField));
277  // "short name" field?
278  if (vFieldInfo[iField].nUserOptionsId == UserOptToken::ID)
279  {
280  nNameRow = vRows.size() - 1;
281  nShortNameField = vFields.size() - 1;
282  }
283  }
284  rRow.nLastField = vFields.size();
285  }
286 }
287 
289 {
290 #if HAVE_FEATURE_GPGME
291  m_xCryptoFrame->show();
292 
293  uno::Reference< xml::crypto::XSEInitializer > xSEInitializer;
294  try
295  {
296  xSEInitializer = xml::crypto::GPGSEInitializer::create( comphelper::getProcessComponentContext() );
297  uno::Reference<xml::crypto::XXMLSecurityContext> xSC = xSEInitializer->createSecurityContext( OUString() );
298  if (xSC.is())
299  {
300  uno::Reference<xml::crypto::XSecurityEnvironment> xSE = xSC->getSecurityEnvironment();
301  uno::Sequence<uno::Reference<security::XCertificate>> xCertificates = xSE->getPersonalCertificates();
302 
303  if (xCertificates.hasElements())
304  {
305  for (auto& xCert : xCertificates)
306  {
307  m_xSigningKeyLB->append_text( xCert->getIssuerName());
308  m_xEncryptionKeyLB->append_text( xCert->getIssuerName());
309  }
310  }
311 
312  //tdf#115015: wrap checkbox text and listboxes if necessary
313  int nPrefWidth(m_xEncryptToSelfCB->get_preferred_size().Width());
314  int nMaxWidth = m_xEncryptToSelfCB->get_approximate_digit_width() * 40;
315  if (nPrefWidth > nMaxWidth)
316  {
317  m_xSigningKeyLB->set_size_request(nMaxWidth, -1);
318  m_xEncryptionKeyLB->set_size_request(nMaxWidth, -1);
319  m_xEncryptToSelfCB->set_label_wrap(true);
320  m_xEncryptToSelfCB->set_size_request(nMaxWidth, -1);
321  }
322  }
323  }
324  catch ( uno::Exception const & )
325  {}
326 #endif
327 
328 }
329 
331 {
332  // link for updating the initials
333  Link<weld::Entry&,void> aLink = LINK( this, SvxGeneralTabPage, ModifyHdl_Impl );
334  Row& rNameRow = *vRows[nNameRow];
335  for (unsigned i = rNameRow.nFirstField; i != rNameRow.nLastField - 1; ++i)
336  vFields[i]->xEdit->connect_changed(aLink);
337 }
338 
339 
340 std::unique_ptr<SfxTabPage> SvxGeneralTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
341 {
342  return std::make_unique<SvxGeneralTabPage>( pPage, pController, *rAttrSet );
343 }
344 
346 {
347  // remove leading and trailing whitespaces
348  for (auto const & i: vFields)
349  i->xEdit->set_text(comphelper::string::strip(i->xEdit->get_text(), ' '));
350 
351  bool bModified = false;
352  bModified |= GetData_Impl();
353  if (m_xUseDataCB->get_active() != officecfg::Office::Common::Save::Document::UseUserData::get())
354  {
356  officecfg::Office::Common::Save::Document::UseUserData::set(m_xUseDataCB->get_active(), xChanges);
357  xChanges->commit();
358  bModified = true;
359  }
360  return bModified;
361 }
362 
364 {
365  SetData_Impl();
366 
367  sal_uInt16 const nWhich = GetWhich(SID_FIELD_GRABFOCUS);
368 
369  if (rSet->GetItemState(nWhich) == SfxItemState::SET)
370  {
371  EditPosition nField = static_cast<EditPosition>(static_cast<const SfxUInt16Item&>(rSet->Get(nWhich)).GetValue());
372  if (nField != EditPosition::UNKNOWN)
373  {
374  for (auto const & i: vFields)
375  if (nField == vFieldInfo[i->iField].nGrabFocusId)
376  i->xEdit->grab_focus();
377  }
378  else
379  vFields.front()->xEdit->grab_focus();
380  }
381 
382  m_xUseDataCB->set_active(officecfg::Office::Common::Save::Document::UseUserData::get());
383 }
384 
385 
386 // ModifyHdl_Impl()
387 // This handler updates the initials (short name)
388 // when one of the name fields was updated.
389 IMPL_LINK( SvxGeneralTabPage, ModifyHdl_Impl, weld::Entry&, rEdit, void )
390 {
391  // short name field and row
392  Field& rShortName = *vFields[nShortNameField];
393  Row& rNameRow = *vRows[nNameRow];
394  // number of initials
395  unsigned const nInits = rNameRow.nLastField - rNameRow.nFirstField - 1;
396  // which field was updated? (in rNameRow)
397  unsigned nField = nInits;
398  for (unsigned i = 0; i != nInits; ++i)
399  {
400  if (vFields[rNameRow.nFirstField + i]->xEdit.get() == &rEdit)
401  nField = i;
402  }
403  // updating the initial
404  if (!(nField < nInits && rShortName.xEdit->get_sensitive()))
405  return;
406 
407  OUString sShortName = rShortName.xEdit->get_text();
408  // clear short name if it contains more characters than the number of initials
409  if (o3tl::make_unsigned(sShortName.getLength()) > nInits)
410  {
411  rShortName.xEdit->set_text(OUString());
412  }
413  while (o3tl::make_unsigned(sShortName.getLength()) < nInits)
414  sShortName += " ";
415  OUString sName = rEdit.get_text();
416  OUString sLetter = sName.isEmpty()
417  ? OUString(u' ') : sName.copy(0, 1);
418  rShortName.xEdit->set_text(sShortName.replaceAt(nField, 1, sLetter).trim());
419 }
420 
421 
423 {
424  // updating
425  SvtUserOptions aUserOpt;
426  for (auto const & i: vFields)
427  aUserOpt.SetToken(
428  vFieldInfo[i->iField].nUserOptionsId,
429  i->xEdit->get_text()
430  );
431 
432  // modified?
433  bool bModified = false;
434  for (auto const & i: vFields)
435  {
436  if (i->xEdit->get_value_changed_from_saved())
437  {
438  bModified = true;
439  break;
440  }
441  }
442 
443 #if HAVE_FEATURE_GPGME
444  OUString aSK = m_xSigningKeyLB->get_active() == 0 ? OUString() //i.e. no key
445  : m_xSigningKeyLB->get_active_text();
446  OUString aEK = m_xEncryptionKeyLB->get_active() == 0 ? OUString()
447  : m_xEncryptionKeyLB->get_active_text();
448 
449  aUserOpt.SetToken( UserOptToken::SigningKey, aSK );
450  aUserOpt.SetToken( UserOptToken::EncryptionKey, aEK );
451  aUserOpt.SetBoolValue( UserOptToken::EncryptToSelf, m_xEncryptToSelfCB->get_active() );
452 
453  bModified |= m_xSigningKeyLB->get_value_changed_from_saved() ||
454  m_xEncryptionKeyLB->get_value_changed_from_saved() ||
455  m_xEncryptToSelfCB->get_state_changed_from_saved();
456 #endif
457 
458  return bModified;
459 }
460 
461 
463 {
464  // updating and disabling edit boxes
465  SvtUserOptions aUserOpt;
466  for (auto const & i: vRows)
467  {
468  Row& rRow = *i;
469  // the label is enabled if any of its edit fields are enabled
470  bool bEnableLabel = false;
471  for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
472  {
473  Field& rField = *vFields[iField];
474  // updating content
475  UserOptToken const nToken = vFieldInfo[rField.iField].nUserOptionsId;
476  rField.xEdit->set_text(aUserOpt.GetToken(nToken));
477  // is enabled?
478  bool const bEnableEdit = !aUserOpt.IsTokenReadonly(nToken);
479  rField.xEdit->set_sensitive(bEnableEdit);
480  bEnableLabel = bEnableLabel || bEnableEdit;
481  }
482  rRow.xLabel->set_sensitive(bEnableLabel);
483  }
484 
485  // saving
486  for (auto const & i: vFields)
487  i->xEdit->save_value();
488 
489 #if HAVE_FEATURE_GPGME
490  OUString aSK = aUserOpt.GetToken(UserOptToken::SigningKey);
491  aSK.isEmpty() ? m_xSigningKeyLB->set_active( 0 ) //i.e. 'No Key'
492  : m_xSigningKeyLB->set_active_text( aSK );
493 
494  OUString aEK = aUserOpt.GetToken(UserOptToken::EncryptionKey);
495  aEK.isEmpty() ? m_xEncryptionKeyLB->set_active( 0 ) //i.e. 'No Key'
496  : m_xEncryptionKeyLB->set_active_text( aEK );
497 
498  m_xEncryptToSelfCB->set_active( aUserOpt.GetEncryptToSelf() );
499 #endif
500 }
501 
502 
504 {
505  if ( pSet_ )
506  FillItemSet( pSet_ );
507  return DeactivateRC::LeavePage;
508 }
509 
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString GetToken(UserOptToken nToken) const
#define LANGUAGE_ENGLISH_US
const LanguageTag & GetUILanguageTag() const
std::string GetValue
unsigned nShortNameField
Definition: cuioptgenrl.hxx:47
LanguageType getLanguageType(bool bResolveSystem=true) const
OString strip(std::string_view rIn, char c)
static const AllSettings & GetSettings()
#define LANGUAGE_RUSSIAN
std::unique_ptr< weld::Entry > xEdit
Definition: optgenrl.cxx:193
std::unique_ptr< weld::Widget > m_xCryptoFrame
Definition: cuioptgenrl.hxx:35
RowType
Definition: optgenrl.cxx:49
std::unique_ptr< weld::ComboBox > m_xSigningKeyLB
Definition: cuioptgenrl.hxx:36
std::vector< std::shared_ptr< Row > > vRows
Definition: cuioptgenrl.hxx:40
bool IsTokenReadonly(UserOptToken nToken) const
std::unique_ptr< weld::CheckButton > m_xEncryptToSelfCB
Definition: cuioptgenrl.hxx:38
void SetExchangeSupport()
SvxGeneralTabPage(weld::Container *pPage, weld::DialogController *pController, const SfxItemSet &rSet)
Definition: optgenrl.cxx:211
static std::shared_ptr< ConfigurationChanges > create(css::uno::Reference< css::uno::XComponentContext > const &context=comphelper::getProcessComponentContext())
const char * sName
virtual bool FillItemSet(SfxItemSet *rSet) override
Definition: optgenrl.cxx:345
#define SAL_N_ELEMENTS(arr)
Field(std::unique_ptr< weld::Entry > xEdit_, unsigned iField_)
Definition: optgenrl.cxx:197
static bool isFamilyNameFirst(LanguageType nLang)
void SetBoolValue(UserOptToken nToken, bool bNewValue)
void InitCryptography()
Definition: optgenrl.cxx:288
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
int i
bool GetEncryptToSelf() const
std::unique_ptr< weld::CheckButton > m_xUseDataCB
Definition: cuioptgenrl.hxx:34
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
float u
IMPL_LINK(SvxGeneralTabPage, ModifyHdl_Impl, weld::Entry &, rEdit, void)
Definition: optgenrl.cxx:389
virtual OUString get_text() const =0
virtual DeactivateRC DeactivatePage(SfxItemSet *pSet) override
Definition: optgenrl.cxx:503
void SetToken(UserOptToken nToken, OUString const &rNewToken)
DefTokenId nToken
std::vector< std::shared_ptr< Field > > vFields
Definition: cuioptgenrl.hxx:43
weld::Entry & rEdit
UserOptToken
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
virtual void Reset(const SfxItemSet *rSet) override
Definition: optgenrl.cxx:363
Reference< XComponentContext > getProcessComponentContext()
std::unique_ptr< weld::Label > xLabel
Definition: optgenrl.cxx:171
DeactivateRC
virtual ~SvxGeneralTabPage() override
Definition: optgenrl.cxx:230
std::unique_ptr< weld::ComboBox > m_xEncryptionKeyLB
Definition: cuioptgenrl.hxx:37
static std::unique_ptr< SfxTabPage > Create(weld::Container *pPage, weld::DialogController *pController, const SfxItemSet *rAttrSet)
Definition: optgenrl.cxx:340
Row(std::unique_ptr< weld::Label > xLabel_)
Definition: optgenrl.cxx:176
sal_uInt16 GetWhich(sal_uInt16 nSlot, bool bDeep=true) const
std::unique_ptr< weld::Container > xParent
Definition: optgenrl.cxx:194