1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <o3tl/safeint.hxx>
11 #include <o3tl/string_view.hxx>
12 #include "optaboutconfig.hxx"
14 #include <comphelper/processfactory.hxx>
15 #include <comphelper/sequence.hxx>
16 #include <com/sun/star/configuration/theDefaultProvider.hpp>
17 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
18 #include <com/sun/star/beans/NamedValue.hpp>
19 #include <com/sun/star/beans/PropertyAttribute.hpp>
20 #include <com/sun/star/beans/UnknownPropertyException.hpp>
21 #include <com/sun/star/beans/XPropertySetInfo.hpp>
22 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
23 #include <com/sun/star/container/XNameAccess.hpp>
24 #include <com/sun/star/container/XNameReplace.hpp>
25 #include <com/sun/star/container/XHierarchicalName.hpp>
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/uno/Type.hxx>
28 #include <com/sun/star/uno/TypeClass.hpp>
29 #include <com/sun/star/util/XChangesBatch.hpp>
30 #include <com/sun/star/util/SearchFlags.hpp>
31 #include <com/sun/star/util/SearchAlgorithms2.hpp>
32 #include <cppu/unotype.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <unotools/textsearch.hxx>
36 #include <vcl/event.hxx>
37 #include <sal/log.hxx>
38 #include <comphelper/diagnose_ex.hxx>
40 #include <dialmgr.hxx>
41 #include <strings.hrc>
47 using namespace ::com::sun::star
;
48 using namespace com::sun::star::uno
;
49 using namespace com::sun::star::container
;
51 #define SHORT_LEN_LIMIT 7
52 #define LONG_LEN_LIMIT 11
53 #define HYPER_LEN_LIMIT 20
61 Prop_Impl( OUString sName
, OUString sProperty
, Any aValue
)
62 : Name(std::move( sName
))
63 , Property(std::move( sProperty
))
64 , Value(std::move( aValue
))
72 OUString sPropertyPath
;
74 Reference
<XNameAccess
> aXNameAccess
;
76 explicit UserData( OUString aPropertyPath
, bool isReadOnly
)
77 : bIsPropertyPath( true )
78 , bIsReadOnly( isReadOnly
)
79 , sPropertyPath(std::move(aPropertyPath
))
83 explicit UserData( Reference
<XNameAccess
> const & rXNameAccess
, int rIndex
)
84 : bIsPropertyPath( false )
85 , bIsReadOnly( false )
87 , aXNameAccess( rXNameAccess
)
91 IMPL_LINK(CuiAboutConfigValueDialog
, KeyInputHdl
, const KeyEvent
&, rKeyEvent
, bool)
94 bool bNonSpace
= rKeyEvent
.GetKeyCode().GetCode() != KEY_SPACE
;
95 if (m_bNumericOnly
&& bNonSpace
)
97 const vcl::KeyCode
& rKeyCode
= rKeyEvent
.GetKeyCode();
98 sal_uInt16 nGroup
= rKeyCode
.GetGroup();
99 sal_uInt16 nKey
= rKeyCode
.GetCode();
103 case KEYGROUP_CURSOR
:
122 if( nKey
< KEY_ADD
|| nKey
> KEY_EQUAL
)
137 //Select all, Copy, Paste, Cut, Undo Keys
138 if ( !bValid
&& ( rKeyCode
.IsMod1() && (
139 KEY_A
== nKey
|| KEY_C
== nKey
|| KEY_V
== nKey
|| KEY_X
== nKey
|| KEY_Z
== nKey
) ) )
145 //if value return true to claim that it has been handled
149 CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window
* pParent
)
150 : GenericDialogController(pParent
, "cui/ui/aboutconfigdialog.ui", "AboutConfig")
151 , m_xResetBtn(m_xBuilder
->weld_button("reset"))
152 , m_xEditBtn(m_xBuilder
->weld_button("edit"))
153 , m_xSearchBtn(m_xBuilder
->weld_button("searchButton"))
154 , m_xSearchEdit(m_xBuilder
->weld_entry("searchEntry"))
155 , m_xPrefBox(m_xBuilder
->weld_tree_view("preferences"))
156 , m_xScratchIter(m_xPrefBox
->make_iterator())
159 m_xPrefBox
->set_size_request(m_xPrefBox
->get_approximate_digit_width() * 100,
160 m_xPrefBox
->get_height_rows(23));
161 m_xPrefBox
->connect_column_clicked(LINK(this, CuiAboutConfigTabPage
, HeaderBarClick
));
163 m_xEditBtn
->connect_clicked(LINK( this, CuiAboutConfigTabPage
, StandardHdl_Impl
));
164 m_xResetBtn
->connect_clicked(LINK( this, CuiAboutConfigTabPage
, ResetBtnHdl_Impl
));
165 m_xPrefBox
->connect_row_activated(LINK(this, CuiAboutConfigTabPage
, DoubleClickHdl_Impl
));
166 m_xPrefBox
->connect_expanding(LINK(this, CuiAboutConfigTabPage
, ExpandingHdl_Impl
));
167 m_xSearchBtn
->connect_clicked(LINK(this, CuiAboutConfigTabPage
, SearchHdl_Impl
));
169 m_options
.AlgorithmType2
= util::SearchAlgorithms2::ABSOLUTE
;
170 m_options
.transliterateFlags
|= TransliterationFlags::IGNORE_CASE
;
171 m_options
.searchFlag
|= (util::SearchFlags::REG_NOT_BEGINOFLINE
|
172 util::SearchFlags::REG_NOT_ENDOFLINE
);
174 float fWidth
= m_xPrefBox
->get_approximate_digit_width();
175 std::vector
<int> aWidths
177 o3tl::narrowing
<int>(fWidth
* 65),
178 o3tl::narrowing
<int>(fWidth
* 20),
179 o3tl::narrowing
<int>(fWidth
* 8)
181 m_xPrefBox
->set_column_fixed_widths(aWidths
);
183 m_xPrefBox
->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage
, QueryTooltip
));
186 IMPL_LINK(CuiAboutConfigTabPage
, QueryTooltip
, const weld::TreeIter
&, rIter
, OUString
)
188 UserData
*pUserData
= weld::fromId
<UserData
*>(m_xPrefBox
->get_id(rIter
));
189 if (pUserData
&& pUserData
->bIsReadOnly
)
191 return CuiResId(RID_CUISTR_OPT_READONLY
);
197 IMPL_LINK(CuiAboutConfigTabPage
, HeaderBarClick
, int, nColumn
, void)
201 m_xPrefBox
->make_sorted();
205 bool bSortAtoZ
= m_xPrefBox
->get_sort_order();
207 //set new arrow positions in headerbar
208 if (nColumn
== m_xPrefBox
->get_sort_column())
210 bSortAtoZ
= !bSortAtoZ
;
211 m_xPrefBox
->set_sort_order(bSortAtoZ
);
215 int nOldSortColumn
= m_xPrefBox
->get_sort_column();
216 if (nOldSortColumn
!= -1)
217 m_xPrefBox
->set_sort_indicator(TRISTATE_INDET
, nOldSortColumn
);
218 m_xPrefBox
->set_sort_column(nColumn
);
224 m_xPrefBox
->set_sort_indicator(bSortAtoZ
? TRISTATE_TRUE
: TRISTATE_FALSE
, nColumn
);
228 CuiAboutConfigTabPage::~CuiAboutConfigTabPage()
232 void CuiAboutConfigTabPage::InsertEntry(const OUString
& rPropertyPath
, const OUString
& rProp
, const OUString
& rStatus
,
233 const OUString
& rType
, const OUString
& rValue
, const weld::TreeIter
* pParentEntry
,
234 bool bInsertToPrefBox
, bool bIsReadOnly
)
236 m_vectorUserData
.push_back(std::make_unique
<UserData
>(rPropertyPath
, bIsReadOnly
));
237 if (bInsertToPrefBox
)
239 OUString
sId(weld::toId(m_vectorUserData
.back().get()));
240 m_xPrefBox
->insert(pParentEntry
, -1, &rProp
, &sId
, nullptr, nullptr, false, m_xScratchIter
.get());
241 m_xPrefBox
->set_text(*m_xScratchIter
, rStatus
, 1);
242 m_xPrefBox
->set_text(*m_xScratchIter
, rType
, 2);
243 m_xPrefBox
->set_text(*m_xScratchIter
, rValue
, 3);
244 m_xPrefBox
->set_sensitive(*m_xScratchIter
, !bIsReadOnly
, -1);
248 m_prefBoxEntries
.push_back({rProp
, rStatus
, rType
, rValue
, m_vectorUserData
.back().get()});
252 void CuiAboutConfigTabPage::Reset()
254 weld::WaitObject
aWait(m_xDialog
.get());
257 m_vectorOfModified
.clear();
260 m_xPrefBox
->set_sort_indicator(TRISTATE_INDET
, m_xPrefBox
->get_sort_column());
261 m_xPrefBox
->make_unsorted();
264 m_prefBoxEntries
.clear();
265 m_modifiedPrefBoxEntries
.clear();
267 m_xPrefBox
->freeze();
268 Reference
< XNameAccess
> xConfigAccess
= getConfigAccess( "/", false );
269 //Load all XNameAccess to m_prefBoxEntries
270 FillItems( xConfigAccess
, nullptr, 0, true );
271 //Load xConfigAccess' children to m_prefBox
272 FillItems( xConfigAccess
);
276 void CuiAboutConfigTabPage::FillItemSet()
278 std::vector
< std::shared_ptr
< Prop_Impl
> >::iterator pIter
;
279 for( pIter
= m_vectorOfModified
.begin() ; pIter
!= m_vectorOfModified
.end(); ++pIter
)
281 Reference
< XNameAccess
> xUpdateAccess
= getConfigAccess( (*pIter
)->Name
, true );
282 Reference
< XNameReplace
> xNameReplace( xUpdateAccess
, UNO_QUERY_THROW
);
284 xNameReplace
->replaceByName( (*pIter
)->Property
, (*pIter
)->Value
);
286 Reference
< util::XChangesBatch
> xChangesBatch( xUpdateAccess
, UNO_QUERY_THROW
);
287 xChangesBatch
->commitChanges();
291 void CuiAboutConfigTabPage::FillItems(const Reference
< XNameAccess
>& xNameAccess
, const weld::TreeIter
* pParentEntry
,
292 int lineage
, bool bLoadAll
)
294 OUString sPath
= Reference
< XHierarchicalName
>(
295 xNameAccess
, uno::UNO_QUERY_THROW
)->getHierarchicalName();
296 const uno::Sequence
< OUString
> seqItems
= xNameAccess
->getElementNames();
297 for( const OUString
& item
: seqItems
)
299 Any aNode
= xNameAccess
->getByName( item
);
301 bool bNotLeaf
= false;
303 Reference
< XNameAccess
> xNextNameAccess
;
306 xNextNameAccess
.set(aNode
, uno::UNO_QUERY
);
307 bNotLeaf
= xNextNameAccess
.is();
309 catch (const RuntimeException
&)
311 TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage");
317 FillItems(xNextNameAccess
, nullptr, lineage
+ 1, true);
321 m_vectorUserData
.push_back(std::make_unique
<UserData
>(xNextNameAccess
, lineage
+ 1));
322 OUString
sId(weld::toId(m_vectorUserData
.back().get()));
324 m_xPrefBox
->insert(pParentEntry
, -1, &item
, &sId
, nullptr, nullptr, true, m_xScratchIter
.get());
325 // Necessary, without this the selection line will be truncated.
326 m_xPrefBox
->set_text(*m_xScratchIter
, "", 1);
327 m_xPrefBox
->set_text(*m_xScratchIter
, "", 2);
328 m_xPrefBox
->set_text(*m_xScratchIter
, "", 3);
329 m_xPrefBox
->set_sensitive(*m_xScratchIter
, true);
335 OUString sPropertyName
= item
;
336 auto it
= std::find_if(m_modifiedPrefBoxEntries
.begin(), m_modifiedPrefBoxEntries
.end(),
337 [&sPath
, &sPropertyName
](const prefBoxEntry
& rEntry
) -> bool
339 return rEntry
.pUserData
->sPropertyPath
== sPath
340 && rEntry
.sStatus
== sPropertyName
;
344 css::uno::Reference
<css::configuration::XReadWriteAccess
> m_xReadWriteAccess
;
345 m_xReadWriteAccess
= css::configuration::ReadWriteAccess::create(
346 ::comphelper::getProcessComponentContext(), "*");
347 beans::Property aProperty
;
348 bool bReadOnly
= false;
351 aProperty
= m_xReadWriteAccess
->getPropertyByHierarchicalName(sPath
+ "/"
353 bReadOnly
= (aProperty
.Attributes
& beans::PropertyAttribute::READONLY
) != 0;
355 catch (css::beans::UnknownPropertyException
)
357 SAL_WARN("cui.options", "unknown property: " << sPath
+ "/" + sPropertyName
);
360 OUString sType
= aNode
.getValueTypeName();
361 OUStringBuffer sValue
;
363 if (it
!= m_modifiedPrefBoxEntries
.end())
367 switch( aNode
.getValueType().getTypeClass() )
369 case css::uno::TypeClass_VOID
:
372 case css::uno::TypeClass_BOOLEAN
:
373 sValue
= OUString::boolean( aNode
.get
<bool>() );
376 case css::uno::TypeClass_SHORT
:
377 case css::uno::TypeClass_LONG
:
378 case css::uno::TypeClass_HYPER
:
379 sValue
= OUString::number( aNode
.get
<sal_Int64
>() );
382 case css::uno::TypeClass_DOUBLE
:
383 sValue
= OUString::number( aNode
.get
<double>() );
386 case css::uno::TypeClass_STRING
:
387 sValue
= aNode
.get
<OUString
>();
390 case css::uno::TypeClass_SEQUENCE
:
391 if( sType
== "[]boolean" )
393 uno::Sequence
<sal_Bool
> seq
= aNode
.get
< uno::Sequence
<sal_Bool
> >();
394 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
400 sValue
.append(OUString::boolean( seq
[j
] ));
403 else if( sType
== "[]byte" )
405 const uno::Sequence
<sal_Int8
> seq
= aNode
.get
< uno::Sequence
<sal_Int8
> >();
406 for( sal_Int8 j
: seq
)
408 OUString s
= OUString::number(
409 static_cast<sal_uInt8
>(j
), 16 );
410 if( s
.getLength() == 1 )
414 sValue
.append(s
.toAsciiUpperCase());
417 else if( sType
== "[][]byte" )
419 const uno::Sequence
< uno::Sequence
<sal_Int8
> > seq
= aNode
.get
< uno::Sequence
< uno::Sequence
<sal_Int8
> > >();
420 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
426 for( sal_Int8 k
: seq
[j
] )
428 OUString s
= OUString::number(
429 static_cast<sal_uInt8
>(k
), 16 );
430 if( s
.getLength() == 1 )
434 sValue
.append(s
.toAsciiUpperCase());
438 else if( sType
== "[]short" )
440 uno::Sequence
<sal_Int16
> seq
= aNode
.get
< uno::Sequence
<sal_Int16
> >();
441 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
447 sValue
.append( static_cast<sal_Int32
>(seq
[j
]) );
450 else if( sType
== "[]long" )
452 uno::Sequence
<sal_Int32
> seq
= aNode
.get
< uno::Sequence
<sal_Int32
> >();
453 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
459 sValue
.append( seq
[j
] );
462 else if( sType
== "[]hyper" )
464 uno::Sequence
<sal_Int64
> seq
= aNode
.get
< uno::Sequence
<sal_Int64
> >();
465 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
471 sValue
.append( seq
[j
] );
474 else if( sType
== "[]double" )
476 uno::Sequence
<double> seq
= aNode
.get
< uno::Sequence
<double> >();
477 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
483 sValue
.append( seq
[j
] );
486 else if( sType
== "[]string" )
488 uno::Sequence
<OUString
> seq
= aNode
.get
< uno::Sequence
<OUString
> >();
489 for( sal_Int32 j
= 0; j
!= seq
.getLength(); ++j
)
495 sValue
.append(seq
[j
]);
502 "path \"" << sPath
<< "\" member " << item
503 << " of unsupported type " << sType
);
510 "path \"" << sPath
<< "\" member " << item
511 << " of unsupported type " << sType
);
518 for(int j
= 1; j
< lineage
; ++j
)
519 index
= sPath
.indexOf("/", index
+ 1);
521 InsertEntry(sPath
, sPath
.copy(index
+ 1), item
, sType
, sValue
.makeStringAndClear(),
522 pParentEntry
, !bLoadAll
, bReadOnly
);
527 Reference
< XNameAccess
> CuiAboutConfigTabPage::getConfigAccess( const OUString
& sNodePath
, bool bUpdate
)
529 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
531 uno::Reference
< lang::XMultiServiceFactory
> xConfigProvider(
532 css::configuration::theDefaultProvider::get( xContext
) );
534 beans::NamedValue aProperty
;
535 aProperty
.Name
= "nodepath";
536 aProperty
.Value
<<= sNodePath
;
538 uno::Sequence
< uno::Any
> aArgumentList
{ uno::Any(aProperty
) };
540 OUString sAccessString
;
543 sAccessString
= "com.sun.star.configuration.ConfigurationUpdateAccess";
545 sAccessString
= "com.sun.star.configuration.ConfigurationAccess";
547 uno::Reference
< container::XNameAccess
> xNameAccess(
548 xConfigProvider
->createInstanceWithArguments(
549 sAccessString
, aArgumentList
),
550 uno::UNO_QUERY_THROW
);
555 void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr
< Prop_Impl
>& rProp
)
557 bool isModifiedBefore
= false;
558 //Check if value modified before
559 for(std::shared_ptr
<Prop_Impl
> & nInd
: m_vectorOfModified
)
561 if( rProp
->Name
== nInd
->Name
&& rProp
->Property
== nInd
->Property
)
563 //property modified before. Assign reference to the modified value
564 //do your changes on this object. They will be saved later.
566 isModifiedBefore
= true;
571 if( !isModifiedBefore
)
572 m_vectorOfModified
.push_back( rProp
);
573 //property is not modified before
576 std::vector
< OUString
> CuiAboutConfigTabPage::commaStringToSequence( std::u16string_view rCommaSepString
)
578 std::vector
<OUString
> tempVector
;
583 OUString
word( o3tl::getToken(rCommaSepString
, 0, u
',', index
) );
586 tempVector
.push_back(word
);
587 }while( index
>= 0 );
591 CuiAboutConfigValueDialog::CuiAboutConfigValueDialog(weld::Window
* pWindow
,
592 const OUString
& rValue
,
594 : GenericDialogController(pWindow
, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog")
595 , m_bNumericOnly(limit
!= 0)
596 , m_xEDValue(m_xBuilder
->weld_entry("valuebox"))
599 m_xEDValue
->set_max_length(limit
);
600 m_xEDValue
->set_text(rValue
);
601 m_xEDValue
->connect_key_press(LINK(this, CuiAboutConfigValueDialog
, KeyInputHdl
));
604 CuiAboutConfigValueDialog::~CuiAboutConfigValueDialog()
608 IMPL_LINK_NOARG( CuiAboutConfigTabPage
, ResetBtnHdl_Impl
, weld::Button
&, void )
613 IMPL_LINK_NOARG(CuiAboutConfigTabPage
, DoubleClickHdl_Impl
, weld::TreeView
&, bool)
615 StandardHdl_Impl(*m_xEditBtn
);
619 IMPL_LINK_NOARG( CuiAboutConfigTabPage
, StandardHdl_Impl
, weld::Button
&, void )
621 if (!m_xPrefBox
->get_selected(m_xScratchIter
.get()))
624 UserData
*pUserData
= weld::fromId
<UserData
*>(m_xPrefBox
->get_id(*m_xScratchIter
));
625 if (!pUserData
|| !pUserData
->bIsPropertyPath
|| pUserData
->bIsReadOnly
)
628 //if selection is a node
629 OUString sPropertyName
= m_xPrefBox
->get_text(*m_xScratchIter
, 1);
630 OUString sPropertyType
= m_xPrefBox
->get_text(*m_xScratchIter
, 2);
631 OUString sPropertyValue
= m_xPrefBox
->get_text(*m_xScratchIter
, 3);
633 // If the configuration property has a nil value, determine its static type:
634 if (sPropertyType
== "void")
636 css::uno::Reference
<css::beans::XPropertySetInfo
> info(
637 CuiAboutConfigTabPage::getConfigAccess(pUserData
->sPropertyPath
, false),
638 css::uno::UNO_QUERY_THROW
);
641 t
= info
->getPropertyByName(sPropertyName
).Type
;
642 } catch (css::beans::UnknownPropertyException
&) {
643 TOOLS_WARN_EXCEPTION("cui.options", pUserData
->sPropertyPath
<< " " << sPropertyName
);
645 // If the configuration property is of type any (or an UnknownPropertyException was caught
646 // above), stick to "void" for now (ideally, properties of type any would allow setting
647 // values of arbitrary type, regardless of their current value, in this dialog anyway):
648 if (t
!= cppu::UnoType
<void>::get()) {
649 sPropertyType
= t
.getTypeName();
650 switch (t
.getTypeClass()) {
651 case css::uno::TypeClass_BOOLEAN
:
652 sPropertyValue
= "false";
654 case css::uno::TypeClass_SHORT
:
655 case css::uno::TypeClass_LONG
:
656 case css::uno::TypeClass_HYPER
:
657 case css::uno::TypeClass_DOUBLE
:
658 sPropertyValue
= "0";
666 auto pProperty
= std::make_shared
<Prop_Impl
>( pUserData
->sPropertyPath
, sPropertyName
, Any( sPropertyValue
) );
667 bool bSaveChanges
= false;
669 bool bOpenDialog
= true;
670 OUString sDialogValue
;
672 if( sPropertyType
== "boolean" )
675 if( sPropertyValue
== "true" )
677 sDialogValue
= "false";
682 sDialogValue
= "true";
686 pProperty
->Value
<<= bValue
;
690 else if ( sPropertyType
== "void" )
696 sDialogValue
= sPropertyValue
;
704 //Cosmetic length limit for integer values.
706 if( sPropertyType
== "short" )
707 limit
= SHORT_LEN_LIMIT
;
708 else if( sPropertyType
== "long" )
709 limit
= LONG_LEN_LIMIT
;
710 else if( sPropertyType
== "hyper" )
711 limit
= HYPER_LEN_LIMIT
;
713 CuiAboutConfigValueDialog
aValueDialog(m_xDialog
.get(), sDialogValue
, limit
);
715 if (aValueDialog
.run() == RET_OK
)
717 OUString sNewValue
= aValueDialog
.getValue();
719 if ( sPropertyType
== "short")
722 sal_Int32 nNumb
= sNewValue
.toInt32();
724 //if the value is 0 and length is not 1, there is something wrong
725 if( ( nNumb
==0 && sNewValue
.getLength()!=1 ) || nNumb
> SAL_MAX_INT16
|| nNumb
< SAL_MIN_INT16
)
726 throw uno::Exception("out of range short", nullptr);
727 nShort
= static_cast<sal_Int16
>(nNumb
);
728 pProperty
->Value
<<= nShort
;
730 else if( sPropertyType
== "long" )
732 sal_Int32 nLong
= sNewValue
.toInt32();
733 if( nLong
==0 && sNewValue
.getLength()!=1)
734 throw uno::Exception("out of range long", nullptr);
735 pProperty
->Value
<<= nLong
;
737 else if( sPropertyType
== "hyper")
739 sal_Int64 nHyper
= sNewValue
.toInt64();
740 if( nHyper
==0 && sNewValue
.getLength()!=1)
741 throw uno::Exception("out of range hyper", nullptr);
742 pProperty
->Value
<<= nHyper
;
744 else if( sPropertyType
== "double")
746 double nDoub
= sNewValue
.toDouble();
747 if( nDoub
==0 && sNewValue
.getLength()!=1)
748 throw uno::Exception("out of range double", nullptr);
749 pProperty
->Value
<<= nDoub
;
751 else if( sPropertyType
== "float")
753 float nFloat
= sNewValue
.toFloat();
754 if( nFloat
==0 && sNewValue
.getLength()!=1)
755 throw uno::Exception("out of range float", nullptr);
756 pProperty
->Value
<<= nFloat
;
758 else if( sPropertyType
== "string" )
760 pProperty
->Value
<<= sNewValue
;
762 else if( sPropertyType
== "[]short" )
764 //create string sequence from comma separated string
765 //uno::Sequence< OUString > seqStr;
766 std::vector
< OUString
> seqStr
= commaStringToSequence( sNewValue
);
768 //create appropriate sequence with same size as string sequence
769 uno::Sequence
< sal_Int16
> seqShort( seqStr
.size() );
770 //convert all strings to appropriate type
771 std::transform(seqStr
.begin(), seqStr
.end(), seqShort
.getArray(),
773 { return static_cast<sal_Int16
>(str
.toInt32()); });
774 pProperty
->Value
<<= seqShort
;
776 else if( sPropertyType
== "[]long" )
778 std::vector
< OUString
> seqStrLong
= commaStringToSequence( sNewValue
);
780 uno::Sequence
< sal_Int32
> seqLong( seqStrLong
.size() );
781 std::transform(seqStrLong
.begin(), seqStrLong
.end(), seqLong
.getArray(),
782 [](const auto& str
) { return str
.toInt32(); });
783 pProperty
->Value
<<= seqLong
;
785 else if( sPropertyType
== "[]hyper" )
787 std::vector
< OUString
> seqStrHyper
= commaStringToSequence( sNewValue
);
788 uno::Sequence
< sal_Int64
> seqHyper( seqStrHyper
.size() );
789 std::transform(seqStrHyper
.begin(), seqStrHyper
.end(), seqHyper
.getArray(),
790 [](const auto& str
) { return str
.toInt64(); });
791 pProperty
->Value
<<= seqHyper
;
793 else if( sPropertyType
== "[]double" )
795 std::vector
< OUString
> seqStrDoub
= commaStringToSequence( sNewValue
);
796 uno::Sequence
< double > seqDoub( seqStrDoub
.size() );
797 std::transform(seqStrDoub
.begin(), seqStrDoub
.end(), seqDoub
.getArray(),
798 [](const auto& str
) { return str
.toDouble(); });
799 pProperty
->Value
<<= seqDoub
;
801 else if( sPropertyType
== "[]float" )
803 std::vector
< OUString
> seqStrFloat
= commaStringToSequence( sNewValue
);
804 uno::Sequence
< sal_Int16
> seqFloat( seqStrFloat
.size() );
805 std::transform(seqStrFloat
.begin(), seqStrFloat
.end(), seqFloat
.getArray(),
806 [](const auto& str
) { return str
.toFloat(); });
807 pProperty
->Value
<<= seqFloat
;
809 else if( sPropertyType
== "[]string" )
811 pProperty
->Value
<<= comphelper::containerToSequence( commaStringToSequence( sNewValue
));
814 throw uno::Exception("unknown property type " + sPropertyType
, nullptr);
816 sDialogValue
= sNewValue
;
822 AddToModifiedVector( pProperty
);
824 //update listbox value.
825 m_xPrefBox
->set_text(*m_xScratchIter
, sPropertyType
, 2);
826 m_xPrefBox
->set_text(*m_xScratchIter
, sDialogValue
, 3);
827 //update m_prefBoxEntries
828 auto it
= std::find_if(m_prefBoxEntries
.begin(), m_prefBoxEntries
.end(),
829 [&pUserData
, &sPropertyName
](const prefBoxEntry
& rEntry
) -> bool
831 return rEntry
.pUserData
->sPropertyPath
== pUserData
->sPropertyPath
832 && rEntry
.sStatus
== sPropertyName
;
835 if (it
!= m_prefBoxEntries
.end())
837 it
->sValue
= sDialogValue
;
839 auto modifiedIt
= std::find_if(
840 m_modifiedPrefBoxEntries
.begin(), m_modifiedPrefBoxEntries
.end(),
841 [&pUserData
, &sPropertyName
](const prefBoxEntry
& rEntry
) -> bool
843 return rEntry
.pUserData
->sPropertyPath
== pUserData
->sPropertyPath
844 && rEntry
.sStatus
== sPropertyName
;
848 if (modifiedIt
!= m_modifiedPrefBoxEntries
.end())
850 modifiedIt
->sValue
= sDialogValue
;
854 m_modifiedPrefBoxEntries
.push_back(*it
);
859 catch( uno::Exception
& )
864 IMPL_LINK_NOARG( CuiAboutConfigTabPage
, SearchHdl_Impl
, weld::Button
&, void)
866 weld::WaitObject
aWait(m_xDialog
.get());
870 m_xPrefBox
->freeze();
873 m_xPrefBox
->make_unsorted();
875 if (m_xSearchEdit
->get_text().isEmpty())
878 Reference
< XNameAccess
> xConfigAccess
= getConfigAccess( "/", false );
879 FillItems( xConfigAccess
);
883 m_options
.searchString
= m_xSearchEdit
->get_text();
884 utl::TextSearch
textSearch( m_options
);
885 for (auto const& it
: m_prefBoxEntries
)
887 sal_Int32 endPos
, startPos
= 0;
889 for(size_t i
= 0; i
< 5; ++i
)
894 scrTxt
= it
.pUserData
->sPropertyPath
;
904 endPos
= scrTxt
.getLength();
905 if (textSearch
.SearchForward(scrTxt
, &startPos
, &endPos
))
916 m_xPrefBox
->make_sorted();
918 m_xPrefBox
->all_foreach([this](weld::TreeIter
& rEntry
) {
919 m_xPrefBox
->expand_row(rEntry
);
925 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry
& rEntry
)
927 OUString sPathWithProperty
= rEntry
.pUserData
->sPropertyPath
;
928 sal_Int32 index
= sPathWithProperty
.lastIndexOf(rEntry
.sProp
);
929 OUString sPath
= sPathWithProperty
.copy(0, index
);
931 std::unique_ptr
<weld::TreeIter
> xParentEntry(m_xPrefBox
->make_iterator());
932 std::unique_ptr
<weld::TreeIter
> xGrandParentEntry
;
936 int prevIndex
= index
;
937 index
= sPath
.indexOf("/", index
+1);
938 // deal with no parent case (tdf#107811)
941 OUString
sId(weld::toId(rEntry
.pUserData
));
942 m_xPrefBox
->insert(nullptr, -1, &rEntry
.sProp
, &sId
, nullptr, nullptr, false, m_xScratchIter
.get());
943 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sStatus
, 1);
944 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sType
, 2);
945 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sValue
, 3);
946 m_xPrefBox
->set_sensitive(*m_xScratchIter
, !rEntry
.pUserData
->bIsReadOnly
);
949 OUString sParentName
= sPath
.copy(prevIndex
+1, index
- prevIndex
- 1);
951 bool hasEntry
= false;
954 if (!xGrandParentEntry
)
955 bStartOk
= m_xPrefBox
->get_iter_first(*xParentEntry
);
958 m_xPrefBox
->copy_iterator(*xGrandParentEntry
, *xParentEntry
);
959 bStartOk
= m_xPrefBox
->iter_children(*xParentEntry
);
966 if (m_xPrefBox
->get_text(*xParentEntry
, 0) == sParentName
)
971 } while (m_xPrefBox
->iter_next_sibling(*xParentEntry
));
976 m_xPrefBox
->insert(xGrandParentEntry
.get(), -1, &sParentName
, nullptr, nullptr, nullptr, false, xParentEntry
.get());
977 //It is needed, without this the selection line will be truncated.
978 m_xPrefBox
->set_text(*xParentEntry
, "", 1);
979 m_xPrefBox
->set_text(*xParentEntry
, "", 2);
980 m_xPrefBox
->set_text(*xParentEntry
, "", 3);
981 m_xPrefBox
->set_sensitive(*xParentEntry
, true);
984 xGrandParentEntry
= m_xPrefBox
->make_iterator(xParentEntry
.get());
985 } while(index
< sPath
.getLength() - 1);
987 OUString
sId(weld::toId(rEntry
.pUserData
));
988 m_xPrefBox
->insert(xParentEntry
.get(), -1, &rEntry
.sProp
, &sId
, nullptr, nullptr, false, m_xScratchIter
.get());
989 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sStatus
, 1);
990 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sType
, 2);
991 m_xPrefBox
->set_text(*m_xScratchIter
, rEntry
.sValue
, 3);
992 m_xPrefBox
->set_sensitive(*m_xScratchIter
, !rEntry
.pUserData
->bIsReadOnly
);
995 IMPL_LINK(CuiAboutConfigTabPage
, ExpandingHdl_Impl
, const weld::TreeIter
&, rEntry
, bool)
997 if (m_xPrefBox
->iter_has_child(rEntry
))
999 UserData
*pUserData
= weld::fromId
<UserData
*>(m_xPrefBox
->get_id(rEntry
));
1000 if (pUserData
&& !pUserData
->bIsPropertyPath
)
1002 assert(pUserData
->aXNameAccess
.is());
1003 FillItems(pUserData
->aXNameAccess
, &rEntry
, pUserData
->aLineage
);
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */