/* -*- 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 "optaboutconfig.hxx"
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/UnknownPropertyException.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/configuration/ReadWriteAccess.hpp>
#include <com/sun/star/configuration/XDocumentation.hpp>
#include <com/sun/star/configuration/theDefaultProvider.hpp>
#include <com/sun/star/container/XHierarchicalName.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/Type.hxx>
#include <com/sun/star/uno/TypeClass.hpp>
#include <com/sun/star/util/InvalidStateException.hpp>
#include <com/sun/star/util/SearchAlgorithms2.hpp>
#include <com/sun/star/util/SearchFlags.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <cppu/unotype.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <unotools/textsearch.hxx>
#include <utility>
#include <vcl/event.hxx>
#include <dialmgr.hxx>
#include <strings.hrc>
#include <algorithm>
#include <memory>
#include <vector>
using namespace ::com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::container;
struct Prop_Impl
{
OUString Name;
OUString Property;
Any Value;
Prop_Impl(OUString sName, OUString sProperty, Any aValue)
: Name(std::move(sName))
, Property(std::move(sProperty))
, Value(std::move(aValue))
{
}
};
struct UserData
{
bool bIsPropertyPath;
bool bIsReadOnly;
bool bWasModified;
OUString sPropertyPath;
Any aPropertyValue;
OUString sTooltip;
int aLineage;
Reference<XNameAccess> aXNameAccess;
explicit UserData(OUString aPropertyPath, Any aPropValue, OUString aTooltip, bool isReadOnly,
bool wasModified)
: bIsPropertyPath(true)
, bIsReadOnly(isReadOnly)
, bWasModified(wasModified)
, sPropertyPath(std::move(aPropertyPath))
, aPropertyValue(aPropValue)
, sTooltip(std::move(aTooltip))
, aLineage(0)
{
}
explicit UserData(Reference<XNameAccess> const& rXNameAccess, int rIndex)
: bIsPropertyPath(false)
, bIsReadOnly(false)
, bWasModified(false)
, aLineage(rIndex)
, aXNameAccess(rXNameAccess)
{
}
};
CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent)
: GenericDialogController(pParent, u"cui/ui/aboutconfigdialog.ui"_ustr, u"AboutConfig"_ustr)
, m_xResetBtn(m_xBuilder->weld_button(u"reset"_ustr))
, m_xEditBtn(m_xBuilder->weld_button(u"edit"_ustr))
, m_xSearchBtn(m_xBuilder->weld_button(u"searchButton"_ustr))
, m_xModifiedCheckBtn(m_xBuilder->weld_check_button(u"modifiedButton"_ustr))
, m_xSearchEdit(m_xBuilder->weld_entry(u"searchEntry"_ustr))
, m_xPrefBox(m_xBuilder->weld_tree_view(u"preferences"_ustr))
, m_xScratchIter(m_xPrefBox->make_iterator())
, m_bSorted(false)
{
m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100,
m_xPrefBox->get_height_rows(23));
m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick));
m_xEditBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, StandardHdl_Impl));
m_xResetBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, ResetBtnHdl_Impl));
m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl));
m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl));
m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl));
m_xModifiedCheckBtn->connect_toggled(LINK(this, CuiAboutConfigTabPage, ModifiedHdl_Impl));
m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
m_options.searchFlag
|= (util::SearchFlags::REG_NOT_BEGINOFLINE | util::SearchFlags::REG_NOT_ENDOFLINE);
float fWidth = m_xPrefBox->get_approximate_digit_width();
std::vector<int> aWidths{ o3tl::narrowing<int>(fWidth * 65), o3tl::narrowing<int>(fWidth * 20),
o3tl::narrowing<int>(fWidth * 8) };
m_xPrefBox->set_column_fixed_widths(aWidths);
m_xPrefBox->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage, QueryTooltip));
}
IMPL_LINK(CuiAboutConfigTabPage, QueryTooltip, const weld::TreeIter&, rIter, OUString)
{
UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rIter));
OUStringBuffer ret;
if (pUserData && pUserData->bIsReadOnly)
{
ret.append(CuiResId(RID_CUISTR_OPT_READONLY));
}
if (pUserData && !pUserData->sTooltip.isEmpty())
{
if (pUserData->bIsReadOnly)
ret.append("\n\n");
ret.append(pUserData->sTooltip);
}
return ret.makeStringAndClear();
}
IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void)
{
if (!m_bSorted)
{
m_xPrefBox->make_sorted();
m_bSorted = true;
}
bool bSortAtoZ = m_xPrefBox->get_sort_order();
//set new arrow positions in headerbar
if (nColumn == m_xPrefBox->get_sort_column())
{
bSortAtoZ = !bSortAtoZ;
m_xPrefBox->set_sort_order(bSortAtoZ);
}
else
{
int nOldSortColumn = m_xPrefBox->get_sort_column();
if (nOldSortColumn != -1)
m_xPrefBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
m_xPrefBox->set_sort_column(nColumn);
}
if (nColumn != -1)
{
//sort lists
m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
}
}
IMPL_STATIC_LINK_NOARG(CuiAboutConfigTabPage, ValidNameHdl, SvxNameDialog&, bool)
{
// Allow empty value
return true;
}
CuiAboutConfigTabPage::~CuiAboutConfigTabPage() {}
void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, Any aPropertyValue,
const OUString& rProp, const OUString& rStatus,
const OUString& rType, const OUString& rValue,
const OUString& rTooltip,
const weld::TreeIter* pParentEntry, bool bInsertToPrefBox,
bool bIsReadOnly, bool bWasModified)
{
bool bOnlyModified = m_xModifiedCheckBtn->get_active();
if (bOnlyModified && !bWasModified)
return;
m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, aPropertyValue, rTooltip,
bIsReadOnly, bWasModified));
if (bInsertToPrefBox)
{
OUString sId(weld::toId(m_vectorUserData.back().get()));
m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, false,
m_xScratchIter.get());
m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1);
m_xPrefBox->set_text(*m_xScratchIter, rType, 2);
m_xPrefBox->set_text(*m_xScratchIter, rValue, 3);
m_xPrefBox->set_text_emphasis(*m_xScratchIter, bWasModified, -1);
m_xPrefBox->set_sensitive(*m_xScratchIter, !bIsReadOnly, -1);
}
else
{
m_prefBoxEntries.push_back(
{ rProp, rStatus, rType, rValue, m_vectorUserData.back().get() });
}
}
void CuiAboutConfigTabPage::InputChanged()
{
weld::WaitObject aWait(m_xDialog.get());
m_xPrefBox->hide();
m_xPrefBox->clear();
m_xPrefBox->freeze();
if (m_bSorted)
m_xPrefBox->make_unsorted();
if (m_xSearchEdit->get_text().isEmpty())
{
m_xPrefBox->clear();
Reference<XNameAccess> xConfigAccess = getConfigAccess(u"/"_ustr, false);
FillItems(xConfigAccess);
}
else
{
m_options.searchString = m_xSearchEdit->get_text();
utl::TextSearch textSearch(m_options);
for (auto const& it : m_prefBoxEntries)
{
sal_Int32 endPos, startPos = 0;
for (size_t i = 0; i < 5; ++i)
{
OUString scrTxt;
if (i == 0)
scrTxt = it.pUserData->sPropertyPath;
else if (i == 1)
scrTxt = it.sProp;
else if (i == 2)
scrTxt = it.sStatus;
else if (i == 3)
scrTxt = it.sType;
else if (i == 4)
scrTxt = it.sValue;
endPos = scrTxt.getLength();
if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
{
InsertEntry(it);
break;
}
}
}
}
m_xPrefBox->thaw();
if (m_bSorted)
m_xPrefBox->make_sorted();
m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
m_xPrefBox->expand_row(rEntry);
return false;
});
m_xPrefBox->show();
}
void CuiAboutConfigTabPage::Reset()
{
weld::WaitObject aWait(m_xDialog.get());
m_xPrefBox->clear();
m_vectorOfModified.clear();
if (m_bSorted)
{
m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
m_xPrefBox->make_unsorted();
m_bSorted = false;
}
m_prefBoxEntries.clear();
m_modifiedPrefBoxEntries.clear();
m_xPrefBox->freeze();
Reference<XNameAccess> xConfigAccess = getConfigAccess(u"/"_ustr, false);
//Load all XNameAccess to m_prefBoxEntries
FillItems(xConfigAccess, nullptr, 0, true);
//Load xConfigAccess' children to m_prefBox
FillItems(xConfigAccess);
m_xPrefBox->thaw();
}
void CuiAboutConfigTabPage::FillItemSet()
{
std::vector<std::shared_ptr<Prop_Impl>>::iterator pIter;
for (pIter = m_vectorOfModified.begin(); pIter != m_vectorOfModified.end(); ++pIter)
{
Reference<XNameAccess> xUpdateAccess = getConfigAccess((*pIter)->Name, true);
Reference<XNameReplace> xNameReplace(xUpdateAccess, UNO_QUERY_THROW);
xNameReplace->replaceByName((*pIter)->Property, (*pIter)->Value);
Reference<util::XChangesBatch> xChangesBatch(xUpdateAccess, UNO_QUERY_THROW);
xChangesBatch->commitChanges();
}
}
namespace
{
OUString lcl_StringListToString(const uno::Sequence<OUString>& seq)
{
OUStringBuffer sBuffer;
for (sal_Int32 i = 0; i != seq.getLength(); ++i)
{
if (i != 0)
sBuffer.append(",");
sBuffer.append(seq[i]);
}
return sBuffer.makeStringAndClear();
}
OUString lcl_IntListToString(const uno::Sequence<sal_Int16>& seq)
{
OUStringBuffer sBuffer;
for (sal_Int32 i = 0; i != seq.getLength(); ++i)
{
if (i != 0)
sBuffer.append(",");
sBuffer.append(OUString::number(seq[i]));
}
return sBuffer.makeStringAndClear();
}
OUString lcl_IntListToString(const uno::Sequence<sal_Int32>& seq)
{
OUStringBuffer sBuffer;
for (sal_Int32 i = 0; i != seq.getLength(); ++i)
{
if (i != 0)
sBuffer.append(",");
sBuffer.append(OUString::number(seq[i]));
}
return sBuffer.makeStringAndClear();
}
OUString lcl_IntListToString(const uno::Sequence<sal_Int64>& seq)
{
OUStringBuffer sBuffer;
for (sal_Int32 i = 0; i != seq.getLength(); ++i)
{
if (i != 0)
sBuffer.append(",");
sBuffer.append(OUString::number(seq[i]));
}
return sBuffer.makeStringAndClear();
}
OUString lcl_DoubleListToString(const uno::Sequence<double>& seq)
{
OUStringBuffer sBuffer;
for (sal_Int32 i = 0; i != seq.getLength(); ++i)
{
if (i != 0)
sBuffer.append(",");
sBuffer.append(OUString::number(seq[i]));
}
return sBuffer.makeStringAndClear();
}
}
void CuiAboutConfigTabPage::FillItems(const Reference<XNameAccess>& xNameAccess,
const weld::TreeIter* pParentEntry, int lineage,
bool bLoadAll)
{
OUString sPath
= Reference<XHierarchicalName>(xNameAccess, uno::UNO_QUERY_THROW)->getHierarchicalName();
const uno::Sequence<OUString> seqItems = xNameAccess->getElementNames();
for (const OUString& item : seqItems)
{
Any aNode = xNameAccess->getByName(item);
bool bNotLeaf = false;
Reference<XNameAccess> xNextNameAccess;
try
{
xNextNameAccess.set(aNode, uno::UNO_QUERY);
bNotLeaf = xNextNameAccess.is();
}
catch (const RuntimeException&)
{
TOOLS_WARN_EXCEPTION("cui.options", "CuiAboutConfigTabPage");
}
if (bNotLeaf)
{
if (bLoadAll)
FillItems(xNextNameAccess, nullptr, lineage + 1, true);
else
{
// not leaf node
m_vectorUserData.push_back(
std::make_unique<UserData>(xNextNameAccess, lineage + 1));
OUString sId(weld::toId(m_vectorUserData.back().get()));
m_xPrefBox->insert(pParentEntry, -1, &item, &sId, nullptr, nullptr, true,
m_xScratchIter.get());
// Necessary, without this the selection line will be truncated.
m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 1);
m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 2);
m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 3);
m_xPrefBox->set_text_emphasis(*m_xScratchIter, false, -1);
m_xPrefBox->set_sensitive(*m_xScratchIter, true);
}
}
else
{
// leaf node
OUString sPropertyName = item;
auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
[&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
return rEntry.pUserData->sPropertyPath == sPath
&& rEntry.sStatus == sPropertyName;
});
css::uno::Reference<css::configuration::XReadWriteAccess> m_xReadWriteAccess;
m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(
::comphelper::getProcessComponentContext(), u"*"_ustr);
beans::Property aProperty;
bool bReadOnly = false;
OUString sFullPath(sPath + "/" + sPropertyName);
try
{
aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(sFullPath);
bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0;
}
catch (css::beans::UnknownPropertyException)
{
SAL_WARN("cui.options", "unknown property: " << sFullPath);
}
OUString sTooltip;
OUString sType;
bool bWasModified = false;
css::uno::Type aType = cppu::UnoType<void>::get();
OUString sDynamicType = aNode.getValueTypeName();
try
{
Reference<configuration::XDocumentation> xDocumentation(xNameAccess,
UNO_QUERY_THROW);
sTooltip
= xDocumentation->getDescriptionByHierarchicalName(sPath + "/" + sPropertyName);
aType = xDocumentation->getTypeByHierarchicalName(sFullPath);
bWasModified = xDocumentation->getModifiedByHierarchicalName(sFullPath);
}
catch (css::container::NoSuchElementException)
{
}
catch (css::util::InvalidStateException)
{
}
OUStringBuffer sValue;
// Fall back to dynamic type when this is empty
if (aType == cppu::UnoType<void>::get() && sDynamicType != "void")
{
if (sDynamicType == "boolean")
aType = cppu::UnoType<sal_Bool>::get();
else if (sDynamicType == "short")
aType = cppu::UnoType<sal_Int16>::get();
else if (sDynamicType == "long")
aType = cppu::UnoType<sal_Int32>::get();
else if (sDynamicType == "hyper")
aType = cppu::UnoType<sal_Int64>::get();
else if (sDynamicType == "double")
aType = cppu::UnoType<double>::get();
else if (sDynamicType == "string")
aType = cppu::UnoType<OUString>::get();
else if (sDynamicType == "[]byte")
aType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get();
else if (sDynamicType == "[]boolean")
aType = cppu::UnoType<css::uno::Sequence<sal_Bool>>::get();
else if (sDynamicType == "[]short")
aType = cppu::UnoType<css::uno::Sequence<sal_Int16>>::get();
else if (sDynamicType == "[]long")
aType = cppu::UnoType<css::uno::Sequence<sal_Int32>>::get();
else if (sDynamicType == "[]hyper")
aType = cppu::UnoType<css::uno::Sequence<sal_Int64>>::get();
else if (sDynamicType == "[]double")
aType = cppu::UnoType<css::uno::Sequence<double>>::get();
else if (sDynamicType == "[]string")
aType = cppu::UnoType<css::uno::Sequence<OUString>>::get();
else if (sDynamicType == "[][]byte")
aType = cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get();
}
if (it != m_modifiedPrefBoxEntries.end())
sValue = it->sValue;
else
{
bool bHasValue = sDynamicType != "void";
if (aType == cppu::UnoType<sal_Bool>::get())
{
if (bHasValue)
sValue = OUString::boolean(aNode.get<bool>());
sType = "boolean";
}
else if (aType == cppu::UnoType<sal_Int16>::get())
{
if (bHasValue)
sValue = OUString::number(aNode.get<sal_Int16>());
sType = "short";
}
else if (aType == cppu::UnoType<sal_Int32>::get())
{
if (bHasValue)
sValue = OUString::number(aNode.get<sal_Int32>());
sType = "int";
}
else if (aType == cppu::UnoType<sal_Int64>::get())
{
if (bHasValue)
sValue = OUString::number(aNode.get<sal_Int64>());
sType = "long";
}
else if (aType == cppu::UnoType<double>::get())
{
if (bHasValue)
sValue = OUString::number(aNode.get<double>());
sType = "double";
}
else if (aType == cppu::UnoType<OUString>::get())
{
if (bHasValue)
sValue = aNode.get<OUString>();
sType = "string";
}
else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int8>>::get())
{
if (bHasValue)
{
const uno::Sequence<sal_Int8> seq = aNode.get<uno::Sequence<sal_Int8>>();
for (sal_Int8 j : seq)
{
OUString s = OUString::number(static_cast<sal_uInt8>(j), 16);
if (s.getLength() == 1)
{
sValue.append("0");
}
sValue.append(s.toAsciiUpperCase());
}
}
sType = "hexBinary";
}
else if (aType == cppu::UnoType<css::uno::Sequence<sal_Bool>>::get())
{
if (bHasValue)
{
uno::Sequence<sal_Bool> seq = aNode.get<uno::Sequence<sal_Bool>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
sValue.append(OUString::boolean(seq[j]));
}
}
sType = "boolean-list";
}
else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int16>>::get())
{
if (bHasValue)
{
uno::Sequence<sal_Int16> seq = aNode.get<uno::Sequence<sal_Int16>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
sValue.append(static_cast<sal_Int32>(seq[j]));
}
}
sType = "short-list";
}
else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int32>>::get())
{
if (bHasValue)
{
uno::Sequence<sal_Int32> seq = aNode.get<uno::Sequence<sal_Int32>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
sValue.append(seq[j]);
}
}
sType = "int-list";
}
else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int64>>::get())
{
if (bHasValue)
{
uno::Sequence<sal_Int64> seq = aNode.get<uno::Sequence<sal_Int64>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
sValue.append(seq[j]);
}
}
sType = "long-list";
}
else if (aType == cppu::UnoType<css::uno::Sequence<double>>::get())
{
if (bHasValue)
{
uno::Sequence<double> seq = aNode.get<uno::Sequence<double>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
sValue.append(seq[j]);
}
}
sType = "double-list";
}
else if (aType == cppu::UnoType<css::uno::Sequence<OUString>>::get())
{
if (bHasValue)
sValue = lcl_StringListToString(aNode.get<uno::Sequence<OUString>>());
sType = "string-list";
}
else if (aType
== cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get())
{
if (bHasValue)
{
const uno::Sequence<uno::Sequence<sal_Int8>> seq
= aNode.get<uno::Sequence<uno::Sequence<sal_Int8>>>();
for (sal_Int32 j = 0; j != seq.getLength(); ++j)
{
if (j != 0)
{
sValue.append(",");
}
for (sal_Int8 k : seq[j])
{
OUString s = OUString::number(static_cast<sal_uInt8>(k), 16);
if (s.getLength() == 1)
{
sValue.append("0");
}
sValue.append(s.toAsciiUpperCase());
}
}
}
sType = "hexBinary-list";
}
else
{
SAL_INFO("cui.options", "path \"" << sPath << "\" member " << item
<< " of unsupported type " << sType);
continue;
}
}
//Short name
int index = 0;
for (int j = 1; j < lineage; ++j)
index = sPath.indexOf("/", index + 1);
InsertEntry(sPath, aNode, sPath.copy(index + 1), item, sType,
sValue.makeStringAndClear(), sTooltip, pParentEntry, !bLoadAll, bReadOnly,
bWasModified);
}
}
}
Reference<XNameAccess> CuiAboutConfigTabPage::getConfigAccess(const OUString& sNodePath,
bool bUpdate)
{
const uno::Reference<uno::XComponentContext>& xContext(
::comphelper::getProcessComponentContext());
uno::Reference<lang::XMultiServiceFactory> xConfigProvider(
css::configuration::theDefaultProvider::get(xContext));
beans::NamedValue aProperty;
aProperty.Name = "nodepath";
aProperty.Value <<= sNodePath;
uno::Sequence<uno::Any> aArgumentList{ uno::Any(aProperty) };
OUString sAccessString;
if (bUpdate)
sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
else
sAccessString = "com.sun.star.configuration.ConfigurationAccess";
uno::Reference<container::XNameAccess> xNameAccess(
xConfigProvider->createInstanceWithArguments(sAccessString, aArgumentList),
uno::UNO_QUERY_THROW);
return xNameAccess;
}
void CuiAboutConfigTabPage::AddToModifiedVector(const std::shared_ptr<Prop_Impl>& rProp)
{
bool isModifiedBefore = false;
//Check if value modified before
for (std::shared_ptr<Prop_Impl>& nInd : m_vectorOfModified)
{
if (rProp->Name == nInd->Name && rProp->Property == nInd->Property)
{
//property modified before. Assign reference to the modified value
//do your changes on this object. They will be saved later.
nInd = rProp;
isModifiedBefore = true;
break;
}
}
if (!isModifiedBefore)
m_vectorOfModified.push_back(rProp);
//property is not modified before
}
std::vector<OUString>
CuiAboutConfigTabPage::commaStringToSequence(std::u16string_view rCommaSepString)
{
std::vector<OUString> tempVector;
sal_Int32 index = 0;
do
{
OUString word(o3tl::getToken(rCommaSepString, 0, u',', index));
word = word.trim();
if (!word.isEmpty())
tempVector.push_back(word);
} while (index >= 0);
return tempVector;
}
IMPL_LINK_NOARG(CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void) { Reset(); }
IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool)
{
StandardHdl_Impl(*m_xEditBtn);
return true;
}
IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void)
{
if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
return;
UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(*m_xScratchIter));
if (!pUserData || !pUserData->bIsPropertyPath || pUserData->bIsReadOnly)
return;
//if selection is a node
OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1);
OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2);
OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3);
auto pProperty
= std::make_shared<Prop_Impl>(pUserData->sPropertyPath, sPropertyName, Any(sPropertyValue));
bool bSaveChanges = false;
bool bOpenDialog = true;
OUString sDialogValue;
if (sPropertyType == "boolean")
{
bool bValue;
if (sPropertyValue == "true")
{
sDialogValue = "false";
bValue = false;
}
else
{
sDialogValue = "true";
bValue = true;
}
pProperty->Value <<= bValue;
bOpenDialog = false;
bSaveChanges = true;
}
else
{
sDialogValue = sPropertyValue;
bOpenDialog = true;
}
try
{
if (bOpenDialog)
{
if (sPropertyType == "short" || sPropertyType == "int" || sPropertyType == "long")
{
sal_Int64 nMin = sPropertyType == "short"
? SAL_MIN_INT16
: sPropertyType == "int" ? SAL_MIN_INT32 : SAL_MIN_INT64;
sal_Int64 nMax = sPropertyType == "short"
? SAL_MAX_INT16
: sPropertyType == "int" ? SAL_MAX_INT32 : SAL_MAX_INT64;
SvxNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName,
sDialogValue.toInt64(), nMin, nMax);
if (aNumberDialog.run() == RET_OK)
{
sal_Int64 nNewValue = aNumberDialog.GetNumber();
if (sPropertyType == "short")
{
pProperty->Value <<= static_cast<sal_Int16>(nNewValue);
}
else if (sPropertyType == "int")
{
pProperty->Value <<= static_cast<sal_Int32>(nNewValue);
}
else if (sPropertyType == "long")
{
pProperty->Value <<= nNewValue;
}
bSaveChanges = true;
sDialogValue = OUString::number(nNewValue);
}
}
else if (sPropertyType == "double")
{
SvxDecimalNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName,
sDialogValue.toDouble());
if (aNumberDialog.run() == RET_OK)
{
double fNewValue = aNumberDialog.GetNumber();
pProperty->Value <<= fNewValue;
bSaveChanges = true;
sDialogValue = OUString::number(fNewValue);
}
}
else if (sPropertyType == "string")
{
SvxNameDialog aNameDialog(m_xDialog.get(), sDialogValue, sPropertyName);
aNameDialog.SetCheckNameHdl(LINK(this, CuiAboutConfigTabPage, ValidNameHdl));
if (aNameDialog.run() == RET_OK)
{
sDialogValue = aNameDialog.GetName();
pProperty->Value <<= sDialogValue;
bSaveChanges = true;
}
}
else if (sPropertyType == "short-list")
{
SvxListDialog aListDialog(m_xDialog.get());
aListDialog.SetEntries(commaStringToSequence(sDialogValue));
aListDialog.SetMode(ListMode::Int16);
if (aListDialog.run() == RET_OK)
{
std::vector<OUString> seqStr = aListDialog.GetEntries();
uno::Sequence<sal_Int16> seqShort(seqStr.size());
std::transform(
seqStr.begin(), seqStr.end(), seqShort.getArray(),
[](const auto& str) { return static_cast<sal_Int16>(str.toInt32()); });
pProperty->Value <<= seqShort;
sDialogValue = lcl_IntListToString(seqShort);
bSaveChanges = true;
}
}
else if (sPropertyType == "int-list")
{
SvxListDialog aListDialog(m_xDialog.get());
aListDialog.SetEntries(commaStringToSequence(sDialogValue));
aListDialog.SetMode(ListMode::Int32);
if (aListDialog.run() == RET_OK)
{
std::vector<OUString> seqStr = aListDialog.GetEntries();
uno::Sequence<sal_Int32> seq(seqStr.size());
std::transform(
seqStr.begin(), seqStr.end(), seq.getArray(),
[](const auto& str) { return static_cast<sal_Int32>(str.toInt32()); });
pProperty->Value <<= seq;
sDialogValue = lcl_IntListToString(seq);
bSaveChanges = true;
}
}
else if (sPropertyType == "long-list")
{
SvxListDialog aListDialog(m_xDialog.get());
aListDialog.SetEntries(commaStringToSequence(sDialogValue));
aListDialog.SetMode(ListMode::Int64);
if (aListDialog.run() == RET_OK)
{
std::vector<OUString> seqStr = aListDialog.GetEntries();
uno::Sequence<sal_Int64> seq(seqStr.size());
std::transform(
seqStr.begin(), seqStr.end(), seq.getArray(),
[](const auto& str) { return static_cast<sal_Int64>(str.toInt32()); });
pProperty->Value <<= seq;
sDialogValue = lcl_IntListToString(seq);
bSaveChanges = true;
}
}
else if (sPropertyType == "double-list")
{
SvxListDialog aListDialog(m_xDialog.get());
aListDialog.SetEntries(commaStringToSequence(sDialogValue));
aListDialog.SetMode(ListMode::Double);
if (aListDialog.run() == RET_OK)
{
std::vector<OUString> seqStr = aListDialog.GetEntries();
uno::Sequence<double> seq(seqStr.size());
std::transform(
seqStr.begin(), seqStr.end(), seq.getArray(),
[](const auto& str) { return static_cast<double>(str.toDouble()); });
pProperty->Value <<= seq;
sDialogValue = lcl_DoubleListToString(seq);
bSaveChanges = true;
}
}
else if (sPropertyType == "string-list")
{
SvxListDialog aListDialog(m_xDialog.get());
uno::Sequence<OUString> aList
= pUserData->aPropertyValue.get<uno::Sequence<OUString>>();
aListDialog.SetEntries(
comphelper::sequenceToContainer<std::vector<OUString>>(aList));
aListDialog.SetMode(ListMode::String);
if (aListDialog.run() == RET_OK)
{
auto seq = comphelper::containerToSequence(aListDialog.GetEntries());
sDialogValue = lcl_StringListToString(seq);
pProperty->Value <<= seq;
bSaveChanges = true;
}
}
else //unknown
throw uno::Exception("unknown property type " + sPropertyType, nullptr);
}
if (bSaveChanges)
{
AddToModifiedVector(pProperty);
pUserData->aPropertyValue = pProperty->Value;
//update listbox value.
m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2);
m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
m_xPrefBox->set_text_emphasis(*m_xScratchIter, true, -1);
//update m_prefBoxEntries
auto it = std::find_if(
m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
[&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
&& rEntry.sStatus == sPropertyName;
});
if (it != m_prefBoxEntries.end())
{
it->sValue = sDialogValue;
it->pUserData->bWasModified = true;
auto modifiedIt = std::find_if(
m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
[&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
&& rEntry.sStatus == sPropertyName;
});
if (modifiedIt != m_modifiedPrefBoxEntries.end())
{
modifiedIt->sValue = sDialogValue;
modifiedIt->pUserData->bWasModified = true;
}
else
{
m_modifiedPrefBoxEntries.push_back(*it);
}
}
}
}
catch (uno::Exception&)
{
}
}
IMPL_LINK_NOARG(CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) { InputChanged(); }
IMPL_LINK_NOARG(CuiAboutConfigTabPage, ModifiedHdl_Impl, weld::Toggleable&, void)
{
InputChanged();
}
void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry)
{
bool bOnlyModified = m_xModifiedCheckBtn->get_active();
if (bOnlyModified && !rEntry.pUserData->bWasModified)
return;
OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
OUString sPath = sPathWithProperty.copy(0, index);
index = 0;
std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator());
std::unique_ptr<weld::TreeIter> xGrandParentEntry;
do
{
int prevIndex = index;
index = sPath.indexOf("/", index + 1);
// deal with no parent case (tdf#107811)
if (index < 0)
{
OUString sId(weld::toId(rEntry.pUserData));
m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, false,
m_xScratchIter.get());
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1);
m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
return;
}
OUString sParentName = sPath.copy(prevIndex + 1, index - prevIndex - 1);
bool hasEntry = false;
bool bStartOk;
if (!xGrandParentEntry)
bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
else
{
m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
bStartOk = m_xPrefBox->iter_children(*xParentEntry);
}
if (bStartOk)
{
do
{
if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
{
hasEntry = true;
break;
}
} while (m_xPrefBox->iter_next_sibling(*xParentEntry));
}
if (!hasEntry)
{
m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr,
false, xParentEntry.get());
//It is needed, without this the selection line will be truncated.
m_xPrefBox->set_text(*xParentEntry, u""_ustr, 1);
m_xPrefBox->set_text(*xParentEntry, u""_ustr, 2);
m_xPrefBox->set_text(*xParentEntry, u""_ustr, 3);
m_xPrefBox->set_text_emphasis(*xParentEntry, false, -1);
m_xPrefBox->set_sensitive(*xParentEntry, true);
}
xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
} while (index < sPath.getLength() - 1);
OUString sId(weld::toId(rEntry.pUserData));
m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, false,
m_xScratchIter.get());
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1);
m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
}
IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
{
if (m_xPrefBox->iter_has_child(rEntry))
return true;
UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rEntry));
if (pUserData && !pUserData->bIsPropertyPath)
{
assert(pUserData->aXNameAccess.is());
FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
}
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V1048 The 'bOpenDialog' variable was assigned the same value.