Use correct object
[LibreOffice.git] / cui / source / options / optaboutconfig.cxx
blob9480b2de5e8fbc744da4a4e767d0c17d00d675c8
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 "optaboutconfig.hxx"
11 #include <o3tl/safeint.hxx>
12 #include <o3tl/string_view.hxx>
14 #include <com/sun/star/beans/NamedValue.hpp>
15 #include <com/sun/star/beans/PropertyAttribute.hpp>
16 #include <com/sun/star/beans/UnknownPropertyException.hpp>
17 #include <com/sun/star/beans/XPropertySetInfo.hpp>
18 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
19 #include <com/sun/star/configuration/XDocumentation.hpp>
20 #include <com/sun/star/configuration/theDefaultProvider.hpp>
21 #include <com/sun/star/container/XHierarchicalName.hpp>
22 #include <com/sun/star/container/XNameAccess.hpp>
23 #include <com/sun/star/container/XNameReplace.hpp>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/uno/Reference.hxx>
26 #include <com/sun/star/uno/Type.hxx>
27 #include <com/sun/star/uno/TypeClass.hpp>
28 #include <com/sun/star/util/InvalidStateException.hpp>
29 #include <com/sun/star/util/SearchAlgorithms2.hpp>
30 #include <com/sun/star/util/SearchFlags.hpp>
31 #include <com/sun/star/util/XChangesBatch.hpp>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/sequence.hxx>
35 #include <cppu/unotype.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <sal/log.hxx>
38 #include <unotools/textsearch.hxx>
39 #include <utility>
40 #include <vcl/event.hxx>
42 #include <dialmgr.hxx>
43 #include <strings.hrc>
45 #include <algorithm>
46 #include <memory>
47 #include <vector>
49 using namespace ::com::sun::star;
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::container;
53 struct Prop_Impl
55 OUString Name;
56 OUString Property;
57 Any Value;
59 Prop_Impl(OUString sName, OUString sProperty, Any aValue)
60 : Name(std::move(sName))
61 , Property(std::move(sProperty))
62 , Value(std::move(aValue))
67 struct UserData
69 bool bIsPropertyPath;
70 bool bIsReadOnly;
71 bool bWasModified;
72 OUString sPropertyPath;
73 Any aPropertyValue;
74 OUString sTooltip;
75 int aLineage;
76 Reference<XNameAccess> aXNameAccess;
78 explicit UserData(OUString aPropertyPath, Any aPropValue, OUString aTooltip, bool isReadOnly,
79 bool wasModified)
80 : bIsPropertyPath(true)
81 , bIsReadOnly(isReadOnly)
82 , bWasModified(wasModified)
83 , sPropertyPath(std::move(aPropertyPath))
84 , aPropertyValue(aPropValue)
85 , sTooltip(std::move(aTooltip))
86 , aLineage(0)
90 explicit UserData(Reference<XNameAccess> const& rXNameAccess, int rIndex)
91 : bIsPropertyPath(false)
92 , bIsReadOnly(false)
93 , bWasModified(false)
94 , aLineage(rIndex)
95 , aXNameAccess(rXNameAccess)
100 CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent)
101 : GenericDialogController(pParent, u"cui/ui/aboutconfigdialog.ui"_ustr, u"AboutConfig"_ustr)
102 , m_xResetBtn(m_xBuilder->weld_button(u"reset"_ustr))
103 , m_xEditBtn(m_xBuilder->weld_button(u"edit"_ustr))
104 , m_xSearchBtn(m_xBuilder->weld_button(u"searchButton"_ustr))
105 , m_xModifiedCheckBtn(m_xBuilder->weld_check_button(u"modifiedButton"_ustr))
106 , m_xSearchEdit(m_xBuilder->weld_entry(u"searchEntry"_ustr))
107 , m_xPrefBox(m_xBuilder->weld_tree_view(u"preferences"_ustr))
108 , m_xScratchIter(m_xPrefBox->make_iterator())
109 , m_bSorted(false)
111 m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100,
112 m_xPrefBox->get_height_rows(23));
113 m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick));
115 m_xEditBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, StandardHdl_Impl));
116 m_xResetBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, ResetBtnHdl_Impl));
117 m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl));
118 m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl));
119 m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl));
120 m_xModifiedCheckBtn->connect_toggled(LINK(this, CuiAboutConfigTabPage, ModifiedHdl_Impl));
122 m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
123 m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
124 m_options.searchFlag
125 |= (util::SearchFlags::REG_NOT_BEGINOFLINE | util::SearchFlags::REG_NOT_ENDOFLINE);
127 float fWidth = m_xPrefBox->get_approximate_digit_width();
128 std::vector<int> aWidths{ o3tl::narrowing<int>(fWidth * 65), o3tl::narrowing<int>(fWidth * 20),
129 o3tl::narrowing<int>(fWidth * 8) };
130 m_xPrefBox->set_column_fixed_widths(aWidths);
132 m_xPrefBox->connect_query_tooltip(LINK(this, CuiAboutConfigTabPage, QueryTooltip));
135 IMPL_LINK(CuiAboutConfigTabPage, QueryTooltip, const weld::TreeIter&, rIter, OUString)
137 UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rIter));
138 OUStringBuffer ret;
139 if (pUserData && pUserData->bIsReadOnly)
141 ret.append(CuiResId(RID_CUISTR_OPT_READONLY));
143 if (pUserData && !pUserData->sTooltip.isEmpty())
145 if (pUserData->bIsReadOnly)
146 ret.append("\n\n");
147 ret.append(pUserData->sTooltip);
150 return ret.makeStringAndClear();
153 IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void)
155 if (!m_bSorted)
157 m_xPrefBox->make_sorted();
158 m_bSorted = true;
161 bool bSortAtoZ = m_xPrefBox->get_sort_order();
163 //set new arrow positions in headerbar
164 if (nColumn == m_xPrefBox->get_sort_column())
166 bSortAtoZ = !bSortAtoZ;
167 m_xPrefBox->set_sort_order(bSortAtoZ);
169 else
171 int nOldSortColumn = m_xPrefBox->get_sort_column();
172 if (nOldSortColumn != -1)
173 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
174 m_xPrefBox->set_sort_column(nColumn);
177 if (nColumn != -1)
179 //sort lists
180 m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
184 IMPL_STATIC_LINK_NOARG(CuiAboutConfigTabPage, ValidNameHdl, SvxNameDialog&, bool)
186 // Allow empty value
187 return true;
190 CuiAboutConfigTabPage::~CuiAboutConfigTabPage() {}
192 void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, Any aPropertyValue,
193 const OUString& rProp, const OUString& rStatus,
194 const OUString& rType, const OUString& rValue,
195 const OUString& rTooltip,
196 const weld::TreeIter* pParentEntry, bool bInsertToPrefBox,
197 bool bIsReadOnly, bool bWasModified)
199 bool bOnlyModified = m_xModifiedCheckBtn->get_active();
200 if (bOnlyModified && !bWasModified)
201 return;
203 m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, aPropertyValue, rTooltip,
204 bIsReadOnly, bWasModified));
205 if (bInsertToPrefBox)
207 OUString sId(weld::toId(m_vectorUserData.back().get()));
208 m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, false,
209 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 m_xPrefBox->set_text_emphasis(*m_xScratchIter, bWasModified, -1);
214 m_xPrefBox->set_sensitive(*m_xScratchIter, !bIsReadOnly, -1);
216 else
218 m_prefBoxEntries.push_back(
219 { rProp, rStatus, rType, rValue, m_vectorUserData.back().get() });
223 void CuiAboutConfigTabPage::InputChanged()
225 weld::WaitObject aWait(m_xDialog.get());
227 m_xPrefBox->hide();
228 m_xPrefBox->clear();
229 m_xPrefBox->freeze();
231 if (m_bSorted)
232 m_xPrefBox->make_unsorted();
234 if (m_xSearchEdit->get_text().isEmpty())
236 m_xPrefBox->clear();
237 Reference<XNameAccess> xConfigAccess = getConfigAccess(u"/"_ustr, false);
238 FillItems(xConfigAccess);
240 else
242 m_options.searchString = m_xSearchEdit->get_text();
243 utl::TextSearch textSearch(m_options);
244 for (auto const& it : m_prefBoxEntries)
246 sal_Int32 endPos, startPos = 0;
248 for (size_t i = 0; i < 5; ++i)
250 OUString scrTxt;
252 if (i == 0)
253 scrTxt = it.pUserData->sPropertyPath;
254 else if (i == 1)
255 scrTxt = it.sProp;
256 else if (i == 2)
257 scrTxt = it.sStatus;
258 else if (i == 3)
259 scrTxt = it.sType;
260 else if (i == 4)
261 scrTxt = it.sValue;
263 endPos = scrTxt.getLength();
264 if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
266 InsertEntry(it);
267 break;
273 m_xPrefBox->thaw();
274 if (m_bSorted)
275 m_xPrefBox->make_sorted();
277 m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
278 m_xPrefBox->expand_row(rEntry);
279 return false;
281 m_xPrefBox->show();
284 void CuiAboutConfigTabPage::Reset()
286 weld::WaitObject aWait(m_xDialog.get());
288 m_xPrefBox->clear();
289 m_vectorOfModified.clear();
290 if (m_bSorted)
292 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column());
293 m_xPrefBox->make_unsorted();
294 m_bSorted = false;
296 m_prefBoxEntries.clear();
297 m_modifiedPrefBoxEntries.clear();
299 m_xPrefBox->freeze();
300 Reference<XNameAccess> xConfigAccess = getConfigAccess(u"/"_ustr, false);
301 //Load all XNameAccess to m_prefBoxEntries
302 FillItems(xConfigAccess, nullptr, 0, true);
303 //Load xConfigAccess' children to m_prefBox
304 FillItems(xConfigAccess);
305 m_xPrefBox->thaw();
308 void CuiAboutConfigTabPage::FillItemSet()
310 std::vector<std::shared_ptr<Prop_Impl>>::iterator pIter;
311 for (pIter = m_vectorOfModified.begin(); pIter != m_vectorOfModified.end(); ++pIter)
313 Reference<XNameAccess> xUpdateAccess = getConfigAccess((*pIter)->Name, true);
314 Reference<XNameReplace> xNameReplace(xUpdateAccess, UNO_QUERY_THROW);
316 xNameReplace->replaceByName((*pIter)->Property, (*pIter)->Value);
318 Reference<util::XChangesBatch> xChangesBatch(xUpdateAccess, UNO_QUERY_THROW);
319 xChangesBatch->commitChanges();
323 namespace
325 OUString lcl_StringListToString(const uno::Sequence<OUString>& seq)
327 OUStringBuffer sBuffer;
328 for (sal_Int32 i = 0; i != seq.getLength(); ++i)
330 if (i != 0)
331 sBuffer.append(",");
332 sBuffer.append(seq[i]);
334 return sBuffer.makeStringAndClear();
337 OUString lcl_IntListToString(const uno::Sequence<sal_Int16>& seq)
339 OUStringBuffer sBuffer;
340 for (sal_Int32 i = 0; i != seq.getLength(); ++i)
342 if (i != 0)
343 sBuffer.append(",");
344 sBuffer.append(OUString::number(seq[i]));
346 return sBuffer.makeStringAndClear();
349 OUString lcl_IntListToString(const uno::Sequence<sal_Int32>& seq)
351 OUStringBuffer sBuffer;
352 for (sal_Int32 i = 0; i != seq.getLength(); ++i)
354 if (i != 0)
355 sBuffer.append(",");
356 sBuffer.append(OUString::number(seq[i]));
358 return sBuffer.makeStringAndClear();
361 OUString lcl_IntListToString(const uno::Sequence<sal_Int64>& seq)
363 OUStringBuffer sBuffer;
364 for (sal_Int32 i = 0; i != seq.getLength(); ++i)
366 if (i != 0)
367 sBuffer.append(",");
368 sBuffer.append(OUString::number(seq[i]));
370 return sBuffer.makeStringAndClear();
373 OUString lcl_DoubleListToString(const uno::Sequence<double>& seq)
375 OUStringBuffer sBuffer;
376 for (sal_Int32 i = 0; i != seq.getLength(); ++i)
378 if (i != 0)
379 sBuffer.append(",");
380 sBuffer.append(OUString::number(seq[i]));
382 return sBuffer.makeStringAndClear();
386 void CuiAboutConfigTabPage::FillItems(const Reference<XNameAccess>& xNameAccess,
387 const weld::TreeIter* pParentEntry, int lineage,
388 bool bLoadAll)
390 OUString sPath
391 = Reference<XHierarchicalName>(xNameAccess, uno::UNO_QUERY_THROW)->getHierarchicalName();
392 const uno::Sequence<OUString> seqItems = xNameAccess->getElementNames();
393 for (const OUString& item : seqItems)
395 Any aNode = xNameAccess->getByName(item);
397 bool bNotLeaf = false;
399 Reference<XNameAccess> xNextNameAccess;
402 xNextNameAccess.set(aNode, uno::UNO_QUERY);
403 bNotLeaf = xNextNameAccess.is();
405 catch (const RuntimeException&)
407 TOOLS_WARN_EXCEPTION("cui.options", "CuiAboutConfigTabPage");
410 if (bNotLeaf)
412 if (bLoadAll)
413 FillItems(xNextNameAccess, nullptr, lineage + 1, true);
414 else
416 // not leaf node
417 m_vectorUserData.push_back(
418 std::make_unique<UserData>(xNextNameAccess, lineage + 1));
419 OUString sId(weld::toId(m_vectorUserData.back().get()));
421 m_xPrefBox->insert(pParentEntry, -1, &item, &sId, nullptr, nullptr, true,
422 m_xScratchIter.get());
423 // Necessary, without this the selection line will be truncated.
424 m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 1);
425 m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 2);
426 m_xPrefBox->set_text(*m_xScratchIter, u""_ustr, 3);
427 m_xPrefBox->set_text_emphasis(*m_xScratchIter, false, -1);
428 m_xPrefBox->set_sensitive(*m_xScratchIter, true);
431 else
433 // leaf node
434 OUString sPropertyName = item;
435 auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
436 [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
437 return rEntry.pUserData->sPropertyPath == sPath
438 && rEntry.sStatus == sPropertyName;
441 css::uno::Reference<css::configuration::XReadWriteAccess> m_xReadWriteAccess;
442 m_xReadWriteAccess = css::configuration::ReadWriteAccess::create(
443 ::comphelper::getProcessComponentContext(), u"*"_ustr);
444 beans::Property aProperty;
445 bool bReadOnly = false;
446 OUString sFullPath(sPath + "/" + sPropertyName);
449 aProperty = m_xReadWriteAccess->getPropertyByHierarchicalName(sFullPath);
450 bReadOnly = (aProperty.Attributes & beans::PropertyAttribute::READONLY) != 0;
452 catch (css::beans::UnknownPropertyException)
454 SAL_WARN("cui.options", "unknown property: " << sFullPath);
457 OUString sTooltip;
458 OUString sType;
459 bool bWasModified = false;
460 css::uno::Type aType = cppu::UnoType<void>::get();
461 OUString sDynamicType = aNode.getValueTypeName();
464 Reference<configuration::XDocumentation> xDocumentation(xNameAccess,
465 UNO_QUERY_THROW);
466 sTooltip
467 = xDocumentation->getDescriptionByHierarchicalName(sPath + "/" + sPropertyName);
468 aType = xDocumentation->getTypeByHierarchicalName(sFullPath);
469 bWasModified = xDocumentation->getModifiedByHierarchicalName(sFullPath);
471 catch (css::container::NoSuchElementException)
474 catch (css::util::InvalidStateException)
478 OUStringBuffer sValue;
480 // Fall back to dynamic type when this is empty
481 if (aType == cppu::UnoType<void>::get() && sDynamicType != "void")
483 if (sDynamicType == "boolean")
484 aType = cppu::UnoType<sal_Bool>::get();
485 else if (sDynamicType == "short")
486 aType = cppu::UnoType<sal_Int16>::get();
487 else if (sDynamicType == "long")
488 aType = cppu::UnoType<sal_Int32>::get();
489 else if (sDynamicType == "hyper")
490 aType = cppu::UnoType<sal_Int64>::get();
491 else if (sDynamicType == "double")
492 aType = cppu::UnoType<double>::get();
493 else if (sDynamicType == "string")
494 aType = cppu::UnoType<OUString>::get();
495 else if (sDynamicType == "[]byte")
496 aType = cppu::UnoType<css::uno::Sequence<sal_Int8>>::get();
497 else if (sDynamicType == "[]boolean")
498 aType = cppu::UnoType<css::uno::Sequence<sal_Bool>>::get();
499 else if (sDynamicType == "[]short")
500 aType = cppu::UnoType<css::uno::Sequence<sal_Int16>>::get();
501 else if (sDynamicType == "[]long")
502 aType = cppu::UnoType<css::uno::Sequence<sal_Int32>>::get();
503 else if (sDynamicType == "[]hyper")
504 aType = cppu::UnoType<css::uno::Sequence<sal_Int64>>::get();
505 else if (sDynamicType == "[]double")
506 aType = cppu::UnoType<css::uno::Sequence<double>>::get();
507 else if (sDynamicType == "[]string")
508 aType = cppu::UnoType<css::uno::Sequence<OUString>>::get();
509 else if (sDynamicType == "[][]byte")
510 aType = cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get();
513 if (it != m_modifiedPrefBoxEntries.end())
514 sValue = it->sValue;
515 else
517 bool bHasValue = sDynamicType != "void";
518 if (aType == cppu::UnoType<sal_Bool>::get())
520 if (bHasValue)
521 sValue = OUString::boolean(aNode.get<bool>());
522 sType = "boolean";
524 else if (aType == cppu::UnoType<sal_Int16>::get())
526 if (bHasValue)
527 sValue = OUString::number(aNode.get<sal_Int16>());
528 sType = "short";
530 else if (aType == cppu::UnoType<sal_Int32>::get())
532 if (bHasValue)
533 sValue = OUString::number(aNode.get<sal_Int32>());
534 sType = "int";
536 else if (aType == cppu::UnoType<sal_Int64>::get())
538 if (bHasValue)
539 sValue = OUString::number(aNode.get<sal_Int64>());
540 sType = "long";
542 else if (aType == cppu::UnoType<double>::get())
544 if (bHasValue)
545 sValue = OUString::number(aNode.get<double>());
546 sType = "double";
548 else if (aType == cppu::UnoType<OUString>::get())
550 if (bHasValue)
551 sValue = aNode.get<OUString>();
552 sType = "string";
554 else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int8>>::get())
556 if (bHasValue)
558 const uno::Sequence<sal_Int8> seq = aNode.get<uno::Sequence<sal_Int8>>();
559 for (sal_Int8 j : seq)
561 OUString s = OUString::number(static_cast<sal_uInt8>(j), 16);
562 if (s.getLength() == 1)
564 sValue.append("0");
566 sValue.append(s.toAsciiUpperCase());
569 sType = "hexBinary";
571 else if (aType == cppu::UnoType<css::uno::Sequence<sal_Bool>>::get())
573 if (bHasValue)
575 uno::Sequence<sal_Bool> seq = aNode.get<uno::Sequence<sal_Bool>>();
576 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
578 if (j != 0)
580 sValue.append(",");
582 sValue.append(OUString::boolean(seq[j]));
585 sType = "boolean-list";
587 else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int16>>::get())
589 if (bHasValue)
591 uno::Sequence<sal_Int16> seq = aNode.get<uno::Sequence<sal_Int16>>();
592 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
594 if (j != 0)
596 sValue.append(",");
598 sValue.append(static_cast<sal_Int32>(seq[j]));
601 sType = "short-list";
603 else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int32>>::get())
605 if (bHasValue)
607 uno::Sequence<sal_Int32> seq = aNode.get<uno::Sequence<sal_Int32>>();
608 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
610 if (j != 0)
612 sValue.append(",");
614 sValue.append(seq[j]);
617 sType = "int-list";
619 else if (aType == cppu::UnoType<css::uno::Sequence<sal_Int64>>::get())
621 if (bHasValue)
623 uno::Sequence<sal_Int64> seq = aNode.get<uno::Sequence<sal_Int64>>();
624 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
626 if (j != 0)
628 sValue.append(",");
630 sValue.append(seq[j]);
633 sType = "long-list";
635 else if (aType == cppu::UnoType<css::uno::Sequence<double>>::get())
637 if (bHasValue)
639 uno::Sequence<double> seq = aNode.get<uno::Sequence<double>>();
640 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
642 if (j != 0)
644 sValue.append(",");
646 sValue.append(seq[j]);
649 sType = "double-list";
651 else if (aType == cppu::UnoType<css::uno::Sequence<OUString>>::get())
653 if (bHasValue)
654 sValue = lcl_StringListToString(aNode.get<uno::Sequence<OUString>>());
655 sType = "string-list";
657 else if (aType
658 == cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get())
660 if (bHasValue)
662 const uno::Sequence<uno::Sequence<sal_Int8>> seq
663 = aNode.get<uno::Sequence<uno::Sequence<sal_Int8>>>();
664 for (sal_Int32 j = 0; j != seq.getLength(); ++j)
666 if (j != 0)
668 sValue.append(",");
670 for (sal_Int8 k : seq[j])
672 OUString s = OUString::number(static_cast<sal_uInt8>(k), 16);
673 if (s.getLength() == 1)
675 sValue.append("0");
677 sValue.append(s.toAsciiUpperCase());
681 sType = "hexBinary-list";
683 else
685 SAL_INFO("cui.options", "path \"" << sPath << "\" member " << item
686 << " of unsupported type " << sType);
687 continue;
691 //Short name
692 int index = 0;
693 for (int j = 1; j < lineage; ++j)
694 index = sPath.indexOf("/", index + 1);
696 InsertEntry(sPath, aNode, sPath.copy(index + 1), item, sType,
697 sValue.makeStringAndClear(), sTooltip, pParentEntry, !bLoadAll, bReadOnly,
698 bWasModified);
703 Reference<XNameAccess> CuiAboutConfigTabPage::getConfigAccess(const OUString& sNodePath,
704 bool bUpdate)
706 const uno::Reference<uno::XComponentContext>& xContext(
707 ::comphelper::getProcessComponentContext());
709 uno::Reference<lang::XMultiServiceFactory> xConfigProvider(
710 css::configuration::theDefaultProvider::get(xContext));
712 beans::NamedValue aProperty;
713 aProperty.Name = "nodepath";
714 aProperty.Value <<= sNodePath;
716 uno::Sequence<uno::Any> aArgumentList{ uno::Any(aProperty) };
718 OUString sAccessString;
720 if (bUpdate)
721 sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess";
722 else
723 sAccessString = "com.sun.star.configuration.ConfigurationAccess";
725 uno::Reference<container::XNameAccess> xNameAccess(
726 xConfigProvider->createInstanceWithArguments(sAccessString, aArgumentList),
727 uno::UNO_QUERY_THROW);
729 return xNameAccess;
732 void CuiAboutConfigTabPage::AddToModifiedVector(const std::shared_ptr<Prop_Impl>& rProp)
734 bool isModifiedBefore = false;
735 //Check if value modified before
736 for (std::shared_ptr<Prop_Impl>& nInd : m_vectorOfModified)
738 if (rProp->Name == nInd->Name && rProp->Property == nInd->Property)
740 //property modified before. Assign reference to the modified value
741 //do your changes on this object. They will be saved later.
742 nInd = rProp;
743 isModifiedBefore = true;
744 break;
748 if (!isModifiedBefore)
749 m_vectorOfModified.push_back(rProp);
750 //property is not modified before
753 std::vector<OUString>
754 CuiAboutConfigTabPage::commaStringToSequence(std::u16string_view rCommaSepString)
756 std::vector<OUString> tempVector;
758 sal_Int32 index = 0;
761 OUString word(o3tl::getToken(rCommaSepString, 0, u',', index));
762 word = word.trim();
763 if (!word.isEmpty())
764 tempVector.push_back(word);
765 } while (index >= 0);
766 return tempVector;
769 IMPL_LINK_NOARG(CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void) { Reset(); }
771 IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool)
773 StandardHdl_Impl(*m_xEditBtn);
774 return true;
777 IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void)
779 if (!m_xPrefBox->get_selected(m_xScratchIter.get()))
780 return;
782 UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(*m_xScratchIter));
783 if (!pUserData || !pUserData->bIsPropertyPath || pUserData->bIsReadOnly)
784 return;
786 //if selection is a node
787 OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1);
788 OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2);
789 OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3);
791 auto pProperty
792 = std::make_shared<Prop_Impl>(pUserData->sPropertyPath, sPropertyName, Any(sPropertyValue));
793 bool bSaveChanges = false;
795 bool bOpenDialog = true;
796 OUString sDialogValue;
798 if (sPropertyType == "boolean")
800 bool bValue;
801 if (sPropertyValue == "true")
803 sDialogValue = "false";
804 bValue = false;
806 else
808 sDialogValue = "true";
809 bValue = true;
812 pProperty->Value <<= bValue;
813 bOpenDialog = false;
814 bSaveChanges = true;
816 else
818 sDialogValue = sPropertyValue;
819 bOpenDialog = true;
824 if (bOpenDialog)
826 if (sPropertyType == "short" || sPropertyType == "int" || sPropertyType == "long")
828 sal_Int64 nMin = sPropertyType == "short"
829 ? SAL_MIN_INT16
830 : sPropertyType == "int" ? SAL_MIN_INT32 : SAL_MIN_INT64;
831 sal_Int64 nMax = sPropertyType == "short"
832 ? SAL_MAX_INT16
833 : sPropertyType == "int" ? SAL_MAX_INT32 : SAL_MAX_INT64;
834 SvxNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName,
835 sDialogValue.toInt64(), nMin, nMax);
836 if (aNumberDialog.run() == RET_OK)
838 sal_Int64 nNewValue = aNumberDialog.GetNumber();
839 if (sPropertyType == "short")
841 pProperty->Value <<= static_cast<sal_Int16>(nNewValue);
843 else if (sPropertyType == "int")
845 pProperty->Value <<= static_cast<sal_Int32>(nNewValue);
847 else if (sPropertyType == "long")
849 pProperty->Value <<= nNewValue;
851 bSaveChanges = true;
852 sDialogValue = OUString::number(nNewValue);
855 else if (sPropertyType == "double")
857 SvxDecimalNumberDialog aNumberDialog(m_xDialog.get(), sPropertyName,
858 sDialogValue.toDouble());
859 if (aNumberDialog.run() == RET_OK)
861 double fNewValue = aNumberDialog.GetNumber();
862 pProperty->Value <<= fNewValue;
863 bSaveChanges = true;
864 sDialogValue = OUString::number(fNewValue);
867 else if (sPropertyType == "string")
869 SvxNameDialog aNameDialog(m_xDialog.get(), sDialogValue, sPropertyName);
870 aNameDialog.SetCheckNameHdl(LINK(this, CuiAboutConfigTabPage, ValidNameHdl));
871 if (aNameDialog.run() == RET_OK)
873 sDialogValue = aNameDialog.GetName();
874 pProperty->Value <<= sDialogValue;
875 bSaveChanges = true;
878 else if (sPropertyType == "short-list")
880 SvxListDialog aListDialog(m_xDialog.get());
881 aListDialog.SetEntries(commaStringToSequence(sDialogValue));
882 aListDialog.SetMode(ListMode::Int16);
883 if (aListDialog.run() == RET_OK)
885 std::vector<OUString> seqStr = aListDialog.GetEntries();
886 uno::Sequence<sal_Int16> seqShort(seqStr.size());
887 std::transform(
888 seqStr.begin(), seqStr.end(), seqShort.getArray(),
889 [](const auto& str) { return static_cast<sal_Int16>(str.toInt32()); });
890 pProperty->Value <<= seqShort;
891 sDialogValue = lcl_IntListToString(seqShort);
892 bSaveChanges = true;
895 else if (sPropertyType == "int-list")
897 SvxListDialog aListDialog(m_xDialog.get());
898 aListDialog.SetEntries(commaStringToSequence(sDialogValue));
899 aListDialog.SetMode(ListMode::Int32);
900 if (aListDialog.run() == RET_OK)
902 std::vector<OUString> seqStr = aListDialog.GetEntries();
903 uno::Sequence<sal_Int32> seq(seqStr.size());
904 std::transform(
905 seqStr.begin(), seqStr.end(), seq.getArray(),
906 [](const auto& str) { return static_cast<sal_Int32>(str.toInt32()); });
907 pProperty->Value <<= seq;
908 sDialogValue = lcl_IntListToString(seq);
909 bSaveChanges = true;
912 else if (sPropertyType == "long-list")
914 SvxListDialog aListDialog(m_xDialog.get());
915 aListDialog.SetEntries(commaStringToSequence(sDialogValue));
916 aListDialog.SetMode(ListMode::Int64);
917 if (aListDialog.run() == RET_OK)
919 std::vector<OUString> seqStr = aListDialog.GetEntries();
920 uno::Sequence<sal_Int64> seq(seqStr.size());
921 std::transform(
922 seqStr.begin(), seqStr.end(), seq.getArray(),
923 [](const auto& str) { return static_cast<sal_Int64>(str.toInt32()); });
924 pProperty->Value <<= seq;
925 sDialogValue = lcl_IntListToString(seq);
926 bSaveChanges = true;
929 else if (sPropertyType == "double-list")
931 SvxListDialog aListDialog(m_xDialog.get());
932 aListDialog.SetEntries(commaStringToSequence(sDialogValue));
933 aListDialog.SetMode(ListMode::Double);
934 if (aListDialog.run() == RET_OK)
936 std::vector<OUString> seqStr = aListDialog.GetEntries();
937 uno::Sequence<double> seq(seqStr.size());
938 std::transform(
939 seqStr.begin(), seqStr.end(), seq.getArray(),
940 [](const auto& str) { return static_cast<double>(str.toDouble()); });
941 pProperty->Value <<= seq;
942 sDialogValue = lcl_DoubleListToString(seq);
943 bSaveChanges = true;
946 else if (sPropertyType == "string-list")
948 SvxListDialog aListDialog(m_xDialog.get());
949 uno::Sequence<OUString> aList
950 = pUserData->aPropertyValue.get<uno::Sequence<OUString>>();
951 aListDialog.SetEntries(
952 comphelper::sequenceToContainer<std::vector<OUString>>(aList));
953 aListDialog.SetMode(ListMode::String);
954 if (aListDialog.run() == RET_OK)
956 auto seq = comphelper::containerToSequence(aListDialog.GetEntries());
957 sDialogValue = lcl_StringListToString(seq);
958 pProperty->Value <<= seq;
959 bSaveChanges = true;
962 else //unknown
963 throw uno::Exception("unknown property type " + sPropertyType, nullptr);
966 if (bSaveChanges)
968 AddToModifiedVector(pProperty);
969 pUserData->aPropertyValue = pProperty->Value;
971 //update listbox value.
972 m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2);
973 m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
974 m_xPrefBox->set_text_emphasis(*m_xScratchIter, true, -1);
975 //update m_prefBoxEntries
976 auto it = std::find_if(
977 m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
978 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
979 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
980 && rEntry.sStatus == sPropertyName;
982 if (it != m_prefBoxEntries.end())
984 it->sValue = sDialogValue;
985 it->pUserData->bWasModified = true;
987 auto modifiedIt = std::find_if(
988 m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(),
989 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool {
990 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath
991 && rEntry.sStatus == sPropertyName;
994 if (modifiedIt != m_modifiedPrefBoxEntries.end())
996 modifiedIt->sValue = sDialogValue;
997 modifiedIt->pUserData->bWasModified = true;
999 else
1001 m_modifiedPrefBoxEntries.push_back(*it);
1006 catch (uno::Exception&)
1011 IMPL_LINK_NOARG(CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) { InputChanged(); }
1013 IMPL_LINK_NOARG(CuiAboutConfigTabPage, ModifiedHdl_Impl, weld::Toggleable&, void)
1015 InputChanged();
1018 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry)
1020 bool bOnlyModified = m_xModifiedCheckBtn->get_active();
1021 if (bOnlyModified && !rEntry.pUserData->bWasModified)
1022 return;
1024 OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
1025 sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
1026 OUString sPath = sPathWithProperty.copy(0, index);
1027 index = 0;
1028 std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator());
1029 std::unique_ptr<weld::TreeIter> xGrandParentEntry;
1033 int prevIndex = index;
1034 index = sPath.indexOf("/", index + 1);
1035 // deal with no parent case (tdf#107811)
1036 if (index < 0)
1038 OUString sId(weld::toId(rEntry.pUserData));
1039 m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, false,
1040 m_xScratchIter.get());
1041 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
1042 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
1043 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
1044 m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1);
1045 m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
1046 return;
1048 OUString sParentName = sPath.copy(prevIndex + 1, index - prevIndex - 1);
1050 bool hasEntry = false;
1051 bool bStartOk;
1053 if (!xGrandParentEntry)
1054 bStartOk = m_xPrefBox->get_iter_first(*xParentEntry);
1055 else
1057 m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry);
1058 bStartOk = m_xPrefBox->iter_children(*xParentEntry);
1061 if (bStartOk)
1065 if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName)
1067 hasEntry = true;
1068 break;
1070 } while (m_xPrefBox->iter_next_sibling(*xParentEntry));
1073 if (!hasEntry)
1075 m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr,
1076 false, xParentEntry.get());
1077 //It is needed, without this the selection line will be truncated.
1078 m_xPrefBox->set_text(*xParentEntry, u""_ustr, 1);
1079 m_xPrefBox->set_text(*xParentEntry, u""_ustr, 2);
1080 m_xPrefBox->set_text(*xParentEntry, u""_ustr, 3);
1081 m_xPrefBox->set_text_emphasis(*xParentEntry, false, -1);
1082 m_xPrefBox->set_sensitive(*xParentEntry, true);
1085 xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get());
1086 } while (index < sPath.getLength() - 1);
1088 OUString sId(weld::toId(rEntry.pUserData));
1089 m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, false,
1090 m_xScratchIter.get());
1091 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
1092 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
1093 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
1094 m_xPrefBox->set_text_emphasis(*m_xScratchIter, rEntry.pUserData->bWasModified, -1);
1095 m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
1098 IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool)
1100 if (m_xPrefBox->iter_has_child(rEntry))
1101 return true;
1102 UserData* pUserData = weld::fromId<UserData*>(m_xPrefBox->get_id(rEntry));
1103 if (pUserData && !pUserData->bIsPropertyPath)
1105 assert(pUserData->aXNameAccess.is());
1106 FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage);
1108 return true;
1111 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */