summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2023-12-04 09:31:23 +0100
committerAndras Timar <andras.timar@collabora.com>2024-01-16 22:28:41 +0100
commit72050d165514b3682c09d1f022bbd8eb1e9e8cfb (patch)
tree14dab7b796f0f51b7a20507c89c8aeef5a94d986 /sc
parent608d6db0399f1a3cf908ab64de01985a4bfcce3b (diff)
calc: on editing invalidation of view with different zoom is wrong
This patch fixes the following invalidation issue: There are 2 views with different zoom levels. In a view text editing for a cell occurs. The other view is not invalidated properly: the computed invalidation rectangle is misplaced. Change-Id: I72db61486647640ee68e6cb2db96b2902de5b997 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160303 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Tested-by: Caolán McNamara <caolan.mcnamara@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162161 Tested-by: Jenkins
Diffstat (limited to 'sc')
-rw-r--r--sc/qa/unit/tiledrendering/tiledrendering.cxx115
-rw-r--r--sc/source/ui/inc/gridwin.hxx1
-rw-r--r--sc/source/ui/view/gridwin4.cxx26
3 files changed, 142 insertions, 0 deletions
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 737c1a534cce..ee2b50522e3f 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -9,6 +9,7 @@
#include <test/unoapixml_test.hxx>
#include <test/helper/transferable.hxx>
+#include <cppunit/tools/StringHelper.h>
#include <boost/property_tree/json_parser.hpp>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
@@ -64,6 +65,32 @@ static std::ostream& operator<<(std::ostream& os, ViewShellId const & id)
os << static_cast<sal_Int32>(id); return os;
}
+namespace {
+// for passing data to testInvalidateOnTextEditWithDifferentZoomLevels
+struct ColRowZoom
+{
+ SCCOL col;
+ SCROW row;
+ int zoom;
+};
+}
+
+CPPUNIT_NS_BEGIN
+namespace StringHelper
+{
+// used by CPPUNIT_TEST_PARAMETERIZED for testInvalidateOnTextEditWithDifferentZoomLevels
+template<>
+inline std::string toString(const ColRowZoom& item)
+{
+ std::ostringstream ss;
+ ss << "zoom level: " << item.zoom << ", "
+ "col: " << item.col << ", "
+ "row: " << item.row;
+ return ss.str();
+}
+}
+CPPUNIT_NS_END
+
class ScTiledRenderingTest : public UnoApiXmlTest
{
public:
@@ -3144,6 +3171,94 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testGetViewRenderState)
CPPUNIT_ASSERT_EQUAL(";Default"_ostr, pModelObj->getViewRenderState());
}
+/*
+ * testInvalidateOnTextEditWithDifferentZoomLevels
+ * steps:
+ * set view 1 zoom to the passed zoom level
+ * in view 1 type a char at the passed cell address
+ * store invalidation rectangle
+ * exit from in place editing (press esc)
+ * create view 2 (keep 100% zoom)
+ * go to the same cell address used in view 1
+ * type a char into the cell
+ * get invalidation rectangle for view 1
+ * check if the invalidation rectangle is equal to the one stored previously
+*/
+class testInvalidateOnTextEditWithDifferentZoomLevels : public ScTiledRenderingTest
+{
+public:
+ void TestBody(const ColRowZoom& rData);
+ CPPUNIT_TEST_SUITE(testInvalidateOnTextEditWithDifferentZoomLevels);
+ CPPUNIT_TEST_PARAMETERIZED(TestBody,
+ std::initializer_list<ColRowZoom>
+ {
+ // zoom level 120%
+ {0, 999, 1}, {99, 0, 1},
+ // zoom level 40%
+ {0, 999, -5}, {99, 0, -5}
+ });
+ CPPUNIT_TEST_SUITE_END();
+};
+CPPUNIT_TEST_SUITE_REGISTRATION(testInvalidateOnTextEditWithDifferentZoomLevels);
+
+void testInvalidateOnTextEditWithDifferentZoomLevels::TestBody(const ColRowZoom& rData)
+{
+ ScModelObj* pModelObj = createDoc("empty.ods");
+ CPPUNIT_ASSERT(pModelObj);
+ ScDocument* pDoc = pModelObj->GetDocument();
+ CPPUNIT_ASSERT(pDoc);
+ OUString sZoomUnoCmd = ".uno:ZoomPlus";
+ int nZoomLevel = rData.zoom;
+ if (nZoomLevel < 0)
+ {
+ nZoomLevel = -nZoomLevel;
+ sZoomUnoCmd = ".uno:ZoomMinus";
+ }
+ // view #1
+ ViewCallback aView1;
+ // set zoom level
+ for (int i = 0; i < nZoomLevel; ++i)
+ dispatchCommand(mxComponent, sZoomUnoCmd, {});
+ Scheduler::ProcessEventsToIdle();
+ auto* pTabViewShell1 = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+ CPPUNIT_ASSERT(pTabViewShell1);
+ // enable in place editing in view 1
+ auto& rInvalidations = aView1.m_aInvalidations;
+ pTabViewShell1->SetCursor(rData.col, rData.row);
+ Scheduler::ProcessEventsToIdle();
+ aView1.m_bInvalidateTiles = false;
+ rInvalidations.clear();
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(aView1.m_bInvalidateTiles);
+ CPPUNIT_ASSERT(!rInvalidations.empty());
+ tools::Rectangle aInvRect1 = rInvalidations[0];
+ // end editing
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE);
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE);
+ Scheduler::ProcessEventsToIdle();
+ // view #2
+ SfxLokHelper::createView();
+ pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ ViewCallback aView2;
+ Scheduler::ProcessEventsToIdle();
+ auto* pTabViewShell2 = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+ CPPUNIT_ASSERT(pTabViewShell2);
+ pTabViewShell2->SetCursor(rData.col, rData.row);
+ Scheduler::ProcessEventsToIdle();
+ // text edit in view #2
+ aView1.m_bInvalidateTiles = false;
+ rInvalidations.clear();
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(aView1.m_bInvalidateTiles);
+ CPPUNIT_ASSERT(!rInvalidations.empty());
+ tools::Rectangle aInvRect2 = rInvalidations[0];
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalidation rectangle is wrong.", aInvRect1, aInvRect2);
+}
+
CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testOpenURL)
{
// Given a document that has 2 views:
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 37c38fe069a0..b86331d6f96e 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -381,6 +381,7 @@ public:
void LogicInvalidate(const tools::Rectangle* pRectangle) override;
void LogicInvalidatePart(const tools::Rectangle* pRectangle, int nPart);
+ bool InvalidateByForeignEditView(EditView* pEditView) override;
/// Update the cell selection according to what handles have been dragged.
/// @see vcl::ITiledRenderable::setTextSelection() for the values of nType.
/// Coordinates are in pixels.
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index ea59babd3a14..b6ef7367ff68 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -671,6 +671,11 @@ int lcl_GetMultiLineHeight(EditEngine* pEditEngine)
return nHeight;
}
+
+tools::Rectangle lcl_negateRectX(const tools::Rectangle& rRect)
+{
+ return tools::Rectangle(-rRect.Right(), rRect.Top(), -rRect.Left(), rRect.Bottom());
+}
}
void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableInfo, ScOutputData& aOutputData,
@@ -1767,6 +1772,27 @@ void ScGridWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
LogicInvalidatePart(pRectangle, pViewShell->getPart());
}
+bool ScGridWindow::InvalidateByForeignEditView(EditView* pEditView)
+{
+ if (!pEditView)
+ return false;
+
+ auto* pGridWin = dynamic_cast<ScGridWindow*>(pEditView->GetWindow());
+ if (!pGridWin)
+ return false;
+
+ const ScViewData& rViewData = pGridWin->getViewData();
+ tools::Long nRefTabNo = rViewData.GetRefTabNo();
+ tools::Long nX = rViewData.GetCurXForTab(nRefTabNo);
+ tools::Long nY = rViewData.GetCurYForTab(nRefTabNo);
+
+ tools::Rectangle aPixRect = getViewData().GetEditArea(eWhich, nX, nY, this, nullptr, true);
+ tools::Rectangle aLogicRect = PixelToLogic(aPixRect, getViewData().GetLogicMode());
+ Invalidate(pEditView->IsNegativeX() ? lcl_negateRectX(aLogicRect) : aLogicRect);
+
+ return true;
+}
+
void ScGridWindow::SetCellSelectionPixel(int nType, int nPixelX, int nPixelY)
{
ScTabView* pTabView = mrViewData.GetView();