Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / cui / source / options / optaboutconfig.cxx
blob4578bc02758136e4c7757fe2d0a8a45485ed5588
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <o3tl/safeint.hxx>
11 #include <o3tl/string_view.hxx>
12 #include "optaboutconfig.hxx"
14 #include <comphelper/processfactory.hxx>
15 #include <comphelper/sequence.hxx>
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/PropertyAttribute.hpp>
20 #include <com/sun/star/beans/UnknownPropertyException.hpp>
21 #include <com/sun/star/beans/XPropertySetInfo.hpp>
22 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
23 #include <com/sun/star/container/XNameAccess.hpp>
24 #include <com/sun/star/container/XNameReplace.hpp>
25 #include <com/sun/star/container/XHierarchicalName.hpp>
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/uno/Type.hxx>
28 #include <com/sun/star/uno/TypeClass.hpp>
29 #include <com/sun/star/util/XChangesBatch.hpp>
30 #include <com/sun/star/util/SearchFlags.hpp>
31 #include <com/sun/star/util/SearchAlgorithms2.hpp>
32 #include <cppu/unotype.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <unotools/textsearch.hxx>
35 #include <utility>
36 #include <vcl/event.hxx>
37 #include <sal/log.hxx>
38 #include <comphelper/diagnose_ex.hxx>
40 #include <dialmgr.hxx>
41 #include <strings.hrc>
43 #include <algorithm>
44 #include <memory>
45 #include <vector>
47 using namespace ::com::sun::star;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::container;
51 #define SHORT_LEN_LIMIT 7
52 #define LONG_LEN_LIMIT 11
53 #define HYPER_LEN_LIMIT 20
55 struct Prop_Impl
57 OUString Name;
58 OUString Property;
59 Any Value;
61 Prop_Impl( OUString sName, OUString sProperty, Any aValue )
62 : Name(std::move( sName ))
63 , Property(std::move( sProperty ))
64 , Value(std::move( aValue ))
68 struct UserData
70 bool bIsPropertyPath;
71 bool bIsReadOnly;
72 OUString sPropertyPath;
73 int aLineage;
74 Reference<XNameAccess> aXNameAccess;
76 explicit UserData( OUString aPropertyPath, bool isReadOnly )
77 : bIsPropertyPath( true )
78 , bIsReadOnly( isReadOnly )
79 , sPropertyPath(std::move(aPropertyPath))
80 , aLineage(0)
83 explicit UserData( Reference<XNameAccess> const & rXNameAccess, int rIndex )
84 : bIsPropertyPath( false )
85 , bIsReadOnly( false )
86 , aLineage(rIndex)
87 , aXNameAccess( rXNameAccess )
91 IMPL_LINK(CuiAboutConfigValueDialog, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
93 bool bValid = false;
94 bool bNonSpace = rKeyEvent.GetKeyCode().GetCode() != KEY_SPACE;
95 if (m_bNumericOnly && bNonSpace )
97 const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
98 sal_uInt16 nGroup = rKeyCode.GetGroup();
99 sal_uInt16 nKey = rKeyCode.GetCode();
101 switch ( nGroup ) {
102 case KEYGROUP_NUM :
103 case KEYGROUP_CURSOR :
105 bValid = true;
106 break;
109 case KEYGROUP_MISC :
111 switch ( nKey ) {
112 case KEY_SUBTRACT :
113 case KEY_COMMA :
114 case KEY_POINT :
116 bValid = true;
117 break;
120 default :
122 if( nKey < KEY_ADD || nKey > KEY_EQUAL )
123 bValid = true;
124 break;
127 break;
130 default :
132 bValid = false;
133 break;
137 //Select all, Copy, Paste, Cut, Undo Keys
138 if ( !bValid && ( rKeyCode.IsMod1() && (
139 KEY_A == nKey || KEY_C == nKey || KEY_V == nKey || KEY_X == nKey || KEY_Z == nKey ) ) )
140 bValid = true;
142 else
143 bValid = true;
145 //if value return true to claim that it has been handled
146 return !bValid;
149 CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent)
150 : GenericDialogController(pParent, "cui/ui/aboutconfigdialog.ui", "AboutConfig")
151 , m_xResetBtn(m_xBuilder->weld_button("reset"))
152 , m_xEditBtn(m_xBuilder->weld_button("edit"))
153 , m_xSearchBtn(m_xBuilder->weld_button("searchButton"))
154 , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
155 , m_xPrefBox(m_xBuilder->weld_tree_view("preferences"))
156 , m_xScratchIter(m_xPrefBox->make_iterator())
157 , m_bSorted(false)
159 m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100,
160 m_xPrefBox->get_height_rows(23));
161 m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick));
163 m_xEditBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, StandardHdl_Impl));
164 m_xResetBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, ResetBtnHdl_Impl));
165 m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl));
166 m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl));
167 m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl));
169 m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
170 m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
171 m_options.searchFlag |= (util::SearchFlags::REG_NOT_BEGINOFLINE |
172 util::SearchFlags::REG_NOT_ENDOFLINE);
174 float fWidth = m_xPrefBox->get_approximate_digit_width();
175 std::vector<int> aWidths
177 o3tl::narrowing<int>(fWidth * 65),
178 o3tl::narrowing<int>(fWidth * 20),
179 o3tl::narrowing<int>(fWidth * 8)
181 m_xPrefBox->set_column_fixed_widths(aWidths);
183 m_xPrefBox->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage, QueryTooltip));
186 IMPL_LINK(CuiAboutConfigTabPage, QueryTooltip, const weld::TreeIter&, rIter, OUString)
188 UserData *pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rIter));
189 if (pUserData && pUserData->bIsReadOnly)
191 return CuiResId(RID_CUISTR_OPT_READONLY);
194 return OUString();
197 IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void)
199 if (!m_bSorted)
201 m_xPrefBox->make_sorted();
202 m_bSorted = true;
205 bool bSortAtoZ = m_xPrefBox->get_sort_order();
207 //set new arrow positions in headerbar
208 if (nColumn == m_xPrefBox->get_sort_column())
210 bSortAtoZ = !bSortAtoZ;
211 m_xPrefBox->set_sort_order(bSortAtoZ);
213 else
215 int nOldSortColumn = m_xPrefBox->get_sort_column();
216 if (nOldSortColumn != -1)
217 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
218 m_xPrefBox->set_sort_column(nColumn);
221 if (nColumn != -1)
223 //sort lists
224 m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
228 CuiAboutConfigTabPage::~CuiAboutConfigTabPage()
232 void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, const OUString& rProp, const OUString& rStatus,
233 const OUString& rType, const OUString& rValue, const weld::TreeIter* pParentEntry,
234 bool bInsertToPrefBox, bool bIsReadOnly)
236 m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, bIsReadOnly));
237 if (bInsertToPrefBox)
239 OUString sId(weld::toId(m_vectorUserData.back().get()));
240 m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
241 m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1);
242 m_xPrefBox->set_text(*m_xScratchIter, rType, 2);
243 m_xPrefBox->set_text(*m_xScratchIter, rValue, 3);
244 m_xPrefBox->set_sensitive(*m_xScratchIter, !bIsReadOnly, -1);
246 else
248 m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()});
252 void CuiAboutConfigTabPage::Reset()
254 weld::WaitObject aWait(m_xDialog.get());
256 m_xPrefBox->clear();
257 m_vectorOfModified.clear();
258 if (m_bSorted)
260 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
261 m_xPrefBox->make_unsorted();
262 m_bSorted = false;
264 m_prefBoxEntries.clear();
265 m_modifiedPrefBoxEntries.clear();
267 m_xPrefBox->freeze();
268 Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
269 //Load all XNameAccess to m_prefBoxEntries
270 FillItems( xConfigAccess, nullptr, 0, true );
271 //Load xConfigAccess' children to m_prefBox
272 FillItems( xConfigAccess );
273 m_xPrefBox->thaw();
276 void CuiAboutConfigTabPage::FillItemSet()
278 std::vector< std::shared_ptr< Prop_Impl > >::iterator pIter;
279 for( pIter = m_vectorOfModified.begin() ; pIter != m_vectorOfModified.end(); ++pIter )
281 Reference< XNameAccess > xUpdateAccess = getConfigAccess( (*pIter)->Name , true );
282 Reference< XNameReplace > xNameReplace( xUpdateAccess, UNO_QUERY_THROW );
284 xNameReplace->replaceByName( (*pIter)->Property, (*pIter)->Value );
286 Reference< util::XChangesBatch > xChangesBatch( xUpdateAccess, UNO_QUERY_THROW );
287 xChangesBatch->commitChanges();
291 void CuiAboutConfigTabPage::FillItems(const Reference< XNameAccess >& xNameAccess, const weld::TreeIter* pParentEntry,
292 int lineage, bool bLoadAll)
294 OUString sPath = Reference< XHierarchicalName >(
295 xNameAccess, uno::UNO_QUERY_THROW )->getHierarchicalName();
296 const uno::Sequence< OUString > seqItems = xNameAccess->getElementNames();
297 for( const OUString& item : seqItems )
299 Any aNode = xNameAccess->getByName( item );
301 bool bNotLeaf = false;
303 Reference< XNameAccess > xNextNameAccess;
306 xNextNameAccess.set(aNode, uno::UNO_QUERY);
307 bNotLeaf = xNextNameAccess.is();
309 catch (const RuntimeException&)
311 TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage");
314 if (bNotLeaf)
316 if(bLoadAll)
317 FillItems(xNextNameAccess, nullptr, lineage + 1, true);
318 else
320 // not leaf node
321 m_vectorUserData.push_back(std::make_unique<UserData>(xNextNameAccess, lineage + 1));
322 OUString sId(weld::toId(m_vectorUserData.back().get()));
324 m_xPrefBox->insert(pParentEntry, -1, &item, &sId, nullptr, nullptr, true, m_xScratchIter.get());
325 // Necessary, without this the selection line will be truncated.
326 m_xPrefBox->set_text(*m_xScratchIter, "", 1);
327 m_xPrefBox->set_text(*m_xScratchIter, "", 2);
328 m_xPrefBox->set_text(*m_xScratchIter, "", 3);
329 m_xPrefBox->set_sensitive(*m_xScratchIter, true);
332 else
334 // leaf node
335 OUString sPropertyName = item;
336 auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
337 [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool
339 return rEntry.pUserData->sPropertyPath == sPath
340 && rEntry.sStatus == sPropertyName;
344 css::uno::Reference<css::configuration::XReadWriteAccess> m_xReadWriteAccess;
345 m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(
346 ::comphelper::getProcessComponentContext(), "*");
347 beans::Property aProperty;
348 bool bReadOnly = false;
351 aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(sPath + "/"
352 + sPropertyName);
353 bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0;
355 catch (css::beans::UnknownPropertyException)
357 SAL_WARN("cui.options", "unknown property: " << sPath + "/" + sPropertyName);
360 OUString sType = aNode.getValueTypeName();
361 OUStringBuffer sValue;
363 if (it != m_modifiedPrefBoxEntries.end())
364 sValue = it->sValue;
365 else
367 switch( aNode.getValueType().getTypeClass() )
369 case css::uno::TypeClass_VOID:
370 break;
372 case css::uno::TypeClass_BOOLEAN:
373 sValue = OUString::boolean( aNode.get<bool>() );
374 break;
376 case css::uno::TypeClass_SHORT:
377 case css::uno::TypeClass_LONG:
378 case css::uno::TypeClass_HYPER:
379 sValue = OUString::number( aNode.get<sal_Int64>() );
380 break;
382 case css::uno::TypeClass_DOUBLE:
383 sValue = OUString::number( aNode.get<double>() );
384 break;
386 case css::uno::TypeClass_STRING:
387 sValue = aNode.get<OUString>();
388 break;
390 case css::uno::TypeClass_SEQUENCE:
391 if( sType == "[]boolean" )
393 uno::Sequence<sal_Bool> seq = aNode.get< uno::Sequence<sal_Bool> >();
394 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
396 if( j != 0 )
398 sValue.append(",");
400 sValue.append(OUString::boolean( seq[j] ));
403 else if( sType == "[]byte" )
405 const uno::Sequence<sal_Int8> seq = aNode.get< uno::Sequence<sal_Int8> >();
406 for( sal_Int8 j : seq )
408 OUString s = OUString::number(
409 static_cast<sal_uInt8>(j), 16 );
410 if( s.getLength() == 1 )
412 sValue.append("0");
414 sValue.append(s.toAsciiUpperCase());
417 else if( sType == "[][]byte" )
419 const uno::Sequence< uno::Sequence<sal_Int8> > seq = aNode.get< uno::Sequence< uno::Sequence<sal_Int8> > >();
420 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
422 if( j != 0 )
424 sValue.append(",");
426 for( sal_Int8 k : seq[j] )
428 OUString s = OUString::number(
429 static_cast<sal_uInt8>(k), 16 );
430 if( s.getLength() == 1 )
432 sValue.append("0");
434 sValue.append(s.toAsciiUpperCase());
438 else if( sType == "[]short" )
440 uno::Sequence<sal_Int16> seq = aNode.get< uno::Sequence<sal_Int16> >();
441 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
443 if( j != 0 )
445 sValue.append(",");
447 sValue.append( static_cast<sal_Int32>(seq[j]) );
450 else if( sType == "[]long" )
452 uno::Sequence<sal_Int32> seq = aNode.get< uno::Sequence<sal_Int32> >();
453 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
455 if( j != 0 )
457 sValue.append(",");
459 sValue.append( seq[j] );
462 else if( sType == "[]hyper" )
464 uno::Sequence<sal_Int64> seq = aNode.get< uno::Sequence<sal_Int64> >();
465 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
467 if( j != 0 )
469 sValue.append(",");
471 sValue.append( seq[j] );
474 else if( sType == "[]double" )
476 uno::Sequence<double> seq = aNode.get< uno::Sequence<double> >();
477 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
479 if( j != 0 )
481 sValue.append(",");
483 sValue.append( seq[j] );
486 else if( sType == "[]string" )
488 uno::Sequence<OUString> seq = aNode.get< uno::Sequence<OUString> >();
489 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
491 if( j != 0 )
493 sValue.append(",");
495 sValue.append(seq[j]);
498 else
500 SAL_WARN(
501 "cui.options",
502 "path \"" << sPath << "\" member " << item
503 << " of unsupported type " << sType);
505 break;
507 default:
508 SAL_WARN(
509 "cui.options",
510 "path \"" << sPath << "\" member " << item
511 << " of unsupported type " << sType);
512 break;
516 //Short name
517 int index = 0;
518 for(int j = 1; j < lineage; ++j)
519 index = sPath.indexOf("/", index + 1);
521 InsertEntry(sPath, sPath.copy(index + 1), item, sType, sValue.makeStringAndClear(),
522 pParentEntry, !bLoadAll, bReadOnly);
527 Reference< XNameAccess > CuiAboutConfigTabPage::getConfigAccess( const OUString& sNodePath, bool bUpdate )
529 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
531 uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
532 css::configuration::theDefaultProvider::get( xContext ) );
534 beans::NamedValue aProperty;
535 aProperty.Name = "nodepath";
536 aProperty.Value <<= sNodePath;
538 uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) };
540 OUString sAccessString;
542 if( bUpdate )
543 sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
544 else
545 sAccessString = "com.sun.star.configuration.ConfigurationAccess";
547 uno::Reference< container::XNameAccess > xNameAccess(
548 xConfigProvider->createInstanceWithArguments(
549 sAccessString, aArgumentList ),
550 uno::UNO_QUERY_THROW );
552 return xNameAccess;
555 void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr< Prop_Impl >& rProp )
557 bool isModifiedBefore = false;
558 //Check if value modified before
559 for(std::shared_ptr<Prop_Impl> & nInd : m_vectorOfModified)
561 if( rProp->Name == nInd->Name && rProp->Property == nInd->Property )
563 //property modified before. Assign reference to the modified value
564 //do your changes on this object. They will be saved later.
565 nInd = rProp;
566 isModifiedBefore = true;
567 break;
571 if( !isModifiedBefore )
572 m_vectorOfModified.push_back( rProp );
573 //property is not modified before
576 std::vector< OUString > CuiAboutConfigTabPage::commaStringToSequence( std::u16string_view rCommaSepString )
578 std::vector<OUString> tempVector;
580 sal_Int32 index = 0;
583 OUString word( o3tl::getToken(rCommaSepString, 0, u',', index) );
584 word = word.trim();
585 if( !word.isEmpty())
586 tempVector.push_back(word);
587 }while( index >= 0 );
588 return tempVector;
591 CuiAboutConfigValueDialog::CuiAboutConfigValueDialog(weld::Window* pWindow,
592 const OUString& rValue,
593 int limit)
594 : GenericDialogController(pWindow, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog")
595 , m_bNumericOnly(limit != 0)
596 , m_xEDValue(m_xBuilder->weld_entry("valuebox"))
598 if (limit)
599 m_xEDValue->set_max_length(limit);
600 m_xEDValue->set_text(rValue);
601 m_xEDValue->connect_key_press(LINK(this, CuiAboutConfigValueDialog, KeyInputHdl));
604 CuiAboutConfigValueDialog::~CuiAboutConfigValueDialog()
608 IMPL_LINK_NOARG( CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void )
610 Reset();
613 IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool)
615 StandardHdl_Impl(*m_xEditBtn);
616 return true;
619 IMPL_LINK_NOARG( CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void )
621 if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
622 return;
624 UserData *pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(*m_xScratchIter));
625 if (!pUserData || !pUserData->bIsPropertyPath || pUserData->bIsReadOnly)
626 return;
628 //if selection is a node
629 OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1);
630 OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2);
631 OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3);
633 // If the configuration property has a nil value, determine its static type:
634 if (sPropertyType == "void")
636 css::uno::Reference<css::beans::XPropertySetInfo> info(
637 CuiAboutConfigTabPage::getConfigAccess(pUserData->sPropertyPath, false),
638 css::uno::UNO_QUERY_THROW);
639 css::uno::Type t;
640 try {
641 t = info->getPropertyByName(sPropertyName).Type;
642 } catch (css::beans::UnknownPropertyException &) {
643 TOOLS_WARN_EXCEPTION("cui.options", pUserData->sPropertyPath << " " << sPropertyName);
645 // If the configuration property is of type any (or an UnknownPropertyException was caught
646 // above), stick to "void" for now (ideally, properties of type any would allow setting
647 // values of arbitrary type, regardless of their current value, in this dialog anyway):
648 if (t != cppu::UnoType<void>::get()) {
649 sPropertyType = t.getTypeName();
650 switch (t.getTypeClass()) {
651 case css::uno::TypeClass_BOOLEAN:
652 sPropertyValue = "false";
653 break;
654 case css::uno::TypeClass_SHORT:
655 case css::uno::TypeClass_LONG:
656 case css::uno::TypeClass_HYPER:
657 case css::uno::TypeClass_DOUBLE:
658 sPropertyValue = "0";
659 break;
660 default:
661 break;
666 auto pProperty = std::make_shared<Prop_Impl>( pUserData->sPropertyPath, sPropertyName, Any( sPropertyValue ) );
667 bool bSaveChanges = false;
669 bool bOpenDialog = true;
670 OUString sDialogValue;
672 if( sPropertyType == "boolean" )
674 bool bValue;
675 if( sPropertyValue == "true" )
677 sDialogValue = "false";
678 bValue = false;
680 else
682 sDialogValue = "true";
683 bValue = true;
686 pProperty->Value <<= bValue;
687 bOpenDialog = false;
688 bSaveChanges = true;
690 else if ( sPropertyType == "void" )
692 bOpenDialog = false;
694 else
696 sDialogValue = sPropertyValue;
697 bOpenDialog = true;
702 if( bOpenDialog )
704 //Cosmetic length limit for integer values.
705 int limit=0;
706 if( sPropertyType == "short" )
707 limit = SHORT_LEN_LIMIT;
708 else if( sPropertyType == "long" )
709 limit = LONG_LEN_LIMIT;
710 else if( sPropertyType == "hyper" )
711 limit = HYPER_LEN_LIMIT;
713 CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit);
715 if (aValueDialog.run() == RET_OK )
717 OUString sNewValue = aValueDialog.getValue();
718 bSaveChanges = true;
719 if ( sPropertyType == "short")
721 sal_Int16 nShort;
722 sal_Int32 nNumb = sNewValue.toInt32();
724 //if the value is 0 and length is not 1, there is something wrong
725 if( ( nNumb==0 && sNewValue.getLength()!=1 ) || nNumb > SAL_MAX_INT16 || nNumb < SAL_MIN_INT16)
726 throw uno::Exception("out of range short", nullptr);
727 nShort = static_cast<sal_Int16>(nNumb);
728 pProperty->Value <<= nShort;
730 else if( sPropertyType == "long" )
732 sal_Int32 nLong = sNewValue.toInt32();
733 if( nLong==0 && sNewValue.getLength()!=1)
734 throw uno::Exception("out of range long", nullptr);
735 pProperty->Value <<= nLong;
737 else if( sPropertyType == "hyper")
739 sal_Int64 nHyper = sNewValue.toInt64();
740 if( nHyper==0 && sNewValue.getLength()!=1)
741 throw uno::Exception("out of range hyper", nullptr);
742 pProperty->Value <<= nHyper;
744 else if( sPropertyType == "double")
746 double nDoub = sNewValue.toDouble();
747 if( nDoub ==0 && sNewValue.getLength()!=1)
748 throw uno::Exception("out of range double", nullptr);
749 pProperty->Value <<= nDoub;
751 else if( sPropertyType == "float")
753 float nFloat = sNewValue.toFloat();
754 if( nFloat ==0 && sNewValue.getLength()!=1)
755 throw uno::Exception("out of range float", nullptr);
756 pProperty->Value <<= nFloat;
758 else if( sPropertyType == "string" )
760 pProperty->Value <<= sNewValue;
762 else if( sPropertyType == "[]short" )
764 //create string sequence from comma separated string
765 //uno::Sequence< OUString > seqStr;
766 std::vector< OUString > seqStr = commaStringToSequence( sNewValue );
768 //create appropriate sequence with same size as string sequence
769 uno::Sequence< sal_Int16 > seqShort( seqStr.size() );
770 //convert all strings to appropriate type
771 std::transform(seqStr.begin(), seqStr.end(), seqShort.getArray(),
772 [](const auto& str)
773 { return static_cast<sal_Int16>(str.toInt32()); });
774 pProperty->Value <<= seqShort;
776 else if( sPropertyType == "[]long" )
778 std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue );
780 uno::Sequence< sal_Int32 > seqLong( seqStrLong.size() );
781 std::transform(seqStrLong.begin(), seqStrLong.end(), seqLong.getArray(),
782 [](const auto& str) { return str.toInt32(); });
783 pProperty->Value <<= seqLong;
785 else if( sPropertyType == "[]hyper" )
787 std::vector< OUString > seqStrHyper = commaStringToSequence( sNewValue );
788 uno::Sequence< sal_Int64 > seqHyper( seqStrHyper.size() );
789 std::transform(seqStrHyper.begin(), seqStrHyper.end(), seqHyper.getArray(),
790 [](const auto& str) { return str.toInt64(); });
791 pProperty->Value <<= seqHyper;
793 else if( sPropertyType == "[]double" )
795 std::vector< OUString > seqStrDoub = commaStringToSequence( sNewValue );
796 uno::Sequence< double > seqDoub( seqStrDoub.size() );
797 std::transform(seqStrDoub.begin(), seqStrDoub.end(), seqDoub.getArray(),
798 [](const auto& str) { return str.toDouble(); });
799 pProperty->Value <<= seqDoub;
801 else if( sPropertyType == "[]float" )
803 std::vector< OUString > seqStrFloat = commaStringToSequence( sNewValue );
804 uno::Sequence< sal_Int16 > seqFloat( seqStrFloat.size() );
805 std::transform(seqStrFloat.begin(), seqStrFloat.end(), seqFloat.getArray(),
806 [](const auto& str) { return str.toFloat(); });
807 pProperty->Value <<= seqFloat;
809 else if( sPropertyType == "[]string" )
811 pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue ));
813 else //unknown
814 throw uno::Exception("unknown property type " + sPropertyType, nullptr);
816 sDialogValue = sNewValue;
820 if(bSaveChanges)
822 AddToModifiedVector( pProperty );
824 //update listbox value.
825 m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2);
826 m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
827 //update m_prefBoxEntries
828 auto it = std::find_if(m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
829 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
831 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
832 && rEntry.sStatus == sPropertyName;
835 if (it != m_prefBoxEntries.end())
837 it->sValue = sDialogValue;
839 auto modifiedIt = std::find_if(
840 m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
841 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
843 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
844 && rEntry.sStatus == sPropertyName;
848 if (modifiedIt != m_modifiedPrefBoxEntries.end())
850 modifiedIt->sValue = sDialogValue;
852 else
854 m_modifiedPrefBoxEntries.push_back(*it);
859 catch( uno::Exception& )
864 IMPL_LINK_NOARG( CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void)
866 weld::WaitObject aWait(m_xDialog.get());
868 m_xPrefBox->hide();
869 m_xPrefBox->clear();
870 m_xPrefBox->freeze();
872 if (m_bSorted)
873 m_xPrefBox->make_unsorted();
875 if (m_xSearchEdit->get_text().isEmpty())
877 m_xPrefBox->clear();
878 Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
879 FillItems( xConfigAccess );
881 else
883 m_options.searchString = m_xSearchEdit->get_text();
884 utl::TextSearch textSearch( m_options );
885 for (auto const& it : m_prefBoxEntries)
887 sal_Int32 endPos, startPos = 0;
889 for(size_t i = 0; i < 5; ++i)
891 OUString scrTxt;
893 if (i == 0)
894 scrTxt = it.pUserData->sPropertyPath;
895 else if (i == 1)
896 scrTxt = it.sProp;
897 else if (i == 2)
898 scrTxt = it.sStatus;
899 else if (i == 3)
900 scrTxt = it.sType;
901 else if (i == 4)
902 scrTxt = it.sValue;
904 endPos = scrTxt.getLength();
905 if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
907 InsertEntry(it);
908 break;
914 m_xPrefBox->thaw();
915 if (m_bSorted)
916 m_xPrefBox->make_sorted();
918 m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
919 m_xPrefBox->expand_row(rEntry);
920 return false;
922 m_xPrefBox->show();
925 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry)
927 OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
928 sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
929 OUString sPath = sPathWithProperty.copy(0, index);
930 index = 0;
931 std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator());
932 std::unique_ptr<weld::TreeIter> xGrandParentEntry;
936 int prevIndex = index;
937 index = sPath.indexOf("/", index+1);
938 // deal with no parent case (tdf#107811)
939 if (index < 0)
941 OUString sId(weld::toId(rEntry.pUserData));
942 m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
943 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
944 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
945 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
946 m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
947 return;
949 OUString sParentName = sPath.copy(prevIndex+1, index - prevIndex - 1);
951 bool hasEntry = false;
952 bool bStartOk;
954 if (!xGrandParentEntry)
955 bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
956 else
958 m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
959 bStartOk = m_xPrefBox->iter_children(*xParentEntry);
962 if (bStartOk)
966 if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
968 hasEntry = true;
969 break;
971 } while (m_xPrefBox->iter_next_sibling(*xParentEntry));
974 if (!hasEntry)
976 m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr, false, xParentEntry.get());
977 //It is needed, without this the selection line will be truncated.
978 m_xPrefBox->set_text(*xParentEntry, "", 1);
979 m_xPrefBox->set_text(*xParentEntry, "", 2);
980 m_xPrefBox->set_text(*xParentEntry, "", 3);
981 m_xPrefBox->set_sensitive(*xParentEntry, true);
984 xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
985 } while(index < sPath.getLength() - 1);
987 OUString sId(weld::toId(rEntry.pUserData));
988 m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, false, m_xScratchIter.get());
989 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
990 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
991 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
992 m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
995 IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
997 if (m_xPrefBox->iter_has_child(rEntry))
998 return true;
999 UserData *pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rEntry));
1000 if (pUserData && !pUserData->bIsPropertyPath)
1002 assert(pUserData->aXNameAccess.is());
1003 FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
1005 return true;
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */