diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /cui/source/options/optaboutconfig.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'cui/source/options/optaboutconfig.cxx')
-rw-r--r-- | cui/source/options/optaboutconfig.cxx | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/cui/source/options/optaboutconfig.cxx b/cui/source/options/optaboutconfig.cxx new file mode 100644 index 0000000000..f927363f86 --- /dev/null +++ b/cui/source/options/optaboutconfig.cxx @@ -0,0 +1,1109 @@ +/* -*- 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, "cui/ui/aboutconfigdialog.ui", "AboutConfig") + , m_xResetBtn(m_xBuilder->weld_button("reset")) + , m_xEditBtn(m_xBuilder->weld_button("edit")) + , m_xSearchBtn(m_xBuilder->weld_button("searchButton")) + , m_xModifiedCheckBtn(m_xBuilder->weld_check_button("modifiedButton")) + , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry")) + , m_xPrefBox(m_xBuilder->weld_tree_view("preferences")) + , m_xScratchIter(m_xPrefBox->make_iterator()) + , m_bSorted(false) + , m_pParent(pParent) +{ + 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("/", 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("/", 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, "", 1); + m_xPrefBox->set_text(*m_xScratchIter, "", 2); + m_xPrefBox->set_text(*m_xScratchIter, "", 3); + 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(), "*"); + 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) +{ + 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, "", 1); + m_xPrefBox->set_text(*xParentEntry, "", 2); + m_xPrefBox->set_text(*xParentEntry, "", 3); + 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: */ |