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