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