configmgr/source/access.cxx                          |   22 ++
 configmgr/source/access.hxx                          |    3 
 configmgr/source/childaccess.cxx                     |    4 
 configmgr/source/dconf.cxx                           |    4 
 configmgr/source/localizedvaluenode.cxx              |    5 
 configmgr/source/localizedvaluenode.hxx              |    8 
 configmgr/source/propertynode.cxx                    |    9 -
 configmgr/source/propertynode.hxx                    |    8 
 configmgr/source/valueparser.cxx                     |    5 
 configmgr/source/xcuparser.cxx                       |    4 
 cui/source/options/optaboutconfig.cxx                |  154 +++++++++++--------
 cui/source/options/optaboutconfig.hxx                |    6 
 cui/uiconfig/ui/aboutconfigdialog.ui                 |   18 ++
 offapi/com/sun/star/configuration/XDocumentation.idl |   16 +
 vcl/source/app/salvtables.cxx                        |   15 +
 vcl/unx/gtk3/gtkinst.cxx                             |   18 +-
 16 files changed, 216 insertions(+), 83 deletions(-)

New commits:
commit 030b72df0af04752157378e07703db0e035ff9c2
Author:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
AuthorDate: Mon Nov 27 11:01:09 2023 +0100
Commit:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
CommitDate: Thu Dec 7 08:03:36 2023 +0100

    tdf#157432 Expert config: Allow filtering by changed values
    
    Change-Id: Ib8bbb7fc9e8014a9367278f3fa640f53af46dd2b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159986
    Tested-by: Jenkins
    Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>

diff --git a/configmgr/source/access.cxx b/configmgr/source/access.cxx
index 371ebdc95b06..3075bc0a32f6 100644
--- a/configmgr/source/access.cxx
+++ b/configmgr/source/access.cxx
@@ -478,6 +478,28 @@ css::uno::Type Access::getTypeByHierarchicalName(OUString 
const & aName)
     }
 }
 
+sal_Bool Access::getModifiedByHierarchicalName(OUString const & aName)
+{
+    assert(thisIs(IS_ANY));
+    osl::MutexGuard g(*lock_);
+    checkLocalizedPropertyAccess();
+    rtl::Reference< ChildAccess > child(getSubChild(aName));
+    if (!child.is()) {
+        throw css::container::NoSuchElementException(
+            aName, getXWeak());
+    }
+    auto const & p = child->getNode();
+    switch (p->kind()) {
+    case Node::KIND_PROPERTY:
+        return static_cast<PropertyNode *>(p.get())->isModified();
+    case Node::KIND_LOCALIZED_VALUE:
+        return static_cast<LocalizedValueNode *>(p.get())->isModified();
+    default:
+        throw css::util::InvalidStateException(
+            aName, getXWeak());
+    }
+}
+
 sal_Bool Access::hasByHierarchicalName(OUString const & aName)
 {
     assert(thisIs(IS_ANY));
diff --git a/configmgr/source/access.hxx b/configmgr/source/access.hxx
index a94d20a6bce6..bd93b4222177 100644
--- a/configmgr/source/access.hxx
+++ b/configmgr/source/access.hxx
@@ -168,6 +168,9 @@ public:
     virtual css::uno::Type SAL_CALL getTypeByHierarchicalName(
         OUString const & aName) override;
 
+    virtual sal_Bool SAL_CALL getModifiedByHierarchicalName(
+        OUString const & aName) override;
+
     virtual sal_Bool SAL_CALL hasByHierarchicalName(OUString const & aName) 
override;
 
     virtual void SAL_CALL replaceByHierarchicalName(
diff --git a/configmgr/source/childaccess.cxx b/configmgr/source/childaccess.cxx
index e0a9f9ac6cee..abf3795f1d55 100644
--- a/configmgr/source/childaccess.cxx
+++ b/configmgr/source/childaccess.cxx
@@ -279,11 +279,11 @@ void ChildAccess::commitChanges(bool valid, Modifications 
* globalModifications)
         switch (node_->kind()) {
         case Node::KIND_PROPERTY:
             static_cast< PropertyNode * >(node_.get())->setValue(
-                Data::NO_LAYER, *changedValue_);
+                Data::NO_LAYER, *changedValue_, true);
             break;
         case Node::KIND_LOCALIZED_VALUE:
             static_cast< LocalizedValueNode * >(node_.get())->setValue(
-                Data::NO_LAYER, *changedValue_);
+                Data::NO_LAYER, *changedValue_, true);
             break;
         default:
             assert(false); // this cannot happen
diff --git a/configmgr/source/dconf.cxx b/configmgr/source/dconf.cxx
index 8548daa46b3c..c12f4a2814fd 100644
--- a/configmgr/source/dconf.cxx
+++ b/configmgr/source/dconf.cxx
@@ -973,7 +973,7 @@ void readDir(
                     case ReadValue::Error:
                         continue;
                     case ReadValue::Value:
-                        prop->setValue(layer, value);
+                        prop->setValue(layer, value, false);
                         finalize(client, path, member, layer);
                         break;
                     case ReadValue::Remove:
@@ -1005,7 +1005,7 @@ void readDir(
                         continue;
                     }
                     static_cast<LocalizedValueNode *>(member.get())->setValue(
-                        layer, value);
+                        layer, value, false);
                     finalize(client, path, member, layer);
                     break;
                 }
diff --git a/configmgr/source/localizedvaluenode.cxx 
b/configmgr/source/localizedvaluenode.cxx
index 816975063d29..7f377cc65e2f 100644
--- a/configmgr/source/localizedvaluenode.cxx
+++ b/configmgr/source/localizedvaluenode.cxx
@@ -30,7 +30,7 @@
 namespace configmgr {
 
 LocalizedValueNode::LocalizedValueNode(int layer, css::uno::Any value):
-    Node(layer), value_(std::move(value))
+    Node(layer), value_(std::move(value)), modified_(false)
 {}
 
 LocalizedValueNode::LocalizedValueNode(int layer):
@@ -46,9 +46,10 @@ OUString LocalizedValueNode::getTemplateName() const {
 }
 
 
-void LocalizedValueNode::setValue(int layer, css::uno::Any const & value)
+void LocalizedValueNode::setValue(int layer, css::uno::Any const & value, bool 
bIsUserModification)
 {
     setLayer(layer);
+    modified_ = bIsUserModification;
     if (&value != &value_)
         value_ = value;
 }
diff --git a/configmgr/source/localizedvaluenode.hxx 
b/configmgr/source/localizedvaluenode.hxx
index 07949ac5a621..305c82811f33 100644
--- a/configmgr/source/localizedvaluenode.hxx
+++ b/configmgr/source/localizedvaluenode.hxx
@@ -39,13 +39,16 @@ public:
     virtual OUString getTemplateName() const override;
 
     const css::uno::Any& getValue() const { return value_; }
-    css::uno::Any* getValuePtr(int layer)
+    css::uno::Any* getValuePtr(int layer, bool bIsUserModification)
     {
         setLayer(layer);
+        modified_ = bIsUserModification;
         return &value_;
     }
 
-    void setValue(int layer, css::uno::Any const& value);
+    void setValue(int layer, css::uno::Any const& value, bool 
bIsUserModification);
+
+    bool isModified() { return modified_; }
 
 private:
     LocalizedValueNode(LocalizedValueNode const&) = default;
@@ -55,6 +58,7 @@ private:
     virtual Kind kind() const override;
 
     css::uno::Any value_;
+    bool modified_;
 };
 }
 
diff --git a/configmgr/source/propertynode.cxx 
b/configmgr/source/propertynode.cxx
index 351025a2ffb1..6a9d2a6e2817 100644
--- a/configmgr/source/propertynode.cxx
+++ b/configmgr/source/propertynode.cxx
@@ -39,7 +39,7 @@ PropertyNode::PropertyNode(
     int layer, Type staticType, bool nillable, css::uno::Any value,
     bool extension):
     Node(layer), staticType_(staticType), nillable_(nillable),
-    extension_(extension), value_(std::move(value))
+    extension_(extension), modified_(false), value_(std::move(value))
 {}
 
 rtl::Reference< Node > PropertyNode::clone(bool) const {
@@ -62,15 +62,18 @@ css::uno::Any const & PropertyNode::getValue(Components & 
components) {
     return value_;
 }
 
-void PropertyNode::setValue(int layer, css::uno::Any const & value) {
+void PropertyNode::setValue(int layer, css::uno::Any const & value, bool 
bIsUserModification) {
     setLayer(layer);
     value_ = value;
+    // Consider as modified when modified during runtime or by user registry 
modifications
+    modified_ = bIsUserModification;
     externalDescriptor_.clear();
 }
 
-css::uno::Any *PropertyNode::getValuePtr(int layer)
+css::uno::Any *PropertyNode::getValuePtr(int layer, bool bIsUserModification)
 {
     setLayer(layer);
+    modified_ = bIsUserModification;
     externalDescriptor_.clear();
     return &value_;
 }
diff --git a/configmgr/source/propertynode.hxx 
b/configmgr/source/propertynode.hxx
index 108b8e944b2b..db6fb926adbf 100644
--- a/configmgr/source/propertynode.hxx
+++ b/configmgr/source/propertynode.hxx
@@ -46,13 +46,15 @@ public:
 
     css::uno::Any const & getValue(Components & components);
 
-    void setValue(int layer, css::uno::Any const & value);
-    css::uno::Any *getValuePtr(int layer);
+    void setValue(int layer, css::uno::Any const & value, bool 
bIsUserModification);
+    css::uno::Any *getValuePtr(int layer, bool bIsUserModification);
 
     void setExternal(int layer, OUString const & descriptor);
 
     bool isExtension() const { return extension_;}
 
+    bool isModified() const { return modified_;}
+
 private:
     PropertyNode(PropertyNode const&) = default;
 
@@ -65,6 +67,8 @@ private:
         // TYPE_HEXBINARY_LIST; not TYPE_ERROR or TYPE_NIL)
     bool nillable_;
     bool extension_;
+    /// Whether the property was modified by the user:
+    bool modified_;
     OUString externalDescriptor_;
     css::uno::Any value_;
 };
diff --git a/configmgr/source/valueparser.cxx b/configmgr/source/valueparser.cxx
index 17174368d59b..249c1c1dbdcb 100644
--- a/configmgr/source/valueparser.cxx
+++ b/configmgr/source/valueparser.cxx
@@ -33,6 +33,7 @@
 #include <xmlreader/span.hxx>
 #include <xmlreader/xmlreader.hxx>
 
+#include "data.hxx"
 #include "localizedvaluenode.hxx"
 #include "node.hxx"
 #include "nodemap.hxx"
@@ -347,7 +348,7 @@ bool ValueParser::endElement() {
 
             switch (node_->kind()) {
             case Node::KIND_PROPERTY:
-                pValue = static_cast< PropertyNode * 
>(node_.get())->getValuePtr(layer_);
+                pValue = static_cast< PropertyNode * 
>(node_.get())->getValuePtr(layer_, layer_ == Data::NO_LAYER);
                 break;
             case Node::KIND_LOCALIZED_PROPERTY:
                 {
@@ -360,7 +361,7 @@ bool ValueParser::endElement() {
                     } else {
                         pLVNode = static_cast< LocalizedValueNode * 
>(i->second.get());
                     }
-                    pValue = pLVNode->getValuePtr(layer_);
+                    pValue = pLVNode->getValuePtr(layer_, layer_ == 
Data::NO_LAYER);
                 }
                 break;
             default:
diff --git a/configmgr/source/xcuparser.cxx b/configmgr/source/xcuparser.cxx
index af21518abd78..b54e7aa95f01 100644
--- a/configmgr/source/xcuparser.cxx
+++ b/configmgr/source/xcuparser.cxx
@@ -427,7 +427,7 @@ void XcuParser::handlePropValue(
                 "xsi:nil and oor:external attributes for prop in " +
                 reader.getUrl());
         }
-        prop->setValue(valueParser_.getLayer(), css::uno::Any());
+        prop->setValue(valueParser_.getLayer(), css::uno::Any(), 
valueParser_.getLayer() == Data::NO_LAYER);
         state_.push(State::Ignore(false));
     } else if (external.isEmpty()) {
         valueParser_.separator_ = separator;
@@ -514,7 +514,7 @@ void XcuParser::handleLocpropValue(
                 } else {
                     static_cast< LocalizedValueNode * >(
                         i->second.get())->setValue(
-                            valueParser_.getLayer(), css::uno::Any());
+                            valueParser_.getLayer(), css::uno::Any(), 
valueParser_.getLayer() == Data::NO_LAYER);
                 }
                 state_.push(State::Ignore(true));
             } else {
diff --git a/cui/source/options/optaboutconfig.cxx 
b/cui/source/options/optaboutconfig.cxx
index ea63035471ca..6e3bdd9b2747 100644
--- a/cui/source/options/optaboutconfig.cxx
+++ b/cui/source/options/optaboutconfig.cxx
@@ -68,14 +68,16 @@ struct UserData
 {
     bool bIsPropertyPath;
     bool bIsReadOnly;
+    bool bWasModified;
     OUString sPropertyPath;
     OUString sTooltip;
     int aLineage;
     Reference<XNameAccess> aXNameAccess;
 
-    explicit UserData(OUString aPropertyPath, OUString aTooltip, bool 
isReadOnly)
+    explicit UserData(OUString aPropertyPath, OUString aTooltip, bool 
isReadOnly, bool wasModified)
         : bIsPropertyPath(true)
         , bIsReadOnly(isReadOnly)
+        , bWasModified(wasModified)
         , sPropertyPath(std::move(aPropertyPath))
         , sTooltip(std::move(aTooltip))
         , aLineage(0)
@@ -85,6 +87,7 @@ struct UserData
     explicit UserData(Reference<XNameAccess> const& rXNameAccess, int rIndex)
         : bIsPropertyPath(false)
         , bIsReadOnly(false)
+        , bWasModified(false)
         , aLineage(rIndex)
         , aXNameAccess(rXNameAccess)
     {
@@ -96,6 +99,7 @@ CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* 
pParent)
     , m_xResetBtn(m_xBuilder->weld_button("reset"))
     , m_xEditBtn(m_xBuilder->weld_button("edit"))
     , m_xSearchBtn(m_xBuilder->weld_button("searchButton"))
+    , m_xModifiedCheckBtn(m_xBuilder->weld_check_button("modifiedButton"))
     , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
     , m_xPrefBox(m_xBuilder->weld_tree_view("preferences"))
     , m_xScratchIter(m_xPrefBox->make_iterator())
@@ -111,6 +115,7 @@ CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* 
pParent)
     m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, 
DoubleClickHdl_Impl));
     m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, 
ExpandingHdl_Impl));
     m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, 
SearchHdl_Impl));
+    m_xModifiedCheckBtn->connect_toggled(LINK(this, CuiAboutConfigTabPage, 
ModifiedHdl_Impl));
 
     m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
     m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
@@ -186,9 +191,14 @@ void CuiAboutConfigTabPage::InsertEntry(const OUString& 
rPropertyPath, const OUS
                                         const OUString& rStatus, const 
OUString& rType,
                                         const OUString& rValue, const 
OUString& rTooltip,
                                         const weld::TreeIter* pParentEntry, 
bool bInsertToPrefBox,
-                                        bool bIsReadOnly)
+                                        bool bIsReadOnly, bool bWasModified)
 {
-    m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath, 
rTooltip, bIsReadOnly));
+    bool bOnlyModified = m_xModifiedCheckBtn->get_active();
+    if (bOnlyModified && !bWasModified)
+        return;
+
+    m_vectorUserData.push_back(
+        std::make_unique<UserData>(rPropertyPath, rTooltip, bIsReadOnly, 
bWasModified));
     if (bInsertToPrefBox)
     {
         OUString sId(weld::toId(m_vectorUserData.back().get()));
@@ -197,6 +207,7 @@ void CuiAboutConfigTabPage::InsertEntry(const OUString& 
rPropertyPath, const OUS
         m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1);
         m_xPrefBox->set_text(*m_xScratchIter, rType, 2);
         m_xPrefBox->set_text(*m_xScratchIter, rValue, 3);
+        m_xPrefBox->set_text_emphasis(*m_xScratchIter, bWasModified, -1);
         m_xPrefBox->set_sensitive(*m_xScratchIter, !bIsReadOnly, -1);
     }
     else
@@ -206,6 +217,67 @@ void CuiAboutConfigTabPage::InsertEntry(const OUString& 
rPropertyPath, const OUS
     }
 }
 
+void CuiAboutConfigTabPage::InputChanged()
+{
+    weld::WaitObject aWait(m_xDialog.get());
+
+    m_xPrefBox->hide();
+    m_xPrefBox->clear();
+    m_xPrefBox->freeze();
+
+    if (m_bSorted)
+        m_xPrefBox->make_unsorted();
+
+    if (m_xSearchEdit->get_text().isEmpty())
+    {
+        m_xPrefBox->clear();
+        Reference<XNameAccess> xConfigAccess = getConfigAccess("/", false);
+        FillItems(xConfigAccess);
+    }
+    else
+    {
+        m_options.searchString = m_xSearchEdit->get_text();
+        utl::TextSearch textSearch(m_options);
+        for (auto const& it : m_prefBoxEntries)
+        {
+            sal_Int32 endPos, startPos = 0;
+
+            for (size_t i = 0; i < 5; ++i)
+            {
+                OUString scrTxt;
+
+                if (i == 0)
+                    scrTxt = it.pUserData->sPropertyPath;
+                else if (i == 1)
+                    scrTxt = it.sProp;
+                else if (i == 2)
+                    scrTxt = it.sStatus;
+                else if (i == 3)
+                    scrTxt = it.sType;
+                else if (i == 4)
+                    scrTxt = it.sValue;
+
+                endPos = scrTxt.getLength();
+                if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
+                {
+                    InsertEntry(it);
+                    break;
+                }
+            }
+        }
+    }
+
+    m_xPrefBox->thaw();
+    if (m_bSorted)
+        m_xPrefBox->make_sorted();
+
+    m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
+        m_xPrefBox->expand_row(rEntry);
+        return false;
+    });
+    m_xPrefBox->show();
+}
+
 void CuiAboutConfigTabPage::Reset()
 {
     weld::WaitObject aWait(m_xDialog.get());
@@ -380,6 +452,7 @@ void CuiAboutConfigTabPage::FillItems(const 
Reference<XNameAccess>& xNameAccess,
 
             OUString sTooltip;
             OUString sType;
+            bool bWasModified = false;
             css::uno::Type aType = cppu::UnoType<void>::get();
             OUString sDynamicType = aNode.getValueTypeName();
             try
@@ -389,6 +462,7 @@ void CuiAboutConfigTabPage::FillItems(const 
Reference<XNameAccess>& xNameAccess,
                 sTooltip
                     = xDocumentation->getDescriptionByHierarchicalName(sPath + 
"/" + sPropertyName);
                 aType = xDocumentation->getTypeByHierarchicalName(sFullPath);
+                bWasModified = 
xDocumentation->getModifiedByHierarchicalName(sFullPath);
             }
             catch (css::container::NoSuchElementException)
             {
@@ -616,7 +690,7 @@ void CuiAboutConfigTabPage::FillItems(const 
Reference<XNameAccess>& xNameAccess,
                 index = sPath.indexOf("/", index + 1);
 
             InsertEntry(sPath, sPath.copy(index + 1), item, sType, 
sValue.makeStringAndClear(),
-                        sTooltip, pParentEntry, !bLoadAll, bReadOnly);
+                        sTooltip, pParentEntry, !bLoadAll, bReadOnly, 
bWasModified);
         }
     }
 }
@@ -892,6 +966,7 @@ IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, 
weld::Button&, void)
             //update listbox value.
             m_xPrefBox->set_text(*m_xScratchIter, sPropertyType, 2);
             m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3);
+            m_xPrefBox->set_text_emphasis(*m_xScratchIter, true, -1);
             //update m_prefBoxEntries
             auto it = std::find_if(
                 m_prefBoxEntries.begin(), m_prefBoxEntries.end(),
@@ -902,6 +977,7 @@ IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, 
weld::Button&, void)
             if (it != m_prefBoxEntries.end())
             {
                 it->sValue = sDialogValue;
+                it->pUserData->bWasModified = true;
 
                 auto modifiedIt = std::find_if(
                     m_modifiedPrefBoxEntries.begin(), 
m_modifiedPrefBoxEntries.end(),
@@ -913,6 +989,7 @@ IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, 
weld::Button&, void)
                 if (modifiedIt != m_modifiedPrefBoxEntries.end())
                 {
                     modifiedIt->sValue = sDialogValue;
+                    modifiedIt->pUserData->bWasModified = true;
                 }
                 else
                 {
@@ -926,69 +1003,19 @@ IMPL_LINK_NOARG(CuiAboutConfigTabPage, StandardHdl_Impl, 
weld::Button&, void)
     }
 }
 
-IMPL_LINK_NOARG(CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void)
-{
-    weld::WaitObject aWait(m_xDialog.get());
-
-    m_xPrefBox->hide();
-    m_xPrefBox->clear();
-    m_xPrefBox->freeze();
-
-    if (m_bSorted)
-        m_xPrefBox->make_unsorted();
+IMPL_LINK_NOARG(CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) { 
InputChanged(); }
 
-    if (m_xSearchEdit->get_text().isEmpty())
-    {
-        m_xPrefBox->clear();
-        Reference<XNameAccess> xConfigAccess = getConfigAccess("/", false);
-        FillItems(xConfigAccess);
-    }
-    else
-    {
-        m_options.searchString = m_xSearchEdit->get_text();
-        utl::TextSearch textSearch(m_options);
-        for (auto const& it : m_prefBoxEntries)
-        {
-            sal_Int32 endPos, startPos = 0;
-
-            for (size_t i = 0; i < 5; ++i)
-            {
-                OUString scrTxt;
-
-                if (i == 0)
-                    scrTxt = it.pUserData->sPropertyPath;
-                else if (i == 1)
-                    scrTxt = it.sProp;
-                else if (i == 2)
-                    scrTxt = it.sStatus;
-                else if (i == 3)
-                    scrTxt = it.sType;
-                else if (i == 4)
-                    scrTxt = it.sValue;
-
-                endPos = scrTxt.getLength();
-                if (textSearch.SearchForward(scrTxt, &startPos, &endPos))
-                {
-                    InsertEntry(it);
-                    break;
-                }
-            }
-        }
-    }
-
-    m_xPrefBox->thaw();
-    if (m_bSorted)
-        m_xPrefBox->make_sorted();
-
-    m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) {
-        m_xPrefBox->expand_row(rEntry);
-        return false;
-    });
-    m_xPrefBox->show();
+IMPL_LINK_NOARG(CuiAboutConfigTabPage, ModifiedHdl_Impl, weld::Toggleable&, 
void)
+{
+    InputChanged();
 }
 
 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry)
 {
+    bool bOnlyModified = m_xModifiedCheckBtn->get_active();
+    if (bOnlyModified && !rEntry.pUserData->bWasModified)
+        return;
+
     OUString sPathWithProperty = rEntry.pUserData->sPropertyPath;
     sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp);
     OUString sPath = sPathWithProperty.copy(0, index);
@@ -1009,6 +1036,7 @@ void CuiAboutConfigTabPage::InsertEntry(const 
prefBoxEntry& rEntry)
             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
             m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
+            m_xPrefBox->set_text_emphasis(*m_xScratchIter, 
rEntry.pUserData->bWasModified, -1);
             m_xPrefBox->set_sensitive(*m_xScratchIter, 
!rEntry.pUserData->bIsReadOnly);
             return;
         }
@@ -1045,6 +1073,7 @@ void CuiAboutConfigTabPage::InsertEntry(const 
prefBoxEntry& rEntry)
             m_xPrefBox->set_text(*xParentEntry, "", 1);
             m_xPrefBox->set_text(*xParentEntry, "", 2);
             m_xPrefBox->set_text(*xParentEntry, "", 3);
+            m_xPrefBox->set_text_emphasis(*m_xScratchIter, 
rEntry.pUserData->bWasModified, -1);
             m_xPrefBox->set_sensitive(*xParentEntry, true);
         }
 
@@ -1057,6 +1086,7 @@ void CuiAboutConfigTabPage::InsertEntry(const 
prefBoxEntry& rEntry)
     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1);
     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2);
     m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3);
+    m_xPrefBox->set_text_emphasis(*m_xScratchIter, 
rEntry.pUserData->bWasModified, -1);
     m_xPrefBox->set_sensitive(*m_xScratchIter, !rEntry.pUserData->bIsReadOnly);
 }
 
diff --git a/cui/source/options/optaboutconfig.hxx 
b/cui/source/options/optaboutconfig.hxx
index 7bfce2ab85aa..28406a8fd776 100644
--- a/cui/source/options/optaboutconfig.hxx
+++ b/cui/source/options/optaboutconfig.hxx
@@ -37,6 +37,7 @@ private:
     std::unique_ptr<weld::Button> m_xResetBtn;
     std::unique_ptr<weld::Button> m_xEditBtn;
     std::unique_ptr<weld::Button> m_xSearchBtn;
+    std::unique_ptr<weld::CheckButton> m_xModifiedCheckBtn;
     std::unique_ptr<weld::Entry> m_xSearchEdit;
     std::unique_ptr<weld::TreeView> m_xPrefBox;
     std::unique_ptr<weld::TreeIter> m_xScratchIter;
@@ -62,6 +63,7 @@ private:
     DECL_LINK(DoubleClickHdl_Impl, weld::TreeView&, bool);
     DECL_LINK(ResetBtnHdl_Impl, weld::Button&, void);
     DECL_LINK(SearchHdl_Impl, weld::Button&, void);
+    DECL_LINK(ModifiedHdl_Impl, weld::Toggleable&, void);
     DECL_LINK(ExpandingHdl_Impl, const weld::TreeIter&, bool);
     DECL_LINK(HeaderBarClick, int, void);
     DECL_STATIC_LINK(CuiAboutConfigTabPage, ValidNameHdl, SvxNameDialog&, 
bool);
@@ -72,8 +74,10 @@ public:
     virtual ~CuiAboutConfigTabPage() override;
     void InsertEntry(const OUString& rPropertyPath, const OUString& rProp, 
const OUString& rStatus,
                      const OUString& rType, const OUString& rValue, const 
OUString& rTooltip,
-                     const weld::TreeIter* pParentEntry, bool 
bInsertToPrefBox, bool bIsReadOnly);
+                     const weld::TreeIter* pParentEntry, bool 
bInsertToPrefBox, bool bIsReadOnly,
+                     bool bWasMOdified);
     void Reset();
+    void InputChanged();
     void FillItems(const css::uno::Reference<css::container::XNameAccess>& 
xNameAccess,
                    const weld::TreeIter* pParentEntry = nullptr, int lineage = 
0,
                    bool bLoadAll = false);
diff --git a/cui/uiconfig/ui/aboutconfigdialog.ui 
b/cui/uiconfig/ui/aboutconfigdialog.ui
index 0d930df1fcc7..65436404895f 100644
--- a/cui/uiconfig/ui/aboutconfigdialog.ui
+++ b/cui/uiconfig/ui/aboutconfigdialog.ui
@@ -197,6 +197,20 @@
                 <property name="position">0</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkCheckButton" id="modifiedButton">
+                <property name="label" translatable="yes" 
context="aboutconfigdialog|modifiedButton">Show only modified 
preferences</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">False</property>
+                <property name="draw-indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkScrolledWindow">
                 <property name="visible">True</property>
@@ -236,6 +250,7 @@
                           <attributes>
                             <attribute name="sensitive">10</attribute>
                             <attribute name="text">1</attribute>
+                            <attribute name="weight">8</attribute>
                           </attributes>
                         </child>
                       </object>
@@ -251,6 +266,7 @@
                           <attributes>
                             <attribute name="sensitive">11</attribute>
                             <attribute name="text">2</attribute>
+                            <attribute name="weight">8</attribute>
                           </attributes>
                         </child>
                       </object>
@@ -266,6 +282,7 @@
                           <attributes>
                             <attribute name="sensitive">12</attribute>
                             <attribute name="text">3</attribute>
+                            <attribute name="weight">8</attribute>
                           </attributes>
                         </child>
                       </object>
@@ -281,6 +298,7 @@
                           <attributes>
                             <attribute name="sensitive">13</attribute>
                             <attribute name="text">4</attribute>
+                            <attribute name="weight">8</attribute>
                           </attributes>
                         </child>
                       </object>
diff --git a/offapi/com/sun/star/configuration/XDocumentation.idl 
b/offapi/com/sun/star/configuration/XDocumentation.idl
index f44a107c4508..7c82659eb2cc 100644
--- a/offapi/com/sun/star/configuration/XDocumentation.idl
+++ b/offapi/com/sun/star/configuration/XDocumentation.idl
@@ -43,6 +43,22 @@ interface XDocumentation {
     type getTypeByHierarchicalName( [in] string aName )
             raises( com::sun::star::container::NoSuchElementException,
                     com::sun::star::util::InvalidStateException );
+
+    /** @returns
+            whether the requested object was modified
+
+        @param aName
+            the hierarchical name of the object.
+
+        @throws NoSuchElementException
+            if an element under aName does not exist.
+
+        @throws InvalidStateException
+            when the object has an invalid type
+     */
+    boolean getModifiedByHierarchicalName( [in] string aName )
+            raises( com::sun::star::container::NoSuchElementException,
+                    com::sun::star::util::InvalidStateException );
 };
 
 }; }; }; };
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index fa9e7fa6d476..17e6435c3fc2 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -4419,8 +4419,21 @@ void SalInstanceTreeView::set_extra_row_indent(const 
weld::TreeIter& rIter, int
 
 void SalInstanceTreeView::set_text_emphasis(SvTreeListEntry* pEntry, bool bOn, 
int col)
 {
-    col = to_internal_model(col);
+    if (col == -1)
+    {
+        for (size_t nCur = 0; nCur < pEntry->ItemCount(); ++nCur)
+        {
+            SvLBoxItem& rItem = pEntry->GetItem(nCur);
+            if (rItem.GetType() == SvLBoxItemType::String)
+            {
+                static_cast<SvLBoxString&>(rItem).Emphasize(bOn);
+                InvalidateModelEntry(pEntry);
+            }
+        }
+        return;
+    }
 
+    col = to_internal_model(col);
     assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
     SvLBoxItem& rItem = pEntry->GetItem(col);
     assert(dynamic_cast<SvLBoxString*>(&rItem));
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index bf78cf85eeff..c76d6291cedf 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -15631,14 +15631,28 @@ public:
     virtual void set_text_emphasis(const weld::TreeIter& rIter, bool bOn, int 
col) override
     {
         const GtkInstanceTreeIter& rGtkIter = static_cast<const 
GtkInstanceTreeIter&>(rIter);
+        auto weight = bOn ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL;
+        if (col == -1)
+        {
+            for (const auto& elem : m_aWeightMap)
+                set(rGtkIter.iter, elem.second, weight);
+            return;
+        }
         col = to_internal_model(col);
-        set(rGtkIter.iter, m_aWeightMap[col], bOn ? PANGO_WEIGHT_BOLD : 
PANGO_WEIGHT_NORMAL);
+        set(rGtkIter.iter, m_aWeightMap[col], weight);
     }
 
     virtual void set_text_emphasis(int pos, bool bOn, int col) override
     {
+        auto weight = bOn ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL;
+        if (col == -1)
+        {
+            for (const auto& elem : m_aWeightMap)
+                set(pos, elem.second, weight);
+            return;
+        }
         col = to_internal_model(col);
-        set(pos, m_aWeightMap[col], bOn ? PANGO_WEIGHT_BOLD : 
PANGO_WEIGHT_NORMAL);
+        set(pos, m_aWeightMap[col], weight);
     }
 
     virtual bool get_text_emphasis(const weld::TreeIter& rIter, int col) const 
override

Reply via email to