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 <rtl/ustrbuf.hxx>
24 #include <unotools/textsearch.hxx>
25 #include <vcl/event.hxx>
26 #include <sal/log.hxx>
27 #include <tools/diagnose_ex.h>
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_bSorted(false)
141 {
142  m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100,
143  m_xPrefBox->get_height_rows(23));
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  int nOldSortColumn = m_xPrefBox->get_sort_column();
184  if (nOldSortColumn != -1)
185  m_xPrefBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
186  m_xPrefBox->set_sort_column(nColumn);
187  }
188 
189  if (nColumn != -1)
190  {
191  //sort lists
192  m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
193  }
194 }
195 
197 {
198 }
199 
200 void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, const OUString& rProp, const OUString& rStatus,
201  const OUString& rType, const OUString& rValue, const weld::TreeIter* pParentEntry,
202  bool bInsertToPrefBox)
203 {
204  m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath));
205  if (bInsertToPrefBox)
206  {
207  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get())));
208  m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
209  m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1);
210  m_xPrefBox->set_text(*m_xScratchIter, rType, 2);
211  m_xPrefBox->set_text(*m_xScratchIter, rValue, 3);
212  }
213  else
214  {
215  m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()});
216  }
217 }
218 
220 {
221  weld::WaitObject aWait(m_xDialog.get());
222 
223  m_xPrefBox->clear();
224  m_vectorOfModified.clear();
225  if (m_bSorted)
226  {
227  m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
228  m_xPrefBox->make_unsorted();
229  m_bSorted = false;
230  }
231  m_prefBoxEntries.clear();
232  m_modifiedPrefBoxEntries.clear();
233 
234  m_xPrefBox->freeze();
235  Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
236  //Load all XNameAccess to m_prefBoxEntries
237  FillItems( xConfigAccess, nullptr, 0, true );
238  //Load xConfigAccess' children to m_prefBox
239  FillItems( xConfigAccess );
240  m_xPrefBox->thaw();
241 }
242 
244 {
245  std::vector< std::shared_ptr< Prop_Impl > >::iterator pIter;
246  for( pIter = m_vectorOfModified.begin() ; pIter != m_vectorOfModified.end(); ++pIter )
247  {
248  Reference< XNameAccess > xUpdateAccess = getConfigAccess( (*pIter)->Name , true );
249  Reference< XNameReplace > xNameReplace( xUpdateAccess, UNO_QUERY_THROW );
250 
251  xNameReplace->replaceByName( (*pIter)->Property, (*pIter)->Value );
252 
253  Reference< util::XChangesBatch > xChangesBatch( xUpdateAccess, UNO_QUERY_THROW );
254  xChangesBatch->commitChanges();
255  }
256 }
257 
258 void CuiAboutConfigTabPage::FillItems(const Reference< XNameAccess >& xNameAccess, const weld::TreeIter* pParentEntry,
259  int lineage, bool bLoadAll)
260 {
261  OUString sPath = Reference< XHierarchicalName >(
262  xNameAccess, uno::UNO_QUERY_THROW )->getHierarchicalName();
263  const uno::Sequence< OUString > seqItems = xNameAccess->getElementNames();
264  for( const OUString& item : seqItems )
265  {
266  Any aNode = xNameAccess->getByName( item );
267 
268  bool bNotLeaf = false;
269 
270  Reference< XNameAccess > xNextNameAccess;
271  try
272  {
273  xNextNameAccess.set(aNode, uno::UNO_QUERY);
274  bNotLeaf = xNextNameAccess.is();
275  }
276  catch (const RuntimeException&)
277  {
278  TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage");
279  }
280 
281  if (bNotLeaf)
282  {
283  if(bLoadAll)
284  FillItems(xNextNameAccess, nullptr, lineage + 1, true);
285  else
286  {
287  // not leaf node
288  m_vectorUserData.push_back(std::make_unique<UserData>(xNextNameAccess, lineage + 1));
289  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get())));
290 
291  m_xPrefBox->insert(pParentEntry, -1, &item, &sId, nullptr, nullptr, true, m_xScratchIter.get());
292  // Necessary, without this the selection line will be truncated.
293  m_xPrefBox->set_text(*m_xScratchIter, "", 1);
294  m_xPrefBox->set_text(*m_xScratchIter, "", 2);
295  m_xPrefBox->set_text(*m_xScratchIter, "", 3);
296  }
297  }
298  else
299  {
300  // leaf node
301  OUString sPropertyName = item;
302  auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
303  [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool
304  {
305  return rEntry.pUserData->sPropertyPath == sPath
306  && rEntry.sStatus == sPropertyName;
307  }
308  );
309 
310  OUString sType = aNode.getValueTypeName();
311  OUStringBuffer sValue;
312 
313  if (it != m_modifiedPrefBoxEntries.end())
314  sValue = it->sValue;
315  else
316  {
317  switch( aNode.getValueType().getTypeClass() )
318  {
319  case css::uno::TypeClass_VOID:
320  break;
321 
322  case css::uno::TypeClass_BOOLEAN:
323  sValue = OUString::boolean( aNode.get<bool>() );
324  break;
325 
326  case css::uno::TypeClass_SHORT:
327  case css::uno::TypeClass_LONG:
328  case css::uno::TypeClass_HYPER:
329  sValue = OUString::number( aNode.get<sal_Int64>() );
330  break;
331 
332  case css::uno::TypeClass_DOUBLE:
333  sValue = OUString::number( aNode.get<double>() );
334  break;
335 
336  case css::uno::TypeClass_STRING:
337  sValue = aNode.get<OUString>();
338  break;
339 
340  case css::uno::TypeClass_SEQUENCE:
341  if( sType == "[]boolean" )
342  {
343  uno::Sequence<sal_Bool> seq = aNode.get< uno::Sequence<sal_Bool> >();
344  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
345  {
346  if( j != 0 )
347  {
348  sValue.append(",");
349  }
350  sValue.append(OUString::boolean( seq[j] ));
351  }
352  }
353  else if( sType == "[]byte" )
354  {
355  uno::Sequence<sal_Int8> seq = aNode.get< uno::Sequence<sal_Int8> >();
356  for( sal_Int8 j : seq )
357  {
358  OUString s = OUString::number(
359  static_cast<sal_uInt8>(j), 16 );
360  if( s.getLength() == 1 )
361  {
362  sValue.append("0");
363  }
364  sValue.append(s.toAsciiUpperCase());
365  }
366  }
367  else if( sType == "[][]byte" )
368  {
369  uno::Sequence< uno::Sequence<sal_Int8> > seq = aNode.get< uno::Sequence< uno::Sequence<sal_Int8> > >();
370  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
371  {
372  if( j != 0 )
373  {
374  sValue.append(",");
375  }
376  for( sal_Int8 k : seq[j] )
377  {
378  OUString s = OUString::number(
379  static_cast<sal_uInt8>(k), 16 );
380  if( s.getLength() == 1 )
381  {
382  sValue.append("0");
383  }
384  sValue.append(s.toAsciiUpperCase());
385  }
386  }
387  }
388  else if( sType == "[]short" )
389  {
390  uno::Sequence<sal_Int16> seq = aNode.get< uno::Sequence<sal_Int16> >();
391  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
392  {
393  if( j != 0 )
394  {
395  sValue.append(",");
396  }
397  sValue.append( static_cast<sal_Int32>(seq[j]) );
398  }
399  }
400  else if( sType == "[]long" )
401  {
402  uno::Sequence<sal_Int32> seq = aNode.get< uno::Sequence<sal_Int32> >();
403  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
404  {
405  if( j != 0 )
406  {
407  sValue.append(",");
408  }
409  sValue.append( seq[j] );
410  }
411  }
412  else if( sType == "[]hyper" )
413  {
414  uno::Sequence<sal_Int64> seq = aNode.get< uno::Sequence<sal_Int64> >();
415  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
416  {
417  if( j != 0 )
418  {
419  sValue.append(",");
420  }
421  sValue.append( seq[j] );
422  }
423  }
424  else if( sType == "[]double" )
425  {
426  uno::Sequence<double> seq = aNode.get< uno::Sequence<double> >();
427  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
428  {
429  if( j != 0 )
430  {
431  sValue.append(",");
432  }
433  sValue.append( seq[j] );
434  }
435  }
436  else if( sType == "[]string" )
437  {
438  uno::Sequence<OUString> seq = aNode.get< uno::Sequence<OUString> >();
439  for( sal_Int32 j = 0; j != seq.getLength(); ++j )
440  {
441  if( j != 0 )
442  {
443  sValue.append(",");
444  }
445  sValue.append(seq[j]);
446  }
447  }
448  else
449  {
450  SAL_WARN(
451  "cui.options",
452  "path \"" << sPath << "\" member " << item
453  << " of unsupported type " << sType);
454  }
455  break;
456 
457  default:
458  SAL_WARN(
459  "cui.options",
460  "path \"" << sPath << "\" member " << item
461  << " of unsupported type " << sType);
462  break;
463  }
464  }
465 
466  //Short name
467  int index = 0;
468  for(int j = 1; j < lineage; ++j)
469  index = sPath.indexOf("/", index + 1);
470 
471  InsertEntry(sPath, sPath.copy(index+1), item, sType, sValue.makeStringAndClear(), pParentEntry, !bLoadAll);
472  }
473  }
474 }
475 
476 Reference< XNameAccess > CuiAboutConfigTabPage::getConfigAccess( const OUString& sNodePath, bool bUpdate )
477 {
478  uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
479 
480  uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
481  css::configuration::theDefaultProvider::get( xContext ) );
482 
483  beans::NamedValue aProperty;
484  aProperty.Name = "nodepath";
485  aProperty.Value <<= sNodePath;
486 
487  uno::Sequence< uno::Any > aArgumentList( 1 );
488  aArgumentList[0] <<= aProperty;
489 
490  OUString sAccessString;
491 
492  if( bUpdate )
493  sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
494  else
495  sAccessString = "com.sun.star.configuration.ConfigurationAccess";
496 
497  uno::Reference< container::XNameAccess > xNameAccess(
498  xConfigProvider->createInstanceWithArguments(
499  sAccessString, aArgumentList ),
500  uno::UNO_QUERY_THROW );
501 
502  return xNameAccess;
503 }
504 
505 void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr< Prop_Impl >& rProp )
506 {
507  bool isModifiedBefore = false;
508  //Check if value modified before
509  for(std::shared_ptr<Prop_Impl> & nInd : m_vectorOfModified)
510  {
511  if( rProp->Name == nInd->Name && rProp->Property == nInd->Property )
512  {
513  //property modified before. Assign reference to the modified value
514  //do your changes on this object. They will be saved later.
515  nInd = rProp;
516  isModifiedBefore = true;
517  break;
518  }
519  }
520 
521  if( !isModifiedBefore )
522  m_vectorOfModified.push_back( rProp );
523  //property is not modified before
524 }
525 
526 std::vector< OUString > CuiAboutConfigTabPage::commaStringToSequence( const OUString& rCommaSepString )
527 {
528  std::vector<OUString> tempVector;
529 
530  sal_Int32 index = 0;
531  do
532  {
533  OUString word = rCommaSepString.getToken(0, u',', index);
534  word = word.trim();
535  if( !word.isEmpty())
536  tempVector.push_back(word);
537  }while( index >= 0 );
538  return tempVector;
539 }
540 
542  const OUString& rValue,
543  int limit)
544  : GenericDialogController(pWindow, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog")
545  , m_bNumericOnly(limit != 0)
546  , m_xEDValue(m_xBuilder->weld_entry("valuebox"))
547 {
548  if (limit)
549  m_xEDValue->set_max_length(limit);
550  m_xEDValue->set_text(rValue);
551  m_xEDValue->connect_key_press(LINK(this, CuiAboutConfigValueDialog, KeyInputHdl));
552 }
553 
555 {
556 }
557 
559 {
560  Reset();
561 }
562 
564 {
565  StandardHdl_Impl(*m_xEditBtn);
566  return true;
567 }
568 
570 {
571  if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
572  return;
573 
574  UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(*m_xScratchIter).toInt64());
575  if (!(pUserData && pUserData->bIsPropertyPath))
576  return;
577 
578  //if selection is a node
579  OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1);
580  OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2);
581  OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3);
582 
583  auto pProperty = std::make_shared<Prop_Impl>( pUserData->sPropertyPath, sPropertyName, Any( sPropertyValue ) );
584  bool bSaveChanges = false;
585 
586  bool bOpenDialog = true;
587  OUString sDialogValue;
588 
589  if( sPropertyType == "boolean" )
590  {
591  bool bValue;
592  if( sPropertyValue == "true" )
593  {
594  sDialogValue = "false";
595  bValue = false;
596  }
597  else
598  {
599  sDialogValue = "true";
600  bValue = true;
601  }
602 
603  pProperty->Value <<= bValue;
604  bOpenDialog = false;
605  bSaveChanges = true;
606  }
607  else if ( sPropertyType == "void" )
608  {
609  bOpenDialog = false;
610  }
611  else
612  {
613  sDialogValue = sPropertyValue;
614  bOpenDialog = true;
615  }
616 
617  try
618  {
619  if( bOpenDialog )
620  {
621  //Cosmetic length limit for integer values.
622  int limit=0;
623  if( sPropertyType == "short" )
624  limit = SHORT_LEN_LIMIT;
625  else if( sPropertyType == "long" )
626  limit = LONG_LEN_LIMIT;
627  else if( sPropertyType == "hyper" )
628  limit = HYPER_LEN_LIMIT;
629 
630  CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit);
631 
632  if (aValueDialog.run() == RET_OK )
633  {
634  OUString sNewValue = aValueDialog.getValue();
635  bSaveChanges = true;
636  if ( sPropertyType == "short")
637  {
638  sal_Int16 nShort;
639  sal_Int32 nNumb = sNewValue.toInt32();
640 
641  //if the value is 0 and length is not 1, there is something wrong
642  if( ( nNumb==0 && sNewValue.getLength()!=1 ) || nNumb > SAL_MAX_INT16 || nNumb < SAL_MIN_INT16)
643  throw uno::Exception("out of range short", nullptr);
644  nShort = static_cast<sal_Int16>(nNumb);
645  pProperty->Value <<= nShort;
646  }
647  else if( sPropertyType == "long" )
648  {
649  sal_Int32 nLong = sNewValue.toInt32();
650  if( nLong==0 && sNewValue.getLength()!=1)
651  throw uno::Exception("out of range long", nullptr);
652  pProperty->Value <<= nLong;
653  }
654  else if( sPropertyType == "hyper")
655  {
656  sal_Int64 nHyper = sNewValue.toInt64();
657  if( nHyper==0 && sNewValue.getLength()!=1)
658  throw uno::Exception("out of range hyper", nullptr);
659  pProperty->Value <<= nHyper;
660  }
661  else if( sPropertyType == "double")
662  {
663  double nDoub = sNewValue.toDouble();
664  if( nDoub ==0 && sNewValue.getLength()!=1)
665  throw uno::Exception("out of range double", nullptr);
666  pProperty->Value <<= nDoub;
667  }
668  else if( sPropertyType == "float")
669  {
670  float nFloat = sNewValue.toFloat();
671  if( nFloat ==0 && sNewValue.getLength()!=1)
672  throw uno::Exception("out of range float", nullptr);
673  pProperty->Value <<= nFloat;
674  }
675  else if( sPropertyType == "string" )
676  {
677  pProperty->Value <<= sNewValue;
678  }
679  else if( sPropertyType == "[]short" )
680  {
681  //create string sequence from comma separated string
682  //uno::Sequence< OUString > seqStr;
683  std::vector< OUString > seqStr = commaStringToSequence( sNewValue );
684 
685  //create appropriate sequence with same size as string sequence
686  uno::Sequence< sal_Int16 > seqShort( seqStr.size() );
687  //convert all strings to appropriate type
688  for( size_t i = 0; i < seqStr.size(); ++i )
689  {
690  seqShort[i] = static_cast<sal_Int16>(seqStr[i].toInt32());
691  }
692  pProperty->Value <<= seqShort;
693  }
694  else if( sPropertyType == "[]long" )
695  {
696  std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue );
697 
698  uno::Sequence< sal_Int32 > seqLong( seqStrLong.size() );
699  for( size_t i = 0; i < seqStrLong.size(); ++i )
700  {
701  seqLong[i] = seqStrLong[i].toInt32();
702  }
703  pProperty->Value <<= seqLong;
704  }
705  else if( sPropertyType == "[]hyper" )
706  {
707  std::vector< OUString > seqStrHyper = commaStringToSequence( sNewValue );
708  uno::Sequence< sal_Int64 > seqHyper( seqStrHyper.size() );
709  for( size_t i = 0; i < seqStrHyper.size(); ++i )
710  {
711  seqHyper[i] = seqStrHyper[i].toInt64();
712  }
713  pProperty->Value <<= seqHyper;
714  }
715  else if( sPropertyType == "[]double" )
716  {
717  std::vector< OUString > seqStrDoub = commaStringToSequence( sNewValue );
718  uno::Sequence< double > seqDoub( seqStrDoub.size() );
719  for( size_t i = 0; i < seqStrDoub.size(); ++i )
720  {
721  seqDoub[i] = seqStrDoub[i].toDouble();
722  }
723  pProperty->Value <<= seqDoub;
724  }
725  else if( sPropertyType == "[]float" )
726  {
727  std::vector< OUString > seqStrFloat = commaStringToSequence( sNewValue );
728  uno::Sequence< sal_Int16 > seqFloat( seqStrFloat.size() );
729  for( size_t i = 0; i < seqStrFloat.size(); ++i )
730  {
731  seqFloat[i] = seqStrFloat[i].toFloat();
732  }
733  pProperty->Value <<= seqFloat;
734  }
735  else if( sPropertyType == "[]string" )
736  {
737  pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue ));
738  }
739  else //unknown
740  throw uno::Exception("unknown property type " + sPropertyType, nullptr);
741 
742  sDialogValue = sNewValue;
743  }
744  }
745 
746  if(bSaveChanges)
747  {
748  AddToModifiedVector( pProperty );
749 
750  //update listbox value.
751  m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
752  //update m_prefBoxEntries
753  auto it = std::find_if(m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
754  [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
755  {
756  return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
757  && rEntry.sStatus == sPropertyName;
758  }
759  );
760  if (it != m_prefBoxEntries.end())
761  {
762  it->sValue = sDialogValue;
763 
764  auto modifiedIt = std::find_if(
765  m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
766  [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
767  {
768  return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
769  && rEntry.sStatus == sPropertyName;
770  }
771  );
772 
773  if (modifiedIt != m_modifiedPrefBoxEntries.end())
774  {
775  modifiedIt->sValue = sDialogValue;
776  }
777  else
778  {
779  m_modifiedPrefBoxEntries.push_back(*it);
780  }
781  }
782  }
783  }
784  catch( uno::Exception& )
785  {
786  }
787 }
788 
790 {
791  weld::WaitObject aWait(m_xDialog.get());
792 
793  m_xPrefBox->hide();
794  m_xPrefBox->clear();
795  m_xPrefBox->freeze();
796 
797  if (m_bSorted)
798  m_xPrefBox->make_unsorted();
799 
800  if (m_xSearchEdit->get_text().isEmpty())
801  {
802  m_xPrefBox->clear();
803  Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
804  FillItems( xConfigAccess );
805  }
806  else
807  {
808  m_options.searchString = m_xSearchEdit->get_text();
809  utl::TextSearch textSearch( m_options );
810  for (auto const& it : m_prefBoxEntries)
811  {
812  sal_Int32 endPos, startPos = 0;
813 
814  for(size_t i = 0; i < 5; ++i)
815  {
816  OUString scrTxt;
817 
818  if (i == 0)
819  scrTxt = it.pUserData->sPropertyPath;
820  else if (i == 1)
821  scrTxt = it.sProp;
822  else if (i == 2)
823  scrTxt = it.sStatus;
824  else if (i == 3)
825  scrTxt = it.sType;
826  else if (i == 4)
827  scrTxt = it.sValue;
828 
829  endPos = scrTxt.getLength();
830  if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
831  {
832  InsertEntry(it);
833  break;
834  }
835  }
836  }
837  }
838 
839  m_xPrefBox->thaw();
840  if (m_bSorted)
841  m_xPrefBox->make_sorted();
842 
843  m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
844  m_xPrefBox->expand_row(rEntry);
845  return false;
846  });
847  m_xPrefBox->show();
848 }
849 
851 {
852  OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
853  sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
854  OUString sPath = sPathWithProperty.copy(0, index);
855  index = 0;
856  std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator());
857  std::unique_ptr<weld::TreeIter> xGrandParentEntry;
858 
859  do
860  {
861  int prevIndex = index;
862  index = sPath.indexOf("/", index+1);
863  // deal with no parent case (tdf#107811)
864  if (index < 0)
865  {
866  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData)));
867  m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
868  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
869  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
870  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
871  return;
872  }
873  OUString sParentName = sPath.copy(prevIndex+1, index - prevIndex - 1);
874 
875  bool hasEntry = false;
876  bool bStartOk;
877 
878  if (!xGrandParentEntry)
879  bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
880  else
881  {
882  m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
883  bStartOk = m_xPrefBox->iter_children(*xParentEntry);
884  }
885 
886  if (bStartOk)
887  {
888  do
889  {
890  if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
891  {
892  hasEntry = true;
893  break;
894  }
895  } while (m_xPrefBox->iter_next_sibling(*xParentEntry));
896  }
897 
898  if (!hasEntry)
899  {
900  m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr, false, xParentEntry.get());
901  //It is needed, without this the selection line will be truncated.
902  m_xPrefBox->set_text(*xParentEntry, "", 1);
903  m_xPrefBox->set_text(*xParentEntry, "", 2);
904  m_xPrefBox->set_text(*xParentEntry, "", 3);
905  }
906 
907  xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
908  } while(index < sPath.getLength() - 1);
909 
910  OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData)));
911  m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
912  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
913  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
914  m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
915 }
916 
917 IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
918 {
919  if (m_xPrefBox->iter_has_child(rEntry))
920  return true;
921  UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(rEntry).toInt64());
922  if (pUserData && !pUserData->bIsPropertyPath)
923  {
924  assert(pUserData->aXNameAccess.is());
925  FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
926  }
927  return true;
928 }
929 
930 /* 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