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/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>
35#include <utility>
36#include <vcl/event.hxx>
37#include <sal/log.hxx>
39
40#include <dialmgr.hxx>
41#include <strings.hrc>
42
43#include <algorithm>
44#include <memory>
45#include <vector>
46
47using namespace ::com::sun::star;
48using namespace com::sun::star::uno;
49using namespace com::sun::star::container;
50
51#define SHORT_LEN_LIMIT 7
52#define LONG_LEN_LIMIT 11
53#define HYPER_LEN_LIMIT 20
54
56{
57 OUString Name;
58 OUString Property;
60
61 Prop_Impl( OUString sName, OUString sProperty, Any aValue )
62 : Name(std::move( sName ))
63 , Property(std::move( sProperty ))
64 , Value(std::move( aValue ))
65 {}
66};
67
68struct UserData
69{
70 bool bIsPropertyPath;
71 bool bIsReadOnly;
72 OUString sPropertyPath;
73 int aLineage;
74 Reference<XNameAccess> aXNameAccess;
75
76 explicit UserData( OUString aPropertyPath, bool isReadOnly )
77 : bIsPropertyPath( true )
78 , bIsReadOnly( isReadOnly )
79 , sPropertyPath(std::move(aPropertyPath))
80 , aLineage(0)
81 {}
82
83 explicit UserData( Reference<XNameAccess> const & rXNameAccess, int rIndex )
84 : bIsPropertyPath( false )
85 , bIsReadOnly( false )
86 , aLineage(rIndex)
87 , aXNameAccess( rXNameAccess )
88 {}
89};
90
91IMPL_LINK(CuiAboutConfigValueDialog, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
92{
93 bool bValid = false;
94 bool bNonSpace = rKeyEvent.GetKeyCode().GetCode() != KEY_SPACE;
95 if (m_bNumericOnly && bNonSpace )
96 {
97 const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
98 sal_uInt16 nGroup = rKeyCode.GetGroup();
99 sal_uInt16 nKey = rKeyCode.GetCode();
100
101 switch ( nGroup ) {
102 case KEYGROUP_NUM :
103 case KEYGROUP_CURSOR :
104 {
105 bValid = true;
106 break;
107 }
108
109 case KEYGROUP_MISC :
110 {
111 switch ( nKey ) {
112 case KEY_SUBTRACT :
113 case KEY_COMMA :
114 case KEY_POINT :
115 {
116 bValid = true;
117 break;
118 }
119
120 default :
121 {
122 if( nKey < KEY_ADD || nKey > KEY_EQUAL )
123 bValid = true;
124 break;
125 }
126 }
127 break;
128 }
129
130 default :
131 {
132 bValid = false;
133 break;
134 }
135 }
136
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;
141 }
142 else
143 bValid = true;
144
145 //if value return true to claim that it has been handled
146 return !bValid;
147}
148
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)
158{
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));
162
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));
168
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);
173
174 float fWidth = m_xPrefBox->get_approximate_digit_width();
175 std::vector<int> aWidths
176 {
177 o3tl::narrowing<int>(fWidth * 65),
178 o3tl::narrowing<int>(fWidth * 20),
179 o3tl::narrowing<int>(fWidth * 8)
180 };
181 m_xPrefBox->set_column_fixed_widths(aWidths);
182
183 m_xPrefBox->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage, QueryTooltip));
184}
185
186IMPL_LINK(CuiAboutConfigTabPage, QueryTooltip, const weld::TreeIter&, rIter, OUString)
187{
188 UserData *pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rIter));
189 if (pUserData && pUserData->bIsReadOnly)
190 {
191 return CuiResId(RID_CUISTR_OPT_READONLY);
192 }
193
194 return OUString();
195}
196
197IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void)
198{
199 if (!m_bSorted)
200 {
201 m_xPrefBox->make_sorted();
202 m_bSorted = true;
203 }
204
205 bool bSortAtoZ = m_xPrefBox->get_sort_order();
206
207 //set new arrow positions in headerbar
208 if (nColumn == m_xPrefBox->get_sort_column())
209 {
210 bSortAtoZ = !bSortAtoZ;
211 m_xPrefBox->set_sort_order(bSortAtoZ);
212 }
213 else
214 {
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);
219 }
220
221 if (nColumn != -1)
222 {
223 //sort lists
224 m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
225 }
226}
227
229{
230}
231
232void 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)
235{
236 m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, bIsReadOnly));
237 if (bInsertToPrefBox)
238 {
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);
245 }
246 else
247 {
248 m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()});
249 }
250}
251
253{
254 weld::WaitObject aWait(m_xDialog.get());
255
256 m_xPrefBox->clear();
257 m_vectorOfModified.clear();
258 if (m_bSorted)
259 {
260 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
261 m_xPrefBox->make_unsorted();
262 m_bSorted = false;
263 }
264 m_prefBoxEntries.clear();
266
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();
274}
275
277{
278 std::vector< std::shared_ptr< Prop_Impl > >::iterator pIter;
279 for( pIter = m_vectorOfModified.begin() ; pIter != m_vectorOfModified.end(); ++pIter )
280 {
281 Reference< XNameAccess > xUpdateAccess = getConfigAccess( (*pIter)->Name , true );
282 Reference< XNameReplace > xNameReplace( xUpdateAccess, UNO_QUERY_THROW );
283
284 xNameReplace->replaceByName( (*pIter)->Property, (*pIter)->Value );
285
286 Reference< util::XChangesBatch > xChangesBatch( xUpdateAccess, UNO_QUERY_THROW );
287 xChangesBatch->commitChanges();
288 }
289}
290
292 int lineage, bool bLoadAll)
293{
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 )
298 {
299 Any aNode = xNameAccess->getByName( item );
300
301 bool bNotLeaf = false;
302
303 Reference< XNameAccess > xNextNameAccess;
304 try
305 {
306 xNextNameAccess.set(aNode, uno::UNO_QUERY);
307 bNotLeaf = xNextNameAccess.is();
308 }
309 catch (const RuntimeException&)
310 {
311 TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage");
312 }
313
314 if (bNotLeaf)
315 {
316 if(bLoadAll)
317 FillItems(xNextNameAccess, nullptr, lineage + 1, true);
318 else
319 {
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()));
323
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);
330 }
331 }
332 else
333 {
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
338 {
339 return rEntry.pUserData->sPropertyPath == sPath
340 && rEntry.sStatus == sPropertyName;
341 }
342 );
343
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;
349 try
350 {
351 aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(sPath + "/"
352 + sPropertyName);
353 bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0;
354 }
355 catch (css::beans::UnknownPropertyException)
356 {
357 SAL_WARN("cui.options", "unknown property: " << sPath + "/" + sPropertyName);
358 }
359
360 OUString sType = aNode.getValueTypeName();
361 OUStringBuffer sValue;
362
363 if (it != m_modifiedPrefBoxEntries.end())
364 sValue = it->sValue;
365 else
366 {
367 switch( aNode.getValueType().getTypeClass() )
368 {
369 case css::uno::TypeClass_VOID:
370 break;
371
372 case css::uno::TypeClass_BOOLEAN:
373 sValue = OUString::boolean( aNode.get<bool>() );
374 break;
375
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;
381
382 case css::uno::TypeClass_DOUBLE:
383 sValue = OUString::number( aNode.get<double>() );
384 break;
385
386 case css::uno::TypeClass_STRING:
387 sValue = aNode.get<OUString>();
388 break;
389
390 case css::uno::TypeClass_SEQUENCE:
391 if( sType == "[]boolean" )
392 {
394 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
395 {
396 if( j != 0 )
397 {
398 sValue.append(",");
399 }
400 sValue.append(OUString::boolean( seq[j] ));
401 }
402 }
403 else if( sType == "[]byte" )
404 {
405 const uno::Sequence<sal_Int8> seq = aNode.get< uno::Sequence<sal_Int8> >();
406 for( sal_Int8 j : seq )
407 {
408 OUString s = OUString::number(
409 static_cast<sal_uInt8>(j), 16 );
410 if( s.getLength() == 1 )
411 {
412 sValue.append("0");
413 }
414 sValue.append(s.toAsciiUpperCase());
415 }
416 }
417 else if( sType == "[][]byte" )
418 {
420 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
421 {
422 if( j != 0 )
423 {
424 sValue.append(",");
425 }
426 for( sal_Int8 k : seq[j] )
427 {
428 OUString s = OUString::number(
429 static_cast<sal_uInt8>(k), 16 );
430 if( s.getLength() == 1 )
431 {
432 sValue.append("0");
433 }
434 sValue.append(s.toAsciiUpperCase());
435 }
436 }
437 }
438 else if( sType == "[]short" )
439 {
441 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
442 {
443 if( j != 0 )
444 {
445 sValue.append(",");
446 }
447 sValue.append( static_cast<sal_Int32>(seq[j]) );
448 }
449 }
450 else if( sType == "[]long" )
451 {
453 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
454 {
455 if( j != 0 )
456 {
457 sValue.append(",");
458 }
459 sValue.append( seq[j] );
460 }
461 }
462 else if( sType == "[]hyper" )
463 {
465 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
466 {
467 if( j != 0 )
468 {
469 sValue.append(",");
470 }
471 sValue.append( seq[j] );
472 }
473 }
474 else if( sType == "[]double" )
475 {
476 uno::Sequence<double> seq = aNode.get< uno::Sequence<double> >();
477 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
478 {
479 if( j != 0 )
480 {
481 sValue.append(",");
482 }
483 sValue.append( seq[j] );
484 }
485 }
486 else if( sType == "[]string" )
487 {
489 for( sal_Int32 j = 0; j != seq.getLength(); ++j )
490 {
491 if( j != 0 )
492 {
493 sValue.append(",");
494 }
495 sValue.append(seq[j]);
496 }
497 }
498 else
499 {
500 SAL_WARN(
501 "cui.options",
502 "path \"" << sPath << "\" member " << item
503 << " of unsupported type " << sType);
504 }
505 break;
506
507 default:
508 SAL_WARN(
509 "cui.options",
510 "path \"" << sPath << "\" member " << item
511 << " of unsupported type " << sType);
512 break;
513 }
514 }
515
516 //Short name
517 int index = 0;
518 for(int j = 1; j < lineage; ++j)
519 index = sPath.indexOf("/", index + 1);
520
521 InsertEntry(sPath, sPath.copy(index + 1), item, sType, sValue.makeStringAndClear(),
522 pParentEntry, !bLoadAll, bReadOnly);
523 }
524 }
525}
526
527Reference< XNameAccess > CuiAboutConfigTabPage::getConfigAccess( const OUString& sNodePath, bool bUpdate )
528{
529 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
530
532 css::configuration::theDefaultProvider::get( xContext ) );
533
534 beans::NamedValue aProperty;
535 aProperty.Name = "nodepath";
536 aProperty.Value <<= sNodePath;
537
538 uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) };
539
540 OUString sAccessString;
541
542 if( bUpdate )
543 sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
544 else
545 sAccessString = "com.sun.star.configuration.ConfigurationAccess";
546
548 xConfigProvider->createInstanceWithArguments(
549 sAccessString, aArgumentList ),
550 uno::UNO_QUERY_THROW );
551
552 return xNameAccess;
553}
554
555void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr< Prop_Impl >& rProp )
556{
557 bool isModifiedBefore = false;
558 //Check if value modified before
559 for(std::shared_ptr<Prop_Impl> & nInd : m_vectorOfModified)
560 {
561 if( rProp->Name == nInd->Name && rProp->Property == nInd->Property )
562 {
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;
568 }
569 }
570
571 if( !isModifiedBefore )
572 m_vectorOfModified.push_back( rProp );
573 //property is not modified before
574}
575
576std::vector< OUString > CuiAboutConfigTabPage::commaStringToSequence( std::u16string_view rCommaSepString )
577{
578 std::vector<OUString> tempVector;
579
580 sal_Int32 index = 0;
581 do
582 {
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;
589}
590
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"))
597{
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));
602}
603
605{
606}
607
609{
610 Reset();
611}
612
614{
615 StandardHdl_Impl(*m_xEditBtn);
616 return true;
617}
618
620{
621 if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
622 return;
623
624 UserData *pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(*m_xScratchIter));
625 if (!pUserData || !pUserData->bIsPropertyPath || pUserData->bIsReadOnly)
626 return;
627
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);
632
633 // If the configuration property has a nil value, determine its static type:
634 if (sPropertyType == "void")
635 {
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);
644 }
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;
662 }
663 }
664 }
665
666 auto pProperty = std::make_shared<Prop_Impl>( pUserData->sPropertyPath, sPropertyName, Any( sPropertyValue ) );
667 bool bSaveChanges = false;
668
669 bool bOpenDialog = true;
670 OUString sDialogValue;
671
672 if( sPropertyType == "boolean" )
673 {
674 bool bValue;
675 if( sPropertyValue == "true" )
676 {
677 sDialogValue = "false";
678 bValue = false;
679 }
680 else
681 {
682 sDialogValue = "true";
683 bValue = true;
684 }
685
686 pProperty->Value <<= bValue;
687 bOpenDialog = false;
688 bSaveChanges = true;
689 }
690 else if ( sPropertyType == "void" )
691 {
692 bOpenDialog = false;
693 }
694 else
695 {
696 sDialogValue = sPropertyValue;
697 bOpenDialog = true;
698 }
699
700 try
701 {
702 if( bOpenDialog )
703 {
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;
712
713 CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit);
714
715 if (aValueDialog.run() == RET_OK )
716 {
717 OUString sNewValue = aValueDialog.getValue();
718 bSaveChanges = true;
719 if ( sPropertyType == "short")
720 {
721 sal_Int16 nShort;
722 sal_Int32 nNumb = sNewValue.toInt32();
723
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;
729 }
730 else if( sPropertyType == "long" )
731 {
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;
736 }
737 else if( sPropertyType == "hyper")
738 {
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;
743 }
744 else if( sPropertyType == "double")
745 {
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;
750 }
751 else if( sPropertyType == "float")
752 {
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;
757 }
758 else if( sPropertyType == "string" )
759 {
760 pProperty->Value <<= sNewValue;
761 }
762 else if( sPropertyType == "[]short" )
763 {
764 //create string sequence from comma separated string
765 //uno::Sequence< OUString > seqStr;
766 std::vector< OUString > seqStr = commaStringToSequence( sNewValue );
767
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;
775 }
776 else if( sPropertyType == "[]long" )
777 {
778 std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue );
779
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;
784 }
785 else if( sPropertyType == "[]hyper" )
786 {
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;
792 }
793 else if( sPropertyType == "[]double" )
794 {
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;
800 }
801 else if( sPropertyType == "[]float" )
802 {
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;
808 }
809 else if( sPropertyType == "[]string" )
810 {
811 pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue ));
812 }
813 else //unknown
814 throw uno::Exception("unknown property type " + sPropertyType, nullptr);
815
816 sDialogValue = sNewValue;
817 }
818 }
819
820 if(bSaveChanges)
821 {
822 AddToModifiedVector( pProperty );
823
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
830 {
831 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
832 && rEntry.sStatus == sPropertyName;
833 }
834 );
835 if (it != m_prefBoxEntries.end())
836 {
837 it->sValue = sDialogValue;
838
839 auto modifiedIt = std::find_if(
840 m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
841 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool
842 {
843 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
844 && rEntry.sStatus == sPropertyName;
845 }
846 );
847
848 if (modifiedIt != m_modifiedPrefBoxEntries.end())
849 {
850 modifiedIt->sValue = sDialogValue;
851 }
852 else
853 {
854 m_modifiedPrefBoxEntries.push_back(*it);
855 }
856 }
857 }
858 }
859 catch( uno::Exception& )
860 {
861 }
862}
863
865{
866 weld::WaitObject aWait(m_xDialog.get());
867
868 m_xPrefBox->hide();
869 m_xPrefBox->clear();
870 m_xPrefBox->freeze();
871
872 if (m_bSorted)
873 m_xPrefBox->make_unsorted();
874
875 if (m_xSearchEdit->get_text().isEmpty())
876 {
877 m_xPrefBox->clear();
878 Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false );
879 FillItems( xConfigAccess );
880 }
881 else
882 {
883 m_options.searchString = m_xSearchEdit->get_text();
884 utl::TextSearch textSearch( m_options );
885 for (auto const& it : m_prefBoxEntries)
886 {
887 sal_Int32 endPos, startPos = 0;
888
889 for(size_t i = 0; i < 5; ++i)
890 {
891 OUString scrTxt;
892
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;
903
904 endPos = scrTxt.getLength();
905 if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
906 {
907 InsertEntry(it);
908 break;
909 }
910 }
911 }
912 }
913
914 m_xPrefBox->thaw();
915 if (m_bSorted)
916 m_xPrefBox->make_sorted();
917
918 m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
919 m_xPrefBox->expand_row(rEntry);
920 return false;
921 });
922 m_xPrefBox->show();
923}
924
926{
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;
933
934 do
935 {
936 int prevIndex = index;
937 index = sPath.indexOf("/", index+1);
938 // deal with no parent case (tdf#107811)
939 if (index < 0)
940 {
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;
948 }
949 OUString sParentName = sPath.copy(prevIndex+1, index - prevIndex - 1);
950
951 bool hasEntry = false;
952 bool bStartOk;
953
954 if (!xGrandParentEntry)
955 bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
956 else
957 {
958 m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
959 bStartOk = m_xPrefBox->iter_children(*xParentEntry);
960 }
961
962 if (bStartOk)
963 {
964 do
965 {
966 if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
967 {
968 hasEntry = true;
969 break;
970 }
971 } while (m_xPrefBox->iter_next_sibling(*xParentEntry));
972 }
973
974 if (!hasEntry)
975 {
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);
982 }
983
984 xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
985 } while(index < sPath.getLength() - 1);
986
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);
993}
994
995IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
996{
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)
1001 {
1002 assert(pUserData->aXNameAccess.is());
1003 FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
1004 }
1005 return true;
1006}
1007
1008/* 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
OUString CuiResId(TranslateId aKey)
Definition: cuiresmgr.cxx:23
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
OUString sName
bool bReadOnly
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)
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