Files
Michael Weghorn 14cfde3c60 tdf#130857 weld: Have separate method to set treeview toggle button type
So far, weld::TreeView::enable_toggle_buttons was doing
two things:

* enable a special "toggle button column" to be accessed
  with a special column index of -1 in the weld::TreeView
  API (as documented)

* switch the type of *all* toggle buttons used in all cells/columns
  of the TreeView to the type passed as a parameter
  (not only set the type of the toggle buttons for the
  special toggle button column at index -1)

Untangle these 2 things by splitting this to two methods:

* weld::TreeView::enable_toggle_buttons now only enables
  the special toggle button column at index -1.

* The new weld::TreeView::set_toggle_button_type sets
  the type of all toggle buttons used in the table.

This makes the API clearer and will allow using one of the
two without necessarily also using the other, which will
allow further simplification/improvements in upcoming
commits.

It could also make it easier to support only setting
the type of single columns to use radio buttons in the
future (i.e. have one column using radio buttons and
another one using check buttons in the same table), but
that would require further rework in the underlying
toolkit-specific implementations (in particular the vcl one).

One case where mixing the two things together results
in non-optimal behavior is the "Assign Styles" dialog
with the vcl implementation:

While the special toggle column with index -1 isn't
actually used, the SwAddStylesDlg_Impl ctor still
calls weld::TreeView::enable_toggle_buttons, presumably
only to enable the use of radio buttons for the actually
used toggle columns at the end.
As a consequence, the style names in the first column
are indented for no good reason (but only to leave space
for drawing the toggle buttons for the special toggle
button column that was enabled without actually being
needed).
This will be adjusted in an upcoming commit.

Initially, just replace all callers of
weld::TreeView::enable_toggle_buttons passing
weld::ColumnToggleType::Radio for the type with
calls to both methods, to keep the existing behavior
and be able to further look into further improvements
separately.

Change-Id: I098feb474162d61c5452c3496293a420118e2f4f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207250
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
2026-06-25 18:23:52 +02:00

246 lines
8.6 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/.
*/
#include <officecfg/Office/Common.hxx>
#include <osl/file.hxx>
#include <osl/security.hxx>
#include <sfx2/filedlghelper.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <vcl/vclenum.hxx>
#include <vcl/weld/Builder.hxx>
#include <vcl/weld/Dialog.hxx>
#include "certpath.hxx"
#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
#include <comphelper/processfactory.hxx>
using namespace ::com::sun::star;
CertPathDialog::CertPathDialog(weld::Window* pParent)
: GenericDialogController(pParent, u"cui/ui/certdialog.ui"_ustr, u"CertDialog"_ustr)
, m_xManualButton(m_xBuilder->weld_button(u"add"_ustr))
, m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr))
, m_xCertPathList(m_xBuilder->weld_tree_view(u"paths"_ustr))
, m_sAddDialogText(m_xBuilder->weld_label(u"certdir"_ustr)->get_label())
, m_sManualLabel(m_xBuilder->weld_label(u"manual"_ustr)->get_label())
{
m_xCertPathList->set_size_request(m_xCertPathList->get_approximate_digit_width() * 140,
m_xCertPathList->get_height_rows(6));
// needed for VCLPLUGIN != gtk3 (e.g. "gen")
int nControlWidth = m_xCertPathList->get_approximate_digit_width() * 40;
m_xCertPathList->set_column_fixed_widths({nControlWidth});
m_xCertPathList->enable_toggle_buttons();
m_xCertPathList->set_toggle_button_type(weld::ColumnToggleType::Radio);
m_xCertPathList->connect_toggled(LINK(this, CertPathDialog, CheckHdl_Impl));
m_xManualButton->connect_clicked( LINK( this, CertPathDialog, ManualHdl_Impl ) );
m_xOKButton->connect_clicked( LINK( this, CertPathDialog, OKHdl_Impl ) );
}
void CertPathDialog::Init()
{
m_xCertPathList->clear();
m_xCertPathList->set_sensitive(true);
try
{
const uno::Reference<uno::XComponentContext>& xContext = comphelper::getProcessComponentContext();
uno::Reference<xml::crypto::XNSSInitializer> xCipherContextSupplier = xml::crypto::NSSInitializer::create(xContext);
OUString sActivePath = xCipherContextSupplier->getNSSPath();
auto aProductList = xCipherContextSupplier->getNSSProfiles();
// these map to the integer values of mozilla::MozillaProductType
const char* const productNames[4] = {
"",
"mozilla",
"firefox",
"thunderbird"
};
for (const auto& rNSSProfile : aProductList)
{
if (rNSSProfile.Type == mozilla::MozillaProductType_Default)
{
if (rNSSProfile.Name == "MOZILLA_CERTIFICATE_FOLDER" && !rNSSProfile.Path.isEmpty())
{
AddCertPath(u"$MOZILLA_CERTIFICATE_FOLDER"_ustr, rNSSProfile.Path);
m_xCertPathList->set_sensitive(false);
}
else if (rNSSProfile.Name == "MANUAL")
AddManualCertPath(rNSSProfile.Path);
}
else
{
OUString sEntry = OUString::createFromAscii(
productNames[static_cast<int>(rNSSProfile.Type)]) + ":" + rNSSProfile.Name;
AddCertPath(sEntry, rNSSProfile.Path, rNSSProfile.Path == sActivePath);
}
}
OUString sManualCertPath = officecfg::Office::Common::Security::Scripting::ManualCertDir::get();
if (!sManualCertPath.isEmpty())
AddManualCertPath(sManualCertPath, false);
}
catch (const uno::Exception&)
{
}
}
void CertPathDialog::AddManualCertPath(const OUString& sUserSetCertPath, bool bSelect)
{
if (sUserSetCertPath.isEmpty())
return;
::osl::DirectoryItem aUserPathItem;
OUString sUserSetCertURLPath;
osl::FileBase::getFileURLFromSystemPath(sUserSetCertPath, sUserSetCertURLPath);
if (::osl::FileBase::E_None == ::osl::DirectoryItem::get(sUserSetCertURLPath, aUserPathItem))
{
::osl::FileStatus aStatus( osl_FileStatus_Mask_Validate );
if (::osl::FileBase::E_None == aUserPathItem.getFileStatus(aStatus))
// the cert path exists
AddCertPath(m_sManualLabel, sUserSetCertPath, bSelect);
}
}
IMPL_LINK_NOARG(CertPathDialog, OKHdl_Impl, weld::Button&, void)
{
try
{
std::shared_ptr< comphelper::ConfigurationChanges > batch(
comphelper::ConfigurationChanges::create());
const int nEntry = m_xCertPathList->get_selected_index();
officecfg::Office::Common::Security::Scripting::CertDir::set(
nEntry == -1 ? OUString() : m_xCertPathList->get_id(nEntry), batch);
officecfg::Office::Common::Security::Scripting::ManualCertDir::set(m_sManualPath, batch);
batch->commit();
}
catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION("cui.options", "CertPathDialog::OKHdl_Impl()");
}
m_xDialog->response(RET_OK);
}
bool CertPathDialog::isActiveServicePath() const
{
int nEntry = m_xCertPathList->get_selected_index();
if (nEntry == -1)
return true;
try
{
const uno::Reference<uno::XComponentContext>& xContext = comphelper::getProcessComponentContext();
uno::Reference<xml::crypto::XNSSInitializer> xCipherContextSupplier = xml::crypto::NSSInitializer::create(xContext);
if (!xCipherContextSupplier->getIsNSSinitialized())
return true;
return (xCipherContextSupplier->getNSSPath() == m_xCertPathList->get_id(nEntry));
}
catch (const uno::Exception&)
{
return false;
}
}
CertPathDialog::~CertPathDialog()
{
}
IMPL_LINK(CertPathDialog, CheckHdl_Impl, const weld::TreeView::iter_col&, rRowCol, void)
{
HandleEntryChecked(m_xCertPathList->get_iter_index_in_parent(rRowCol.first));
}
void CertPathDialog::HandleEntryChecked(int nRow)
{
const bool bChecked = m_xCertPathList->get_toggle(nRow) == TRISTATE_TRUE;
if (bChecked)
{
// we have radio button behavior -> so uncheck the other entries
m_xCertPathList->select(nRow);
const int nCount = m_xCertPathList->n_children();
for (int i = 0; i < nCount; ++i)
{
if (i != nRow)
m_xCertPathList->set_toggle(i, TRISTATE_FALSE);
}
}
}
void CertPathDialog::AddCertPath(const OUString &rProfile, const OUString &rPath, const bool bSelect)
{
int nRow = -1;
for (int i = 0, nCount = m_xCertPathList->n_children(); i < nCount; ++i)
{
OUString sCertPath = m_xCertPathList->get_id(i);
//already exists, just select the original one
if (sCertPath == rPath)
{
const bool bWantSelected = bSelect || m_xCertPathList->get_toggle(i);
m_xCertPathList->set_toggle(i, bWantSelected ? TRISTATE_TRUE : TRISTATE_FALSE);
HandleEntryChecked(i);
return;
}
else if (m_xCertPathList->get_text(i, 0) == rProfile)
nRow = i;
}
if (m_sManualLabel == rProfile)
m_sManualPath = rPath;
if (nRow < 0)
{
m_xCertPathList->append();
nRow = m_xCertPathList->n_children() - 1;
}
m_xCertPathList->set_toggle(nRow, bSelect ? TRISTATE_TRUE : TRISTATE_FALSE);
m_xCertPathList->set_text(nRow, rProfile, 0);
m_xCertPathList->set_text(nRow, rPath, 1);
m_xCertPathList->set_id(nRow, rPath);
HandleEntryChecked(nRow);
}
IMPL_LINK_NOARG(CertPathDialog, ManualHdl_Impl, weld::Button&, void)
{
try
{
uno::Reference<ui::dialogs::XFolderPicker2> xFolderPicker = sfx2::createFolderPicker(
comphelper::getProcessComponentContext(), m_xDialog.get());
OUString sURL;
if (!m_sManualPath.isEmpty())
osl::FileBase::getFileURLFromSystemPath(m_sManualPath, sURL);
if (sURL.isEmpty())
osl::Security().getHomeDir(sURL);
xFolderPicker->setDisplayDirectory(sURL);
xFolderPicker->setDescription(m_sAddDialogText);
if (xFolderPicker->execute() == ui::dialogs::ExecutableDialogResults::OK)
{
sURL = xFolderPicker->getDirectory();
OUString aPath;
if (osl::FileBase::E_None == osl::FileBase::getSystemPathFromFileURL(sURL, aPath))
AddCertPath(m_sManualLabel, aPath);
}
}
catch (const uno::Exception &)
{
TOOLS_WARN_EXCEPTION("cui.options", "");
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */