sd/inc/stlsheet.hxx                    |    2 ++
 sd/source/core/stlsheet.cxx            |   29 +++++++++++++++++++++++++++++
 sd/source/ui/table/TableDesignPane.cxx |   16 +++++++++-------
 3 files changed, 40 insertions(+), 7 deletions(-)

New commits:
commit 423c2a6ac74cd30c6576e6794f67fda4fb685c11
Author:     Maxim Monastirsky <momonas...@gmail.com>
AuthorDate: Thu Nov 24 21:22:42 2022 +0200
Commit:     Maxim Monastirsky <momonas...@gmail.com>
CommitDate: Fri Nov 25 14:17:22 2022 +0100

    sd: better detection of user defined cell styles
    
    Cell style might be used for several table roles
    at once, or even in several table styles (esp.
    after new/clone actions). But when we're editing a
    style, we want just a single place to be changed.
    
    The initial solution was to check if the style is
    user defined. The problem is that if we change the
    built-in styles set, then documents created with
    the old styles will have their once built-in styles
    turned into user defined. In such case we might
    still attempt to edit a shared style, which is
    unintended.
    
    So try harder, and check also that the style isn't
    used twice and that there is no other styles
    inheriting from it.
    
    Change-Id: I67d8c61b15161c9d839e97f7a31a1349a7e2613c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143288
    Tested-by: Jenkins
    Reviewed-by: Maxim Monastirsky <momonas...@gmail.com>

diff --git a/sd/inc/stlsheet.hxx b/sd/inc/stlsheet.hxx
index 645259e9e8fc..9080c3b8805b 100644
--- a/sd/inc/stlsheet.hxx
+++ b/sd/inc/stlsheet.hxx
@@ -63,6 +63,8 @@ public:
     virtual bool        HasClearParentSupport() const override;
     virtual void        SetHelpId( const OUString& r, sal_uLong nId ) override;
 
+    bool IsEditable();
+
     void        AdjustToFontHeight(SfxItemSet& rSet, bool bOnlyMissingItems = 
true);
 
     SdStyleSheet* GetRealStyleSheet() const;
diff --git a/sd/source/core/stlsheet.cxx b/sd/source/core/stlsheet.cxx
index 1c11e5fea39d..4d72cf0915c6 100644
--- a/sd/source/core/stlsheet.cxx
+++ b/sd/source/core/stlsheet.cxx
@@ -325,6 +325,35 @@ bool SdStyleSheet::IsUsed() const
     return bResult;
 }
 
+/**
+ * Checks if a cell style is used in two places at once.
+ * Typically we modify the formatting of a single place,
+ * so such style shouldn't be edited directly.
+ */
+bool SdStyleSheet::IsEditable()
+{
+    if (GetFamily() != SfxStyleFamily::Frame)
+        return true;
+
+    if (!IsUserDefined())
+        return false;
+
+    const size_t nListenerCount = GetSizeOfVector();
+    for (size_t n = 0; n < nListenerCount; ++n)
+    {
+        SfxListener* pListener = GetListener(n);
+        if (pListener == this)
+            continue;
+        if (dynamic_cast<SdStyleSheet*>(pListener))
+            return false;
+    }
+
+    MutexGuard aGuard(mrBHelper.rMutex);
+
+    auto pContainer = 
mrBHelper.getContainer(cppu::UnoType<XModifyListener>::get());
+    return !pContainer || pContainer->getLength() <= 1;
+}
+
 /**
  * Determine the style sheet for which this dummy is for.
  */
diff --git a/sd/source/ui/table/TableDesignPane.cxx 
b/sd/source/ui/table/TableDesignPane.cxx
index dd7749db7e79..aa331c3dcda1 100644
--- a/sd/source/ui/table/TableDesignPane.cxx
+++ b/sd/source/ui/table/TableDesignPane.cxx
@@ -303,8 +303,10 @@ void TableDesignWidget::ResetStyle()
         for (sal_Int32 i = 0; i < xTableStyle->getCount(); ++i)
         {
             Reference<XStyle> xCellStyle(xTableStyle->getByIndex(i), 
UNO_QUERY);
-            if (xCellStyle && xCellStyle->isUserDefined())
-                xTableStyle->replaceByIndex(i, 
mxCellFamily->getByName(xCellStyle->getParentStyle()));
+            while (xCellStyle && xCellStyle->isUserDefined() && 
!xCellStyle->getParentStyle().isEmpty())
+                
xCellStyle.set(mxCellFamily->getByName(xCellStyle->getParentStyle()), 
UNO_QUERY);
+
+            xTableStyle->replaceByIndex(i, Any(xCellStyle));
         }
 
         endTextEditForStyle(xTableStyle);
@@ -353,17 +355,17 @@ void TableDesignWidget::EditStyle(std::string_view 
rCommand)
     {
         Reference<XNameReplace> 
xTableStyle(mxTableFamily->getByIndex(m_xValueSet->GetSelectedItemId() - 1), 
UNO_QUERY_THROW);
         Reference<XStyle> 
xCellStyle(xTableStyle->getByName(OUString::fromUtf8(rCommand)), 
UNO_QUERY_THROW);
+        rtl::Reference xStyleSheet = 
static_cast<SdStyleSheet*>(xCellStyle.get());
 
-        bool bUserDefined = xCellStyle->isUserDefined();
+        bool bUserDefined = xStyleSheet->IsEditable();
         if (!bUserDefined)
         {
             Reference<XSingleServiceFactory> xFactory(mxCellFamily, 
UNO_QUERY_THROW);
-            Reference<XStyle> xNewStyle(xFactory->createInstance(), 
UNO_QUERY_THROW);
-            xNewStyle->setParentStyle(xCellStyle->getName());
-            xCellStyle = xNewStyle;
+            xCellStyle.set(xFactory->createInstance(), UNO_QUERY_THROW);
+            xCellStyle->setParentStyle(xStyleSheet->getName());
+            xStyleSheet = static_cast<SdStyleSheet*>(xCellStyle.get());
         }
 
-        rtl::Reference xStyleSheet = 
static_cast<SdStyleSheet*>(xCellStyle.get());
         SfxItemSet aNewAttr(xStyleSheet->GetItemSet());
 
         // merge drawing layer text distance items into SvxBoxItem used by the 
dialog

Reply via email to