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