xref: /core/cui/source/options/optaboutconfig.cxx (revision 175a2063)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include "optaboutconfig.hxx"
11 
12 #include <comphelper/processfactory.hxx>
13 #include <comphelper/sequence.hxx>
14 #include <com/sun/star/configuration/theDefaultProvider.hpp>
15 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
16 #include <com/sun/star/beans/NamedValue.hpp>
17 #include <com/sun/star/container/XNameAccess.hpp>
18 #include <com/sun/star/container/XNameReplace.hpp>
19 #include <com/sun/star/container/XHierarchicalName.hpp>
20 #include <com/sun/star/util/XChangesBatch.hpp>
21 #include <com/sun/star/util/SearchFlags.hpp>
22 #include <com/sun/star/util/SearchAlgorithms2.hpp>
23 #include <unotools/textsearch.hxx>
24 #include <vcl/event.hxx>
25 #include <sal/log.hxx>
26 #include <tools/diagnose_ex.h>
27 
28 #include <memory>
29 #include <vector>
30 #include <iostream>
31 
32 using namespace ::com::sun::star;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::container;
35 
36 #define SHORT_LEN_LIMIT     7
37 #define LONG_LEN_LIMIT      11
38 #define HYPER_LEN_LIMIT     20
39 
40 struct Prop_Impl
41 {
42     OUString    Name;
43     OUString    Property;
44     Any         Value;
45 
46     Prop_Impl( const OUString& sName, const OUString& sProperty, const Any& aValue )
47         : Name( sName )
48         , Property( sProperty )
49         , Value( aValue )
50     {}
51 };
52 
53 struct UserData
54 {
55     bool bIsPropertyPath;
56     OUString sPropertyPath;
57     int aLineage;
58     Reference<XNameAccess> aXNameAccess;
59 
60     explicit UserData( OUString const & rPropertyPath )
61         : bIsPropertyPath( true )
62         , sPropertyPath(rPropertyPath)
63         , aLineage(0)
64     {}
65 
66     explicit UserData( Reference<XNameAccess> const & rXNameAccess, int rIndex )
67         : bIsPropertyPath( false )
68         , aLineage(rIndex)
69         , aXNameAccess( rXNameAccess )
70     {}
71 };
72 
73 IMPL_LINK(CuiAboutConfigValueDialog, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
74 {
75     bool bValid = false;
76     bool bNonSpace = rKeyEvent.GetKeyCode().GetCode() != KEY_SPACE;
77     if (m_bNumericOnly && bNonSpace )
78     {
79         const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
80         sal_uInt16 nGroup = rKeyCode.GetGroup();
81         sal_uInt16 nKey = rKeyCode.GetCode();
82 
83         switch ( nGroup ) {
84             case KEYGROUP_NUM :
85             case KEYGROUP_CURSOR :
86             {
87                 bValid = true;
88                 break;
89             }
90 
91             case KEYGROUP_MISC :
92             {
93                 switch ( nKey ) {
94                     case KEY_SUBTRACT :
95                     case KEY_COMMA :
96                     case KEY_POINT :
97                     {
98                         bValid = true;
99                         break;
100                     }
101 
102                     default :
103                     {
104                         if( nKey < KEY_ADD || nKey > KEY_EQUAL )
105                             bValid = true;
106                         break;
107                     }
108                 }
109                 break;
110             }
111 
112             default :
113             {
114                 bValid = false;
115                 break;
116             }
117         }
118 
119         //Select all, Copy, Paste, Cut, Undo Keys
120         if ( !bValid && ( rKeyCode.IsMod1() && (
121              KEY_A == nKey || KEY_C == nKey || KEY_V == nKey || KEY_X == nKey || KEY_Z == nKey ) ) )
122             bValid = true;
123     }
124     else
125         bValid = true;
126 
127     //if value return true to claim that it has been handled
128     return !bValid;
129 }
130 
131 CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent)
132     : GenericDialogController(pParent, "cui/ui/aboutconfigdialog.ui", "AboutConfig")
133     , m_xResetBtn(m_xBuilder->weld_button("reset"))
134     , m_xEditBtn(m_xBuilder->weld_button("edit"))
135     , m_xSearchBtn(m_xBuilder->weld_button("searchButton"))
136     , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
137     , m_xPrefBox(m_xBuilder->weld_tree_view("preferences"))
138     , m_xScratchIter(m_xPrefBox->make_iterator())
139     , m_vectorOfModified()
140     , m_bSorted(false)
141 {
142     m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100,
143                                  m_xPrefBox->get_height_rows(28));
144     m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick));
145 
146     m_xEditBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, StandardHdl_Impl));
147     m_xResetBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, ResetBtnHdl_Impl));
148     m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl));
149     m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl));
150     m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl));
151 
152     m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
153     m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
154     m_options.searchFlag |= (util::SearchFlags::REG_NOT_BEGINOFLINE |
155                                         util::SearchFlags::REG_NOT_ENDOFLINE);
156 
157     float fWidth = m_xPrefBox->get_approximate_digit_width();
158     std::vector<int> aWidths;
159     aWidths.push_back(fWidth * 65);
160     aWidths.push_back(fWidth * 20);
161     aWidths.push_back(fWidth * 8);
162     m_xPrefBox->set_column_fixed_widths(aWidths);
163 }
164 
165 IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void)
166 {
167     if (!m_bSorted)
168     {
169         m_xPrefBox->make_sorted();
170         m_bSorted = true;
171     }
172 
173     bool bSortAtoZ = m_xPrefBox->get_sort_order();
174 
175     //set new arrow positions in headerbar
176     if (nColumn == m_xPrefBox->get_sort_column())
177     {
178         bSortAtoZ = !bSortAtoZ;
179         m_xPrefBox->set_sort_order(bSortAtoZ);
180     }
181     else
182     {
183         m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
184         m_xPrefBox->set_sort_column(nColumn);
185     }
186 
187     if (nColumn != -1)
188     {
189         //sort lists
190         m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
191     }
192 }
193 
194 CuiAboutConfigTabPage::~CuiAboutConfigTabPage()
195 {
196 }
197 
198 void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, const OUString& rProp, const OUString& rStatus,
199                                         const OUString& rType, const OUString& rValue, const weld::TreeIter* pParentEntry,
200                                         bool bInsertToPrefBox)
201 {
202     m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath));
203     if (bInsertToPrefBox)
204     {
205         OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get())));
206         m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
207         m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1);
208         m_xPrefBox->set_text(*m_xScratchIter, rType, 2);
209         m_xPrefBox->set_text(*m_xScratchIter, rValue, 3);
210     }
211     else
212     {
213         m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()});
214     }
215 }
216 
217 void CuiAboutConfigTabPage::Reset()
218 {
219     weld::WaitObject aWait(m_xDialog.get());
220 
221     m_xPrefBox->clear();
222     m_vectorOfModified.clear();
223     if (m_bSorted)
224     {
225         m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
226         m_xPrefBox->make_unsorted();
227         m_bSorted = false;
228     }
229     m_prefBoxEntries.clear();
230     m_modifiedPrefBoxEntries.clear();
231 
232     m_xPrefBox->freeze();
233     Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
234     //Load all XNameAccess to m_prefBoxEntries
235     FillItems( xConfigAccess, nullptr, 0, true );
236     //Load xConfigAccess' children to m_prefBox
237     FillItems( xConfigAccess );
238     m_xPrefBox->thaw();
239 }
240 
241 void CuiAboutConfigTabPage::FillItemSet()
242 {
243     std::vector< std::shared_ptr< Prop_Impl > >::iterator pIter;
244     for( pIter = m_vectorOfModified.begin() ; pIter != m_vectorOfModified.end(); ++pIter )
245     {
246         Reference< XNameAccess > xUpdateAccess = getConfigAccess( (*pIter)->Name , true );
247         Reference< XNameReplace > xNameReplace( xUpdateAccess, UNO_QUERY_THROW );
248 
249         xNameReplace->replaceByName( (*pIter)->Property, (*pIter)->Value );
250 
251         Reference< util::XChangesBatch > xChangesBatch( xUpdateAccess, UNO_QUERY_THROW );
252         xChangesBatch->commitChanges();
253     }
254 }
255 
256 void CuiAboutConfigTabPage::FillItems(const Reference< XNameAccess >& xNameAccess, const weld::TreeIter* pParentEntry,
257                                       int lineage, bool bLoadAll)
258 {
259     OUString sPath = Reference< XHierarchicalName >(
260         xNameAccess, uno::UNO_QUERY_THROW )->getHierarchicalName();
261     uno::Sequence< OUString > seqItems = xNameAccess->getElementNames();
262     for( sal_Int32 i = 0; i < seqItems.getLength(); ++i )
263     {
264         Any aNode = xNameAccess->getByName( seqItems[i] );
265 
266         bool bNotLeaf = false;
267 
268         Reference< XNameAccess > xNextNameAccess;
269         try
270         {
271             xNextNameAccess.set(aNode, uno::UNO_QUERY);
272             bNotLeaf = xNextNameAccess.is();
273         }
274         catch (const RuntimeException&)
275         {
276             TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage");
277         }
278 
279         if (bNotLeaf)
280         {
281             if(bLoadAll)
282                 FillItems(xNextNameAccess, nullptr, lineage + 1, true);
283             else
284             {
285                 // not leaf node
286                 m_vectorUserData.push_back(std::make_unique<UserData>(xNextNameAccess, lineage + 1));
287                 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get())));
288 
289                 m_xPrefBox->insert(pParentEntry, -1, &seqItems[i], &sId, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
290                 //It is needed, without this the selection line will be truncated.
291                 m_xPrefBox->set_text(*m_xScratchIter, "", 1);
292                 m_xPrefBox->set_text(*m_xScratchIter, "", 2);
293                 m_xPrefBox->set_text(*m_xScratchIter, "", 3);
294             }
295         }
296         else
297         {
298             // leaf node
299             OUString sPropertyName = seqItems[i];
300             auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
301               [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool
302               {
303                   return rEntry.pUserData->sPropertyPath == sPath
304                       && rEntry.sStatus == sPropertyName;
305               }
306             );
307 
308             OUString sType = aNode.getValueTypeName();
309             OUStringBuffer sValue;
310 
311             if (it != m_modifiedPrefBoxEntries.end())
312                 sValue = it->sValue;
313             else
314             {
315                 switch( aNode.getValueType().getTypeClass() )
316                 {
317                 case css::uno::TypeClass_VOID:
318                     break;
319 
320                 case css::uno::TypeClass_BOOLEAN:
321                     sValue = OUString::boolean( aNode.get<bool>() );
322                     break;
323 
324                 case css::uno::TypeClass_SHORT:
325                 case css::uno::TypeClass_LONG:
326                 case css::uno::TypeClass_HYPER:
327                     sValue = OUString::number( aNode.get<sal_Int64>() );
328                     break;
329 
330                 case css::uno::TypeClass_DOUBLE:
331                     sValue = OUString::number( aNode.get<double>() );
332                     break;
333 
334                 case css::uno::TypeClass_STRING:
335                     sValue = aNode.get<OUString>();
336                     break;
337 
338                 case css::uno::TypeClass_SEQUENCE:
339                     if( sType == "[]boolean" )
340                     {
341                         uno::Sequence<sal_Bool> seq = aNode.get< uno::Sequence<sal_Bool> >();
342                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
343                         {
344                             if( j != 0 )
345                             {
346                                 sValue.append(",");
347                             }
348                             sValue.append(OUString::boolean( seq[j] ));
349                         }
350                     }
351                     else if( sType == "[]byte" )
352                     {
353                         uno::Sequence<sal_Int8> seq = aNode.get< uno::Sequence<sal_Int8> >();
354                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
355                         {
356                             OUString s = OUString::number(
357                                 static_cast<sal_uInt8>(seq[j]), 16 );
358                             if( s.getLength() == 1 )
359                             {
360                                 sValue.append("0");
361                             }
362                             sValue.append(s.toAsciiUpperCase());
363                         }
364                     }
365                     else if( sType == "[][]byte" )
366                     {
367                         uno::Sequence< uno::Sequence<sal_Int8> > seq = aNode.get< uno::Sequence< uno::Sequence<sal_Int8> > >();
368                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
369                         {
370                             if( j != 0 )
371                             {
372                                 sValue.append(",");
373                             }
374                             for( sal_Int32 k = 0; k != seq[j].getLength(); ++k )
375                             {
376                                 OUString s = OUString::number(
377                                     static_cast<sal_uInt8>(seq[j][k]), 16 );
378                                 if( s.getLength() == 1 )
379                                 {
380                                     sValue.append("0");
381                                 }
382                                 sValue.append(s.toAsciiUpperCase());
383                             }
384                         }
385                     }
386                     else if( sType == "[]short" )
387                     {
388                         uno::Sequence<sal_Int16> seq = aNode.get< uno::Sequence<sal_Int16> >();
389                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
390                         {
391                             if( j != 0 )
392                             {
393                                 sValue.append(",");
394                             }
395                             sValue.append(OUString::number( seq[j] ));
396                         }
397                     }
398                     else if( sType == "[]long" )
399                     {
400                         uno::Sequence<sal_Int32> seq = aNode.get< uno::Sequence<sal_Int32> >();
401                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
402                         {
403                             if( j != 0 )
404                             {
405                                 sValue.append(",");
406                             }
407                             sValue.append(OUString::number( seq[j] ));
408                         }
409                     }
410                     else if( sType == "[]hyper" )
411                     {
412                         uno::Sequence<sal_Int64> seq = aNode.get< uno::Sequence<sal_Int64> >();
413                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
414                         {
415                             if( j != 0 )
416                             {
417                                 sValue.append(",");
418                             }
419                             sValue.append(OUString::number( seq[j] ));
420                         }
421                     }
422                     else if( sType == "[]double" )
423                     {
424                         uno::Sequence<double> seq = aNode.get< uno::Sequence<double> >();
425                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
426                         {
427                             if( j != 0 )
428                             {
429                                 sValue.append(",");
430                             }
431                             sValue.append(OUString::number( seq[j] ));
432                         }
433                     }
434                     else if( sType == "[]string" )
435                     {
436                         uno::Sequence<OUString> seq = aNode.get< uno::Sequence<OUString> >();
437                         for( sal_Int32 j = 0; j != seq.getLength(); ++j )
438                         {
439                             if( j != 0 )
440                             {
441                                 sValue.append(",");
442                             }
443                             sValue.append(seq[j]);
444                         }
445                     }
446                     else
447                     {
448                         SAL_WARN(
449                             "cui.options",
450                             "path \"" << sPath << "\" member " << seqItems[i]
451                                 << " of unsupported type " << sType);
452                     }
453                     break;
454 
455                 default:
456                     SAL_WARN(
457                         "cui.options",
458                         "path \"" << sPath << "\" member " << seqItems[i]
459                             << " of unsupported type " << sType);
460                     break;
461                 }
462             }
463 
464             //Short name
465             int index = 0;
466             for(int j = 1; j < lineage; ++j)
467                 index = sPath.indexOf("/", index + 1);
468 
469             InsertEntry(sPath, sPath.copy(index+1), seqItems[i], sType, sValue.makeStringAndClear(), pParentEntry, !bLoadAll);
470         }
471     }
472 }
473 
474 Reference< XNameAccess > CuiAboutConfigTabPage::getConfigAccess( const OUString& sNodePath, bool bUpdate )
475 {
476     uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
477 
478     uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
479                 css::configuration::theDefaultProvider::get( xContext  ) );
480 
481     beans::NamedValue aProperty;
482     aProperty.Name = "nodepath";
483     aProperty.Value <<= sNodePath;
484 
485     uno::Sequence< uno::Any > aArgumentList( 1 );
486     aArgumentList[0] <<= aProperty;
487 
488     OUString sAccessString;
489 
490     if( bUpdate )
491         sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
492     else
493         sAccessString = "com.sun.star.configuration.ConfigurationAccess";
494 
495     uno::Reference< container::XNameAccess > xNameAccess(
496                 xConfigProvider->createInstanceWithArguments(
497                     sAccessString, aArgumentList ),
498                 uno::UNO_QUERY_THROW );
499 
500     return xNameAccess;
501 }
502 
503 void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr< Prop_Impl >& rProp )
504 {
505     bool isModifiedBefore = false;
506     //Check if value modified before
507     for(std::shared_ptr<Prop_Impl> & nInd : m_vectorOfModified)
508     {
509         if( rProp->Name == nInd->Name && rProp->Property == nInd->Property )
510         {
511             //property modified before. Assign reference to the modified value
512             //do your changes on this object. They will be saved later.
513             nInd = rProp;
514             isModifiedBefore = true;
515             break;
516         }
517     }
518 
519     if( !isModifiedBefore )
520         m_vectorOfModified.push_back( rProp );
521     //property is not modified before
522 }
523 
524 std::vector< OUString > CuiAboutConfigTabPage::commaStringToSequence( const OUString& rCommaSepString )
525 {
526     std::vector<OUString> tempVector;
527 
528     sal_Int32 index = 0;
529     do
530     {
531         OUString word = rCommaSepString.getToken(0, u',', index);
532         word = word.trim();
533         if( !word.isEmpty())
534             tempVector.push_back(word);
535     }while( index >= 0 );
536     return tempVector;
537 }
538 
539 CuiAboutConfigValueDialog::CuiAboutConfigValueDialog(weld::Window* pWindow,
540                                                      const OUString& rValue,
541                                                      int limit)
542     : GenericDialogController(pWindow, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog")
543     , m_bNumericOnly(limit != 0)
544     , m_xEDValue(m_xBuilder->weld_entry("valuebox"))
545 {
546     if (limit)
547         m_xEDValue->set_max_length(limit);
548     m_xEDValue->set_text(rValue);
549     m_xEDValue->connect_key_press(LINK(this, CuiAboutConfigValueDialog, KeyInputHdl));
550 }
551 
552 CuiAboutConfigValueDialog::~CuiAboutConfigValueDialog()
553 {
554 }
555 
556 IMPL_LINK_NOARG( CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void )
557 {
558     Reset();
559 }
560 
561 IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool)
562 {
563     StandardHdl_Impl(*m_xEditBtn);
564     return true;
565 }
566 
567 IMPL_LINK_NOARG( CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void )
568 {
569     if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
570         return;
571 
572     UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(*m_xScratchIter).toInt64());
573     if (pUserData && pUserData->bIsPropertyPath)
574     {
575         //if selection is a node
576         OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1);
577         OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2);
578         OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3);
579 
580         auto pProperty  = std::make_shared<Prop_Impl>( pUserData->sPropertyPath, sPropertyName, Any( sPropertyValue ) );
581         bool bSaveChanges = false;
582 
583         bool bOpenDialog = true;
584         OUString sDialogValue;
585         OUString sNewValue;
586 
587         if( sPropertyType == "boolean" )
588         {
589             bool bValue;
590             if( sPropertyValue == "true" )
591             {
592                 sDialogValue = "false";
593                 bValue = false;
594             }
595             else
596             {
597                 sDialogValue = "true";
598                 bValue = true;
599             }
600 
601             pProperty->Value <<= bValue;
602             bOpenDialog = false;
603             bSaveChanges = true;
604         }
605         else if ( sPropertyType == "void" )
606         {
607             bOpenDialog = false;
608         }
609         else
610         {
611             sDialogValue = sPropertyValue;
612             bOpenDialog = true;
613         }
614 
615         try
616         {
617             if( bOpenDialog )
618             {
619                 //Cosmetic length limit for integer values.
620                 int limit=0;
621                 if( sPropertyType == "short" )
622                     limit = SHORT_LEN_LIMIT;
623                 else if( sPropertyType == "long" )
624                     limit = LONG_LEN_LIMIT;
625                 else if( sPropertyType == "hyper" )
626                     limit = HYPER_LEN_LIMIT;
627 
628                 CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit);
629 
630                 if (aValueDialog.run() == RET_OK )
631                 {
632                     sNewValue = aValueDialog.getValue();
633                     bSaveChanges = true;
634                     if ( sPropertyType == "short")
635                     {
636                         sal_Int16 nShort;
637                         sal_Int32 nNumb = sNewValue.toInt32();
638 
639                         //if the value is 0 and length is not 1, there is something wrong
640                         if( ( nNumb==0 && sNewValue.getLength()!=1 ) || nNumb > SAL_MAX_INT16 || nNumb < SAL_MIN_INT16)
641                             throw uno::Exception("out of range short", nullptr);
642                         nShort = static_cast<sal_Int16>(nNumb);
643                         pProperty->Value <<= nShort;
644                     }
645                     else if( sPropertyType == "long" )
646                     {
647                         sal_Int32 nLong = sNewValue.toInt32();
648                         if( nLong==0 && sNewValue.getLength()!=1)
649                             throw uno::Exception("out of range long", nullptr);
650                         pProperty->Value <<= nLong;
651                     }
652                     else if( sPropertyType == "hyper")
653                     {
654                         sal_Int64 nHyper = sNewValue.toInt64();
655                         if( nHyper==0 && sNewValue.getLength()!=1)
656                             throw uno::Exception("out of range hyper", nullptr);
657                         pProperty->Value <<= nHyper;
658                     }
659                     else if( sPropertyType == "double")
660                     {
661                         double nDoub = sNewValue.toDouble();
662                         if( nDoub ==0 && sNewValue.getLength()!=1)
663                             throw uno::Exception("out of range double", nullptr);
664                         pProperty->Value <<= nDoub;
665                     }
666                     else if( sPropertyType == "float")
667                     {
668                         float nFloat = sNewValue.toFloat();
669                         if( nFloat ==0 && sNewValue.getLength()!=1)
670                             throw uno::Exception("out of range float", nullptr);
671                         pProperty->Value <<= nFloat;
672                     }
673                     else if( sPropertyType == "string" )
674                     {
675                         pProperty->Value <<= sNewValue;
676                     }
677                     else if( sPropertyType == "[]short" )
678                     {
679                         //create string sequence from comma separated string
680                         //uno::Sequence< OUString > seqStr;
681                         std::vector< OUString > seqStr = commaStringToSequence( sNewValue );
682 
683                         //create appropriate sequence with same size as string sequence
684                         uno::Sequence< sal_Int16 > seqShort( seqStr.size() );
685                         //convert all strings to appropriate type
686                         for( size_t i = 0; i < seqStr.size(); ++i )
687                         {
688                             seqShort[i] = static_cast<sal_Int16>(seqStr[i].toInt32());
689                         }
690                         pProperty->Value <<= seqShort;
691                     }
692                     else if( sPropertyType == "[]long" )
693                     {
694                         std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue );
695 
696                         uno::Sequence< sal_Int32 > seqLong( seqStrLong.size() );
697                         for( size_t i = 0; i < seqStrLong.size(); ++i )
698                         {
699                             seqLong[i] = seqStrLong[i].toInt32();
700                         }
701                         pProperty->Value <<= seqLong;
702                     }
703                     else if( sPropertyType == "[]hyper" )
704                     {
705                         std::vector< OUString > seqStrHyper = commaStringToSequence( sNewValue );
706                         uno::Sequence< sal_Int64 > seqHyper( seqStrHyper.size() );
707                         for( size_t i = 0; i < seqStrHyper.size(); ++i )
708                         {
709                             seqHyper[i] = seqStrHyper[i].toInt64();
710                         }
711                         pProperty->Value <<= seqHyper;
712                     }
713                     else if( sPropertyType == "[]double" )
714                     {
715                         std::vector< OUString > seqStrDoub = commaStringToSequence( sNewValue );
716                         uno::Sequence< double > seqDoub( seqStrDoub.size() );
717                         for( size_t i = 0; i < seqStrDoub.size(); ++i )
718                         {
719                             seqDoub[i] = seqStrDoub[i].toDouble();
720                         }
721                         pProperty->Value <<= seqDoub;
722                     }
723                     else if( sPropertyType == "[]float" )
724                     {
725                         std::vector< OUString > seqStrFloat = commaStringToSequence( sNewValue );
726                         uno::Sequence< sal_Int16 > seqFloat( seqStrFloat.size() );
727                         for( size_t i = 0; i < seqStrFloat.size(); ++i )
728                         {
729                             seqFloat[i] = seqStrFloat[i].toFloat();
730                         }
731                         pProperty->Value <<= seqFloat;
732                     }
733                     else if( sPropertyType == "[]string" )
734                     {
735                         pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue ));
736                     }
737                     else //unknown
738                         throw uno::Exception("unknown property type " + sPropertyType, nullptr);
739 
740                     sDialogValue = sNewValue;
741                 }
742             }
743 
744             if(bSaveChanges)
745             {
746                 AddToModifiedVector( pProperty );
747 
748                 //update listbox value.
749                 m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
750                 //update m_prefBoxEntries
751                 auto it = std::find_if(m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
752                   [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
753                   {
754                       return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
755                           && rEntry.sStatus == sPropertyName;
756                   }
757                 );
758                 if (it != m_prefBoxEntries.end())
759                 {
760                     it->sValue = sDialogValue;
761 
762                     auto modifiedIt = std::find_if(
763                                 m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
764                                 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
765                                 {
766                                     return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
767                                         && rEntry.sStatus == sPropertyName;
768                                 }
769                     );
770 
771                     if (modifiedIt != m_modifiedPrefBoxEntries.end())
772                     {
773                         modifiedIt->sValue = sDialogValue;
774                     }
775                     else
776                     {
777                         m_modifiedPrefBoxEntries.push_back(*it);
778                     }
779                 }
780             }
781         }
782         catch( uno::Exception& )
783         {
784         }
785     }
786 }
787 
788 IMPL_LINK_NOARG( CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void)
789 {
790     weld::WaitObject aWait(m_xDialog.get());
791 
792     m_xPrefBox->clear();
793     m_xPrefBox->freeze();
794 
795     if (m_bSorted)
796         m_xPrefBox->make_unsorted();
797 
798     if (m_xSearchEdit->get_text().isEmpty())
799     {
800         m_xPrefBox->clear();
801         Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
802         FillItems( xConfigAccess );
803     }
804     else
805     {
806         m_options.searchString = m_xSearchEdit->get_text();
807         utl::TextSearch textSearch( m_options );
808         for (auto const& it : m_prefBoxEntries)
809         {
810             sal_Int32 endPos, startPos = 0;
811 
812             for(size_t i = 0; i < 5; ++i)
813             {
814                 OUString scrTxt;
815 
816                 if (i == 0)
817                     scrTxt = it.pUserData->sPropertyPath;
818                 else if (i == 1)
819                     scrTxt = it.sProp;
820                 else if (i == 2)
821                     scrTxt = it.sStatus;
822                 else if (i == 3)
823                     scrTxt = it.sType;
824                 else if (i == 4)
825                     scrTxt = it.sValue;
826 
827                 endPos = scrTxt.getLength();
828                 if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
829                 {
830                     InsertEntry(it);
831                     break;
832                 }
833             }
834         }
835     }
836 
837     m_xPrefBox->thaw();
838     if (m_bSorted)
839         m_xPrefBox->make_sorted();
840 
841     m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
842         m_xPrefBox->expand_row(rEntry);
843         return false;
844     });
845 }
846 
847 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry)
848 {
849     OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
850     sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
851     OUString sPath = sPathWithProperty.copy(0, index);
852     index = 0;
853     std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator());
854     std::unique_ptr<weld::TreeIter> xGrandParentEntry;
855 
856     do
857     {
858         int prevIndex = index;
859         index = sPath.indexOf("/", index+1);
860         // deal with no parent case (tdf#107811)
861         if (index < 0)
862         {
863             OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData)));
864             m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
865             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
866             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
867             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
868             return;
869         }
870         OUString sParentName = sPath.copy(prevIndex+1, index - prevIndex - 1);
871 
872         bool hasEntry = false;
873         bool bStartOk;
874 
875         if (!xGrandParentEntry)
876             bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
877         else
878         {
879             m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
880             bStartOk = m_xPrefBox->iter_children(*xParentEntry);
881         }
882 
883         if (bStartOk)
884         {
885             do
886             {
887                 if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
888                 {
889                     hasEntry = true;
890                     break;
891                 }
892             } while (m_xPrefBox->iter_next_sibling(*xParentEntry));
893         }
894 
895         if (!hasEntry)
896         {
897             m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr, nullptr, false, xParentEntry.get());
898             //It is needed, without this the selection line will be truncated.
899             m_xPrefBox->set_text(*xParentEntry, "", 1);
900             m_xPrefBox->set_text(*xParentEntry, "", 2);
901             m_xPrefBox->set_text(*xParentEntry, "", 3);
902         }
903 
904         xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
905     } while(index < sPath.getLength() - 1);
906 
907     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData)));
908     m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
909     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
910     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
911     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
912 }
913 
914 IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
915 {
916     if (m_xPrefBox->iter_has_child(rEntry))
917         return true;
918     UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(rEntry).toInt64());
919     if (pUserData && !pUserData->bIsPropertyPath)
920     {
921         assert(pUserData->aXNameAccess.is());
922         FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
923     }
924     return true;
925 }
926 
927 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
928