1
0
Fork 0
libreoffice/cui/source/options/optgenrl.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

608 lines
21 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/string.hxx>
#include <comphelper/processfactory.hxx>
#include <config_gpgme.h>
#if HAVE_FEATURE_GPGME
# include <com/sun/star/xml/crypto/GPGSEInitializer.hpp>
# include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
#endif
#include <com/sun/star/xml/crypto/SEInitializer.hpp>
#include <comphelper/xmlsechelper.hxx>
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
#include <i18nlangtag/languagetag.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <o3tl/safeint.hxx>
#include <vcl/svapp.hxx>
#include <svl/intitem.hxx>
#include <vcl/settings.hxx>
#include <officecfg/Office/Common.hxx>
#include <unotools/useroptions.hxx>
#include <cuioptgenrl.hxx>
#include <svx/svxids.hrc>
#include <svx/optgenrl.hxx>
using namespace css;
namespace
{
// rows
enum RowType
{
Row_Company,
Row_Name,
Row_Name_Russian,
Row_Name_Eastern,
Row_Street,
Row_Street_Russian,
Row_City,
Row_City_US,
Row_Country,
Row_TitlePos,
Row_Phone,
Row_FaxMail,
nRowCount
};
// language flags
namespace Lang
{
unsigned const Others = 1;
unsigned const Russian = 2;
unsigned const Eastern = 4;
unsigned const US = 8;
unsigned const All = static_cast<unsigned>(-1);
}
// vRowInfo[] -- rows (text + one or more edit boxes)
// The order is the same as in RowType above, which is up to down.
struct
{
// id of the lockimage
OUString pLockId;
// id of the text
OUString pTextId;
// language flags (see Lang above):
// which language is this row for?
unsigned nLangFlags;
}
const vRowInfo[] =
{
{ u"lockcompanyft"_ustr, u"companyft"_ustr, Lang::All },
{ u"locknameft"_ustr, u"nameft"_ustr, Lang::All & ~Lang::Russian & ~Lang::Eastern },
{ u"lockrusnameft"_ustr, u"rusnameft"_ustr, Lang::Russian },
{ u"lockeastnameft"_ustr, u"eastnameft"_ustr, Lang::Eastern },
{ u"lockstreetft"_ustr, u"streetft"_ustr, Lang::All & ~Lang::Russian },
{ u"lockrusstreetft"_ustr,u"russtreetft"_ustr, Lang::Russian },
{ u"lockicityft"_ustr, u"icityft"_ustr, Lang::All & ~Lang::US },
{ u"lockcityft"_ustr, u"cityft"_ustr, Lang::US },
{ u"lockcountryft"_ustr, u"countryft"_ustr, Lang::All },
{ u"locktitleft"_ustr, u"titleft"_ustr, Lang::All },
{ u"lockphoneft"_ustr, u"phoneft"_ustr, Lang::All },
{ u"lockfaxft"_ustr, u"faxft"_ustr, Lang::All },
};
// vFieldInfo[] -- edit boxes
// The order is up to down, and then left to right.
struct
{
// in which row?
RowType eRow;
// id of the edit box
OUString pEditId;
// id for SvtUserOptions in unotools/useroptions.hxx
UserOptToken nUserOptionsId;
// id for settings the focus (defined in svx/optgenrl.hxx)
EditPosition nGrabFocusId;
}
const vFieldInfo[] =
{
// Company
{ Row_Company, u"company"_ustr, UserOptToken::Company, EditPosition::COMPANY },
// Name
{ Row_Name, u"firstname"_ustr, UserOptToken::FirstName, EditPosition::FIRSTNAME },
{ Row_Name, u"lastname"_ustr, UserOptToken::LastName, EditPosition::LASTNAME },
{ Row_Name, u"shortname"_ustr, UserOptToken::ID, EditPosition::SHORTNAME },
// Name (russian)
{ Row_Name_Russian, u"ruslastname"_ustr, UserOptToken::LastName, EditPosition::LASTNAME },
{ Row_Name_Russian, u"rusfirstname"_ustr, UserOptToken::FirstName, EditPosition::FIRSTNAME },
{ Row_Name_Russian, u"rusfathersname"_ustr, UserOptToken::FathersName, EditPosition::UNKNOWN },
{ Row_Name_Russian, u"russhortname"_ustr, UserOptToken::ID, EditPosition::SHORTNAME },
// Name (eastern: reversed name ord
{ Row_Name_Eastern, u"eastlastname"_ustr, UserOptToken::LastName, EditPosition::LASTNAME },
{ Row_Name_Eastern, u"eastfirstname"_ustr, UserOptToken::FirstName, EditPosition::FIRSTNAME },
{ Row_Name_Eastern, u"eastshortname"_ustr, UserOptToken::ID, EditPosition::SHORTNAME },
// Street
{ Row_Street, u"street"_ustr, UserOptToken::Street, EditPosition::STREET },
// Street (russian)
{ Row_Street_Russian, u"russtreet"_ustr, UserOptToken::Street, EditPosition::STREET },
{ Row_Street_Russian, u"apartnum"_ustr, UserOptToken::Apartment, EditPosition::UNKNOWN },
// City
{ Row_City, u"izip"_ustr, UserOptToken::Zip, EditPosition::PLZ },
{ Row_City, u"icity"_ustr, UserOptToken::City, EditPosition::CITY },
// City (US)
{ Row_City_US, u"city"_ustr, UserOptToken::City, EditPosition::CITY },
{ Row_City_US, u"state"_ustr, UserOptToken::State, EditPosition::STATE },
{ Row_City_US, u"zip"_ustr, UserOptToken::Zip, EditPosition::PLZ },
// Country
{ Row_Country, u"country"_ustr, UserOptToken::Country, EditPosition::COUNTRY },
// Title/Position
{ Row_TitlePos, u"title"_ustr, UserOptToken::Title, EditPosition::TITLE },
{ Row_TitlePos, u"position"_ustr, UserOptToken::Position, EditPosition::POSITION },
// Phone
{ Row_Phone, u"home"_ustr, UserOptToken::TelephoneHome, EditPosition::TELPRIV },
{ Row_Phone, u"work"_ustr, UserOptToken::TelephoneWork, EditPosition::TELCOMPANY },
// Fax/Mail
{ Row_FaxMail, u"fax"_ustr, UserOptToken::Fax, EditPosition::FAX },
{ Row_FaxMail, u"email"_ustr, UserOptToken::Email, EditPosition::EMAIL },
};
} // namespace
// Row
struct SvxGeneralTabPage::Row
{
// row lockdown icon
std::unique_ptr<weld::Widget> xLockImg;
// row label
std::unique_ptr<weld::Label> xLabel;
// first and last field in the row (last is exclusive)
unsigned nFirstField, nLastField;
public:
explicit Row (std::unique_ptr<weld::Widget> xLockImg_, std::unique_ptr<weld::Label> xLabel_)
: xLockImg(std::move(xLockImg_))
, xLabel(std::move(xLabel_))
, nFirstField(0)
, nLastField(0)
{
xLabel->show();
}
};
// Field
struct SvxGeneralTabPage::Field
{
// which field is this? (in vFieldInfo[] above)
unsigned iField;
// edit box
std::unique_ptr<weld::Entry> xEdit;
std::unique_ptr<weld::Container> xParent;
public:
Field (std::unique_ptr<weld::Entry> xEdit_, unsigned iField_)
: iField(iField_)
, xEdit(std::move(xEdit_))
, xParent(xEdit->weld_parent())
{
//We want all widgets inside a container, so each row of the toplevel
//grid has another container in it. To avoid adding spacing to these
//empty grids they all default to invisible, so show them if their
//children are visible
xParent->show();
xEdit->show();
}
};
SvxGeneralTabPage::SvxGeneralTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet)
: SfxTabPage(pPage, pController, u"cui/ui/optuserpage.ui"_ustr, u"OptUserPage"_ustr, &rCoreSet)
, m_xUseDataCB(m_xBuilder->weld_check_button(u"usefordocprop"_ustr))
, m_xUseDataImg(m_xBuilder->weld_widget(u"lockusefordocprop"_ustr))
, m_xCryptoFrame(m_xBuilder->weld_widget( u"cryptography"_ustr))
, m_xSigningKeyLB(m_xBuilder->weld_entry(u"signingkey"_ustr))
, m_xSigningKeyFT(m_xBuilder->weld_label(u"signingkeylabel"_ustr))
, m_xSigningKeyImg(m_xBuilder->weld_widget(u"locksigningkey"_ustr))
, m_xSigningKeyButton(m_xBuilder->weld_button(u"picksigningkey"_ustr))
, m_xRemoveSigningKeyButton(m_xBuilder->weld_button(u"removesigningkey"_ustr))
, m_xEncryptionKeyLB(m_xBuilder->weld_entry(u"encryptionkey"_ustr))
, m_xEncryptionKeyFT(m_xBuilder->weld_label(u"encryptionkeylabel"_ustr))
, m_xEncryptionKeyImg(m_xBuilder->weld_widget(u"lockencryptionkey"_ustr))
, m_xEncryptionKeyButton(m_xBuilder->weld_button(u"pickencryptionkey"_ustr))
, m_xRemoveEncryptionKeyButton(m_xBuilder->weld_button(u"removeencryptionkey"_ustr))
, m_xEncryptToSelfCB(m_xBuilder->weld_check_button(u"encrypttoself"_ustr))
, m_xEncryptToSelfImg(m_xBuilder->weld_widget(u"lockencrypttoself"_ustr))
{
InitControls();
#if HAVE_FEATURE_GPGME
InitCryptography();
#else
m_xCryptoFrame->hide();
#endif
SetExchangeSupport(); // this page needs ExchangeSupport
SetLinks();
}
SvxGeneralTabPage::~SvxGeneralTabPage()
{
}
// Initializes the titles and the edit boxes,
// according to vRowInfo[] and vFieldInfo[] above.
void SvxGeneralTabPage::InitControls ()
{
// which language bit do we use? (see Lang and vRowInfo[] above)
unsigned LangBit;
LanguageType l = Application::GetSettings().GetUILanguageTag().getLanguageType();
if (l == LANGUAGE_ENGLISH_US)
LangBit = Lang::US;
else if (l == LANGUAGE_RUSSIAN)
LangBit = Lang::Russian;
else
{
if (MsLangId::isFamilyNameFirst(l))
LangBit = Lang::Eastern;
else
LangBit = Lang::Others;
}
// creating rows
unsigned iField = 0;
for (unsigned iRow = 0; iRow != nRowCount; ++iRow)
{
RowType const eRow = static_cast<RowType>(iRow);
// is the row visible?
if (!(vRowInfo[iRow].nLangFlags & LangBit))
continue;
// creating row
vRows.push_back(std::make_shared<Row>(m_xBuilder->weld_widget(vRowInfo[iRow].pLockId),
m_xBuilder->weld_label(vRowInfo[iRow].pTextId)));
Row& rRow = *vRows.back();
// fields in the row
static unsigned const nFieldCount = std::size(vFieldInfo);
// skipping other (invisible) rows
while (iField != nFieldCount && vFieldInfo[iField].eRow != eRow)
++iField;
// fields in the row
rRow.nFirstField = vFields.size();
for ( ; iField != nFieldCount && vFieldInfo[iField].eRow == eRow; ++iField)
{
// creating edit field
vFields.push_back(std::make_shared<Field>(
m_xBuilder->weld_entry(vFieldInfo[iField].pEditId), iField));
// "short name" field?
if (vFieldInfo[iField].nUserOptionsId == UserOptToken::ID)
{
nNameRow = vRows.size() - 1;
nShortNameField = vFields.size() - 1;
}
}
rRow.nLastField = vFields.size();
}
}
void SvxGeneralTabPage::InitCryptography()
{
#if HAVE_FEATURE_GPGME
m_xCryptoFrame->show();
m_xSigningKeyButton->connect_clicked(LINK(this, SvxGeneralTabPage, ChooseKeyButtonHdl));
m_xEncryptionKeyButton->connect_clicked(LINK(this, SvxGeneralTabPage, ChooseKeyButtonHdl));
m_xRemoveSigningKeyButton->connect_clicked(LINK(this, SvxGeneralTabPage, RemoveKeyButtonHdl));
m_xRemoveEncryptionKeyButton->connect_clicked(LINK(this, SvxGeneralTabPage, RemoveKeyButtonHdl));
#endif
}
IMPL_LINK(SvxGeneralTabPage, ChooseKeyButtonHdl, weld::Button&, rButton, void)
{
try
{
uno::Reference<security::XDocumentDigitalSignatures> xD(
security::DocumentDigitalSignatures::createDefault(
comphelper::getProcessComponentContext()));
xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
OUString aDescription;
uno::Reference<security::XCertificate> xCertificate;
if (m_xSigningKeyButton.get() == &rButton)
{
xCertificate = xD->selectSigningCertificate(aDescription);
}
else if (m_xEncryptionKeyButton.get() == &rButton)
{
auto xCerts = xD->chooseEncryptionCertificate(css::security::CertificateKind_OPENPGP);
if(xCerts.hasElements())
xCertificate = xCerts[0];
}
if(!xCertificate.is())
return;
OUString aKeyThumbprint
= comphelper::xmlsec::GetHexString(xCertificate->getSHA1Thumbprint(), "");
OUString aIssuer = comphelper::xmlsec::GetContentPart(xCertificate->getIssuerName(),
xCertificate->getCertificateKind());
OUString aSubject = comphelper::xmlsec::GetContentPart(xCertificate->getSubjectName(),
xCertificate->getCertificateKind());
OUString aKeyDisplayName;
switch (xCertificate->getCertificateKind())
{
case security::CertificateKind::CertificateKind_X509:
aKeyDisplayName = u"(X.509) "_ustr + aIssuer + u" "_ustr + aSubject;
break;
case security::CertificateKind::CertificateKind_OPENPGP:
aKeyDisplayName = u"(OpenPGP) "_ustr + aIssuer;
break;
default:
break;
}
if (m_xSigningKeyButton.get() == &rButton)
{
msCurrentSigningKey = aKeyThumbprint;
m_xSigningKeyLB->set_text(aKeyDisplayName);
}
else if (m_xEncryptionKeyButton.get() == &rButton)
{
msCurrentEncryptionKey = aKeyThumbprint;
m_xEncryptionKeyLB->set_text(aKeyDisplayName);
}
}
catch (const css::uno::Exception&)
{
TOOLS_WARN_EXCEPTION("cui.options", "" );
}
}
IMPL_LINK(SvxGeneralTabPage, RemoveKeyButtonHdl, weld::Button&, rButton, void)
{
if (m_xRemoveSigningKeyButton.get() == &rButton)
{
msCurrentSigningKey.clear();
m_xSigningKeyLB->set_text(u""_ustr);
}
else if (m_xRemoveEncryptionKeyButton.get() == &rButton)
{
msCurrentEncryptionKey.clear();
m_xEncryptionKeyLB->set_text(u""_ustr);
}
}
void SvxGeneralTabPage::SetLinks ()
{
// link for updating the initials
Link<weld::Entry&,void> aLink = LINK( this, SvxGeneralTabPage, ModifyHdl_Impl );
Row& rNameRow = *vRows[nNameRow];
for (unsigned i = rNameRow.nFirstField; i != rNameRow.nLastField - 1; ++i)
vFields[i]->xEdit->connect_changed(aLink);
}
std::unique_ptr<SfxTabPage> SvxGeneralTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
{
return std::make_unique<SvxGeneralTabPage>( pPage, pController, *rAttrSet );
}
OUString SvxGeneralTabPage::GetAllStrings()
{
OUString sAllStrings;
OUString labels[]
= { u"label1"_ustr, u"companyft"_ustr, u"nameft"_ustr, u"rusnameft"_ustr,
u"eastnameft"_ustr, u"streetft"_ustr, u"russtreetft"_ustr, u"icityft"_ustr,
u"cityft"_ustr, u"countryft"_ustr, u"titleft"_ustr, u"phoneft"_ustr,
u"faxft"_ustr, u"cryptographylabel"_ustr, u"signingkeylabel"_ustr, u"encryptionkeylabel"_ustr };
for (const auto& label : labels)
{
if (const auto pString = m_xBuilder->weld_label(label))
sAllStrings += pString->get_label() + " ";
}
sAllStrings += m_xUseDataCB->get_label() + " " + m_xEncryptToSelfCB->get_label() + " ";
return sAllStrings.replaceAll("_", "");
}
bool SvxGeneralTabPage::FillItemSet( SfxItemSet* )
{
// remove leading and trailing whitespaces
for (auto const & i: vFields)
i->xEdit->set_text(comphelper::string::strip(i->xEdit->get_text(), ' '));
bool bModified = false;
bModified |= GetData_Impl();
if (m_xUseDataCB->get_active() != officecfg::Office::Common::Save::Document::UseUserData::get())
{
auto xChanges = comphelper::ConfigurationChanges::create();
officecfg::Office::Common::Save::Document::UseUserData::set(m_xUseDataCB->get_active(), xChanges);
xChanges->commit();
bModified = true;
}
return bModified;
}
void SvxGeneralTabPage::Reset( const SfxItemSet* rSet )
{
SetData_Impl();
if (rSet->GetItemState(SID_FIELD_GRABFOCUS) == SfxItemState::SET)
{
EditPosition nField = static_cast<EditPosition>(rSet->Get(SID_FIELD_GRABFOCUS).GetValue());
if (nField != EditPosition::UNKNOWN)
{
for (auto const & i: vFields)
if (nField == vFieldInfo[i->iField].nGrabFocusId)
i->xEdit->grab_focus();
}
else
vFields.front()->xEdit->grab_focus();
}
m_xUseDataCB->set_active(officecfg::Office::Common::Save::Document::UseUserData::get());
}
// ModifyHdl_Impl()
// This handler updates the initials (short name)
// when one of the name fields was updated.
IMPL_LINK( SvxGeneralTabPage, ModifyHdl_Impl, weld::Entry&, rEdit, void )
{
// short name field and row
Field& rShortName = *vFields[nShortNameField];
Row& rNameRow = *vRows[nNameRow];
// number of initials
unsigned const nInits = rNameRow.nLastField - rNameRow.nFirstField - 1;
// which field was updated? (in rNameRow)
unsigned nField = nInits;
for (unsigned i = 0; i != nInits; ++i)
{
if (vFields[rNameRow.nFirstField + i]->xEdit.get() == &rEdit)
nField = i;
}
// updating the initial
if (!(nField < nInits && rShortName.xEdit->get_sensitive()))
return;
OUString sShortName = rShortName.xEdit->get_text();
// clear short name if it contains more characters than the number of initials
if (o3tl::make_unsigned(sShortName.getLength()) > nInits)
{
rShortName.xEdit->set_text(OUString());
}
while (o3tl::make_unsigned(sShortName.getLength()) < nInits)
sShortName += " ";
OUString sName = rEdit.get_text();
OUString sLetter = sName.isEmpty()
? OUString(u' ') : sName.copy(0, 1);
rShortName.xEdit->set_text(sShortName.replaceAt(nField, 1, sLetter).trim());
}
bool SvxGeneralTabPage::GetData_Impl()
{
// updating
SvtUserOptions aUserOpt;
for (auto const & i: vFields)
aUserOpt.SetToken(
vFieldInfo[i->iField].nUserOptionsId,
i->xEdit->get_text()
);
// modified?
bool bModified = false;
for (auto const & i: vFields)
{
if (i->xEdit->get_value_changed_from_saved())
{
bModified = true;
break;
}
}
#if HAVE_FEATURE_GPGME
aUserOpt.SetToken( UserOptToken::SigningKey, msCurrentSigningKey );
aUserOpt.SetToken( UserOptToken::SigningKeyDisplayName, m_xSigningKeyLB->get_text() );
aUserOpt.SetToken( UserOptToken::EncryptionKey, msCurrentEncryptionKey );
aUserOpt.SetToken( UserOptToken::EncryptionKeyDisplayName, m_xEncryptionKeyLB->get_text() );
aUserOpt.SetBoolValue( UserOptToken::EncryptToSelf, m_xEncryptToSelfCB->get_active() );
bModified |= m_xSigningKeyLB->get_value_changed_from_saved() ||
m_xEncryptionKeyLB->get_value_changed_from_saved() ||
m_xEncryptToSelfCB->get_state_changed_from_saved();
#endif
return bModified;
}
void SvxGeneralTabPage::SetData_Impl()
{
// updating and disabling edit boxes
SvtUserOptions aUserOpt;
for (auto const & i: vRows)
{
Row& rRow = *i;
// the label is enabled if any of its edit fields are enabled
bool bEnableLabel = false;
for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
{
Field& rField = *vFields[iField];
// updating content
UserOptToken const nToken = vFieldInfo[rField.iField].nUserOptionsId;
rField.xEdit->set_text(aUserOpt.GetToken(nToken));
// is enabled?
bool const bEnableEdit = !aUserOpt.IsTokenReadonly(nToken);
rField.xEdit->set_sensitive(bEnableEdit);
bEnableLabel = bEnableLabel || bEnableEdit;
}
rRow.xLabel->set_sensitive(bEnableLabel);
rRow.xLockImg->set_visible(!bEnableLabel);
}
// saving
for (auto const & i: vFields)
i->xEdit->save_value();
//enabling and disabling remaining fields
bool bEnable = !officecfg::Office::Common::Save::Document::UseUserData::isReadOnly();
m_xUseDataCB->set_sensitive(bEnable);
m_xUseDataImg->set_visible(!bEnable);
#if HAVE_FEATURE_GPGME
bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::SigningKey);
m_xSigningKeyButton->set_sensitive(bEnable);
m_xSigningKeyFT->set_sensitive(bEnable);
m_xSigningKeyImg->set_visible(!bEnable);
bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::EncryptionKey);
m_xEncryptionKeyButton->set_sensitive(bEnable);
m_xEncryptionKeyFT->set_sensitive(bEnable);
m_xEncryptionKeyImg->set_visible(!bEnable);
bEnable = !aUserOpt.IsTokenReadonly(UserOptToken::EncryptToSelf);
m_xEncryptToSelfCB->set_sensitive(bEnable);
m_xEncryptToSelfImg->set_visible(!bEnable);
msCurrentSigningKey = aUserOpt.GetToken(UserOptToken::SigningKey);
m_xSigningKeyLB->set_text(aUserOpt.GetToken(UserOptToken::SigningKeyDisplayName));
msCurrentEncryptionKey = aUserOpt.GetToken(UserOptToken::EncryptionKey);
m_xEncryptionKeyLB->set_text(aUserOpt.GetToken(UserOptToken::EncryptionKeyDisplayName));
m_xEncryptToSelfCB->set_active( aUserOpt.GetEncryptToSelf() );
#endif
}
DeactivateRC SvxGeneralTabPage::DeactivatePage( SfxItemSet* pSet_ )
{
if ( pSet_ )
FillItemSet( pSet_ );
return DeactivateRC::LeavePage;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */