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