sw/qa/uitest/chart/tdf149718.py     |   40 ++++++++++++++++++++++++++++++++++++
 sw/source/core/unocore/unochart.cxx |    8 ++++++-
 vcl/source/window/event.cxx         |   22 +++++++++++--------
 3 files changed, 60 insertions(+), 10 deletions(-)

New commits:
commit a71e40d37f177b2d4461db158282ae1c620e774e
Author:     Hossein <hoss...@libreoffice.org>
AuthorDate: Mon Oct 10 15:48:02 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Oct 19 08:33:08 2022 +0200

    tdf#149718 Fix crash on insert chart for tables with merged cells
    
    Previously inserting charts for tables with merged cells lead to crash.
    This was because a wrong assumption in unochart.cxx, specifically
    SwChartDataProvider::Impl_createDataSource() that every row has the same
    number of columns. Therefore the code was using the number of columns in
    the first row as the number of columns for all the rows, which is wrong.
    
    For example, inserting a chart for the second column of this table leads
    to a crash:
    
        [                      ]
        [    1     ][     2    ]
    
    In this way, an assertion failure was created because the number of
    columns where counted from the first row, which has merged cells, and
    therefore fewer number of columns compared to the last column of the
    selected part.
    
    To solve tdf#149718, now we use the maximum number of columns calculated
    across all the rows. In this way, the remainder of the function does not
    need a fix, although a cleanup for the whole function can be interesting
    and help avoid using tiny extra memory space.
    
    A UITest is provided to avoid this bug in the future. To run the test:
    
        cd sw && make -srj1 UITest_sw_chart \
        
UITEST_TEST_NAME="tdf149718.tdf149718.test_chart_from_table_with_merged_cells" \
        SAL_USE_VCLPLUGIN=gen
    
    Change-Id: I3c1000d7f177417e98d3a8ceae7886824c1053a6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140092
    Tested-by: Jenkins
    Reviewed-by: Hossein <hoss...@libreoffice.org>
    (cherry picked from commit d1707bc31261d16893c1f5240c803d283e293ec1)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141192
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/uitest/chart/tdf149718.py b/sw/qa/uitest/chart/tdf149718.py
new file mode 100644
index 000000000000..873379a36909
--- /dev/null
+++ b/sw/qa/uitest/chart/tdf149718.py
@@ -0,0 +1,40 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.framework import UITestCase
+from libreoffice.uno.propertyvalue import mkPropertyValues
+from uitest.uihelper.common import get_state_as_dict
+from uitest.uihelper.common import select_pos
+
+class tdf149718( UITestCase ):
+
+    def test_chart_from_table_with_merged_cells( self ):
+        with self.ui_test.create_doc_in_start_center("writer") as document:
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild("writer_edit")
+            with 
self.ui_test.execute_dialog_through_command(".uno:InsertTable") as xDialog:
+                formatlbinstable = xDialog.getChild("formatlbinstable")
+                entry = formatlbinstable.getChild("1")
+                entry.executeAction("SELECT", tuple())
+            xWriterEdit.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"RETURN"}))
+
+            self.xUITest.executeCommand(".uno:GoDown")
+            self.xUITest.executeCommand(".uno:CharRightSel")
+            self.xUITest.executeCommand(".uno:MergeCells")
+
+            self.xUITest.executeCommand(".uno:GoDown")
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"TEXT": "1"}))
+            self.xUITest.executeCommand(".uno:GoLeft")
+            self.xUITest.executeCommand(".uno:GoLeft")
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"TEXT": "1"}))
+            self.xUITest.executeCommand(".uno:CharRightSel")
+            with 
self.ui_test.execute_dialog_through_command(".uno:InsertObjectChart", 
close_button="finish") as xDialog:
+                 xWizard = xDialog.getChild('Wizard')
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/unocore/unochart.cxx 
b/sw/source/core/unocore/unochart.cxx
index edaa628c68f4..e1b8e14e33f5 100644
--- a/sw/source/core/unocore/unochart.cxx
+++ b/sw/source/core/unocore/unochart.cxx
@@ -644,7 +644,13 @@ uno::Reference< chart2::data::XDataSource > 
SwChartDataProvider::Impl_createData
     // get a character map in the size of the table to mark
     // all the ranges to use in
     sal_Int32 nRows = pTable->GetTabLines().size();
-    sal_Int32 nCols = pTable->GetTabLines().front()->GetTabBoxes().size();
+    sal_Int32 nCols = 0;
+    // As per tdf#149718 one should know that some cells can be merged 
together.
+    // Therefore, the number of columns (boxes in each row) are not necessarily
+    // equal. Here, we calculate the maximum number of columns in all rows.
+    for (sal_Int32 i = 0; i < nRows; ++i)
+        nCols = std::max(nCols, 
static_cast<sal_Int32>(pTable->GetTabLines()[i]->GetTabBoxes().size()));
+
     std::vector<std::vector<char>> aMap(nRows);
     for (sal_Int32 i = 0; i < nRows; ++i)
         aMap[i].resize(nCols);
commit 3a5f9015b1d3dfe377ba978adb6939cea550617f
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu Oct 13 13:51:43 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Oct 19 08:32:52 2022 +0200

    tdf#151352 crash closing form while TOTD dialog is displayed
    
    regression from
        commit 8d485ec0cd35ee1ae7684f2b6ca96c0f0c6f9dac
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Sat May 29 08:34:28 2021 +0200
        IsDisposed->isDisposed in vcl/../window
    
    Change-Id: I51889f2451f03797f5b89019e6df32a64acda707
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141292
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    (cherry picked from commit 3471299f1976499ab5f85fc6580b9633f4737399)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141321
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx
index 4b94b70bc11c..e11d032b933a 100644
--- a/vcl/source/window/event.cxx
+++ b/vcl/source/window/event.cxx
@@ -224,7 +224,11 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
 
     Application::ImplCallEventListeners( aEvent );
 
-    if ( xWindow->isDisposed() )
+    // if we have ObjectDying, then the bIsDisposed flag has already been set,
+    // but we still need to let listeners know.
+    const bool bIgnoreDisposed = nEvent == VclEventId::ObjectDying;
+
+    if ( !bIgnoreDisposed && xWindow->isDisposed() )
         return;
 
     // If maEventListeners is empty, the XVCLWindow has not yet been 
initialized.
@@ -240,9 +244,9 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
         mpWindowImpl->mnEventListenersIteratingCount++;
         auto& rWindowImpl = *mpWindowImpl;
         comphelper::ScopeGuard aGuard(
-            [&rWindowImpl, &xWindow]()
+            [&rWindowImpl, &xWindow, &bIgnoreDisposed]()
             {
-                if (!xWindow->isDisposed())
+                if (bIgnoreDisposed || !xWindow->isDisposed())
                 {
                     rWindowImpl.mnEventListenersIteratingCount--;
                     if (rWindowImpl.mnEventListenersIteratingCount == 0)
@@ -252,7 +256,7 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
         );
         for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
         {
-            if (xWindow->isDisposed()) break;
+            if (!bIgnoreDisposed && xWindow->isDisposed()) break;
             // check this hasn't been removed in some re-enterancy scenario 
fdo#47368
             if( rWindowImpl.maEventListenersDeleted.find(rLink) == 
rWindowImpl.maEventListenersDeleted.end() )
                 rLink.Call( aEvent );
@@ -262,7 +266,7 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
     while ( xWindow )
     {
 
-        if ( xWindow->isDisposed() )
+        if ( !bIgnoreDisposed && xWindow->isDisposed() )
             return;
 
         auto& rWindowImpl = *xWindow->mpWindowImpl;
@@ -273,9 +277,9 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
             // we use an iterating counter/flag and a set of deleted Link's to 
avoid O(n^2) behaviour
             rWindowImpl.mnChildEventListenersIteratingCount++;
             comphelper::ScopeGuard aGuard(
-                [&rWindowImpl, &xWindow]()
+                [&rWindowImpl, &xWindow, &bIgnoreDisposed]()
                 {
-                    if (!xWindow->isDisposed())
+                    if (bIgnoreDisposed || !xWindow->isDisposed())
                     {
                         rWindowImpl.mnChildEventListenersIteratingCount--;
                         if (rWindowImpl.mnChildEventListenersIteratingCount == 
0)
@@ -285,7 +289,7 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
             );
             for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
             {
-                if (xWindow->isDisposed())
+                if (!bIgnoreDisposed && xWindow->isDisposed())
                     return;
                 // Check this hasn't been removed in some re-enterancy 
scenario fdo#47368.
                 if( rWindowImpl.maChildEventListenersDeleted.find(rLink) == 
rWindowImpl.maChildEventListenersDeleted.end() )
@@ -293,7 +297,7 @@ void Window::CallEventListeners( VclEventId nEvent, void* 
pData )
             }
         }
 
-        if ( xWindow->isDisposed() )
+        if ( !bIgnoreDisposed && xWindow->isDisposed() )
             return;
 
         xWindow = xWindow->GetParent();

Reply via email to