diff options
Diffstat (limited to 'cui/source/options/optaboutconfig.cxx')
-rw-r--r-- | cui/source/options/optaboutconfig.cxx | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/cui/source/options/optaboutconfig.cxx b/cui/source/options/optaboutconfig.cxx new file mode 100644 index 000000000..c4dafaf5c --- /dev/null +++ b/cui/source/options/optaboutconfig.cxx @@ -0,0 +1,965 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> +#include "optaboutconfig.hxx" + +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/container/XHierarchicalName.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/XChangesBatch.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <cppu/unotype.hxx> +#include <rtl/ustrbuf.hxx> +#include <unotools/textsearch.hxx> +#include <utility> +#include <vcl/event.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <algorithm> +#include <memory> +#include <vector> + +using namespace ::com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::container; + +#define SHORT_LEN_LIMIT 7 +#define LONG_LEN_LIMIT 11 +#define HYPER_LEN_LIMIT 20 + +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; + OUString sPropertyPath; + int aLineage; + Reference<XNameAccess> aXNameAccess; + + explicit UserData( OUString aPropertyPath ) + : bIsPropertyPath( true ) + , sPropertyPath(std::move(aPropertyPath)) + , aLineage(0) + {} + + explicit UserData( Reference<XNameAccess> const & rXNameAccess, int rIndex ) + : bIsPropertyPath( false ) + , aLineage(rIndex) + , aXNameAccess( rXNameAccess ) + {} +}; + +IMPL_LINK(CuiAboutConfigValueDialog, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) +{ + bool bValid = false; + bool bNonSpace = rKeyEvent.GetKeyCode().GetCode() != KEY_SPACE; + if (m_bNumericOnly && bNonSpace ) + { + const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode(); + sal_uInt16 nGroup = rKeyCode.GetGroup(); + sal_uInt16 nKey = rKeyCode.GetCode(); + + switch ( nGroup ) { + case KEYGROUP_NUM : + case KEYGROUP_CURSOR : + { + bValid = true; + break; + } + + case KEYGROUP_MISC : + { + switch ( nKey ) { + case KEY_SUBTRACT : + case KEY_COMMA : + case KEY_POINT : + { + bValid = true; + break; + } + + default : + { + if( nKey < KEY_ADD || nKey > KEY_EQUAL ) + bValid = true; + break; + } + } + break; + } + + default : + { + bValid = false; + break; + } + } + + //Select all, Copy, Paste, Cut, Undo Keys + if ( !bValid && ( rKeyCode.IsMod1() && ( + KEY_A == nKey || KEY_C == nKey || KEY_V == nKey || KEY_X == nKey || KEY_Z == nKey ) ) ) + bValid = true; + } + else + bValid = true; + + //if value return true to claim that it has been handled + return !bValid; +} + +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_xSearchEdit(m_xBuilder->weld_entry("searchEntry")) + , m_xPrefBox(m_xBuilder->weld_tree_view("preferences")) + , 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_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); +} + +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); + } +} + +CuiAboutConfigTabPage::~CuiAboutConfigTabPage() +{ +} + +void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, const OUString& rProp, const OUString& rStatus, + const OUString& rType, const OUString& rValue, const weld::TreeIter* pParentEntry, + bool bInsertToPrefBox) +{ + m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath)); + 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); + } + else + { + m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()}); + } +} + +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(); + } +} + +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); + } + } + 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; + } + ); + + OUString sType = aNode.getValueTypeName(); + OUStringBuffer sValue; + + if (it != m_modifiedPrefBoxEntries.end()) + sValue = it->sValue; + else + { + switch( aNode.getValueType().getTypeClass() ) + { + case css::uno::TypeClass_VOID: + break; + + case css::uno::TypeClass_BOOLEAN: + sValue = OUString::boolean( aNode.get<bool>() ); + break; + + case css::uno::TypeClass_SHORT: + case css::uno::TypeClass_LONG: + case css::uno::TypeClass_HYPER: + sValue = OUString::number( aNode.get<sal_Int64>() ); + break; + + case css::uno::TypeClass_DOUBLE: + sValue = OUString::number( aNode.get<double>() ); + break; + + case css::uno::TypeClass_STRING: + sValue = aNode.get<OUString>(); + break; + + case css::uno::TypeClass_SEQUENCE: + if( sType == "[]boolean" ) + { + 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] )); + } + } + else if( sType == "[]byte" ) + { + 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()); + } + } + else if( sType == "[][]byte" ) + { + 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()); + } + } + } + else if( sType == "[]short" ) + { + 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]) ); + } + } + else if( sType == "[]long" ) + { + 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] ); + } + } + else if( sType == "[]hyper" ) + { + 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] ); + } + } + else if( sType == "[]double" ) + { + 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] ); + } + } + else if( sType == "[]string" ) + { + uno::Sequence<OUString> seq = aNode.get< uno::Sequence<OUString> >(); + for( sal_Int32 j = 0; j != seq.getLength(); ++j ) + { + if( j != 0 ) + { + sValue.append(","); + } + sValue.append(seq[j]); + } + } + else + { + SAL_WARN( + "cui.options", + "path \"" << sPath << "\" member " << item + << " of unsupported type " << sType); + } + break; + + default: + SAL_WARN( + "cui.options", + "path \"" << sPath << "\" member " << item + << " of unsupported type " << sType); + break; + } + } + + //Short name + int index = 0; + for(int j = 1; j < lineage; ++j) + index = sPath.indexOf("/", index + 1); + + InsertEntry(sPath, sPath.copy(index+1), item, sType, sValue.makeStringAndClear(), pParentEntry, !bLoadAll); + } + } +} + +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; +} + +CuiAboutConfigValueDialog::CuiAboutConfigValueDialog(weld::Window* pWindow, + const OUString& rValue, + int limit) + : GenericDialogController(pWindow, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog") + , m_bNumericOnly(limit != 0) + , m_xEDValue(m_xBuilder->weld_entry("valuebox")) +{ + if (limit) + m_xEDValue->set_max_length(limit); + m_xEDValue->set_text(rValue); + m_xEDValue->connect_key_press(LINK(this, CuiAboutConfigValueDialog, KeyInputHdl)); +} + +CuiAboutConfigValueDialog::~CuiAboutConfigValueDialog() +{ +} + +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)) + 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); + + // If the configuration property has a nil value, determine its static type: + if (sPropertyType == "void") + { + css::uno::Reference<css::beans::XPropertySetInfo> info( + CuiAboutConfigTabPage::getConfigAccess(pUserData->sPropertyPath, false), + css::uno::UNO_QUERY_THROW); + css::uno::Type t; + try { + t = info->getPropertyByName(sPropertyName).Type; + } catch (css::beans::UnknownPropertyException &) { + TOOLS_WARN_EXCEPTION("cui.options", pUserData->sPropertyPath << " " << sPropertyName); + } + // If the configuration property is of type any (or an UnknownPropertyException was caught + // above), stick to "void" for now (ideally, properties of type any would allow setting + // values of arbitrary type, regardless of their current value, in this dialog anyway): + if (t != cppu::UnoType<void>::get()) { + sPropertyType = t.getTypeName(); + switch (t.getTypeClass()) { + case css::uno::TypeClass_BOOLEAN: + sPropertyValue = "false"; + break; + case css::uno::TypeClass_SHORT: + case css::uno::TypeClass_LONG: + case css::uno::TypeClass_HYPER: + case css::uno::TypeClass_DOUBLE: + sPropertyValue = "0"; + break; + default: + break; + } + } + } + + 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 if ( sPropertyType == "void" ) + { + bOpenDialog = false; + } + else + { + sDialogValue = sPropertyValue; + bOpenDialog = true; + } + + try + { + if( bOpenDialog ) + { + //Cosmetic length limit for integer values. + int limit=0; + if( sPropertyType == "short" ) + limit = SHORT_LEN_LIMIT; + else if( sPropertyType == "long" ) + limit = LONG_LEN_LIMIT; + else if( sPropertyType == "hyper" ) + limit = HYPER_LEN_LIMIT; + + CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit); + + if (aValueDialog.run() == RET_OK ) + { + OUString sNewValue = aValueDialog.getValue(); + bSaveChanges = true; + if ( sPropertyType == "short") + { + sal_Int16 nShort; + sal_Int32 nNumb = sNewValue.toInt32(); + + //if the value is 0 and length is not 1, there is something wrong + if( ( nNumb==0 && sNewValue.getLength()!=1 ) || nNumb > SAL_MAX_INT16 || nNumb < SAL_MIN_INT16) + throw uno::Exception("out of range short", nullptr); + nShort = static_cast<sal_Int16>(nNumb); + pProperty->Value <<= nShort; + } + else if( sPropertyType == "long" ) + { + sal_Int32 nLong = sNewValue.toInt32(); + if( nLong==0 && sNewValue.getLength()!=1) + throw uno::Exception("out of range long", nullptr); + pProperty->Value <<= nLong; + } + else if( sPropertyType == "hyper") + { + sal_Int64 nHyper = sNewValue.toInt64(); + if( nHyper==0 && sNewValue.getLength()!=1) + throw uno::Exception("out of range hyper", nullptr); + pProperty->Value <<= nHyper; + } + else if( sPropertyType == "double") + { + double nDoub = sNewValue.toDouble(); + if( nDoub ==0 && sNewValue.getLength()!=1) + throw uno::Exception("out of range double", nullptr); + pProperty->Value <<= nDoub; + } + else if( sPropertyType == "float") + { + float nFloat = sNewValue.toFloat(); + if( nFloat ==0 && sNewValue.getLength()!=1) + throw uno::Exception("out of range float", nullptr); + pProperty->Value <<= nFloat; + } + else if( sPropertyType == "string" ) + { + pProperty->Value <<= sNewValue; + } + else if( sPropertyType == "[]short" ) + { + //create string sequence from comma separated string + //uno::Sequence< OUString > seqStr; + std::vector< OUString > seqStr = commaStringToSequence( sNewValue ); + + //create appropriate sequence with same size as string sequence + uno::Sequence< sal_Int16 > seqShort( seqStr.size() ); + //convert all strings to appropriate type + std::transform(seqStr.begin(), seqStr.end(), seqShort.getArray(), + [](const auto& str) + { return static_cast<sal_Int16>(str.toInt32()); }); + pProperty->Value <<= seqShort; + } + else if( sPropertyType == "[]long" ) + { + std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue ); + + uno::Sequence< sal_Int32 > seqLong( seqStrLong.size() ); + std::transform(seqStrLong.begin(), seqStrLong.end(), seqLong.getArray(), + [](const auto& str) { return str.toInt32(); }); + pProperty->Value <<= seqLong; + } + else if( sPropertyType == "[]hyper" ) + { + std::vector< OUString > seqStrHyper = commaStringToSequence( sNewValue ); + uno::Sequence< sal_Int64 > seqHyper( seqStrHyper.size() ); + std::transform(seqStrHyper.begin(), seqStrHyper.end(), seqHyper.getArray(), + [](const auto& str) { return str.toInt64(); }); + pProperty->Value <<= seqHyper; + } + else if( sPropertyType == "[]double" ) + { + std::vector< OUString > seqStrDoub = commaStringToSequence( sNewValue ); + uno::Sequence< double > seqDoub( seqStrDoub.size() ); + std::transform(seqStrDoub.begin(), seqStrDoub.end(), seqDoub.getArray(), + [](const auto& str) { return str.toDouble(); }); + pProperty->Value <<= seqDoub; + } + else if( sPropertyType == "[]float" ) + { + std::vector< OUString > seqStrFloat = commaStringToSequence( sNewValue ); + uno::Sequence< sal_Int16 > seqFloat( seqStrFloat.size() ); + std::transform(seqStrFloat.begin(), seqStrFloat.end(), seqFloat.getArray(), + [](const auto& str) { return str.toFloat(); }); + pProperty->Value <<= seqFloat; + } + else if( sPropertyType == "[]string" ) + { + pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue )); + } + else //unknown + throw uno::Exception("unknown property type " + sPropertyType, nullptr); + + sDialogValue = sNewValue; + } + } + + if(bSaveChanges) + { + AddToModifiedVector( pProperty ); + + //update listbox value. + m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2); + m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3); + //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; + + 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; + } + else + { + m_modifiedPrefBoxEntries.push_back(*it); + } + } + } + } + catch( uno::Exception& ) + { + } +} + +IMPL_LINK_NOARG( CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) +{ + 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::InsertEntry(const prefBoxEntry& rEntry) +{ + 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); + 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); + } + + 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); +} + +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: */ |