desktop/source/lib/init.cxx | 1 editeng/source/editeng/editview.cxx | 5 - include/vcl/window.hxx | 2 sc/inc/inputopt.hxx | 3 sc/inc/sc.hrc | 1 sc/qa/unit/tiledrendering/tiledrendering.cxx | 115 +++++++++++++++++++++++++++ sc/sdi/cellsh.sdi | 2 sc/sdi/scalc.sdi | 15 +++ sc/source/core/tool/inputopt.cxx | 1 sc/source/ui/app/inputhdl.cxx | 14 +++ sc/source/ui/inc/gridwin.hxx | 1 sc/source/ui/inc/tabvwsh.hxx | 5 + sc/source/ui/view/cellsh3.cxx | 20 ++++ sc/source/ui/view/gridwin4.cxx | 26 ++++++ sc/source/ui/view/tabvwsh4.cxx | 1 vcl/source/window/paint.cxx | 5 + 16 files changed, 216 insertions(+), 1 deletion(-)
New commits: commit 72050d165514b3682c09d1f022bbd8eb1e9e8cfb Author: Marco Cecchetti <marco.cecche...@collabora.com> AuthorDate: Mon Dec 4 09:31:23 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Jan 16 22:28:41 2024 +0100 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 <jenkinscollaboraoff...@gmail.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162161 Tested-by: Jenkins diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx index e047e6a41ffa..ff979af96698 100644 --- a/editeng/source/editeng/editview.cxx +++ b/editeng/source/editeng/editview.cxx @@ -231,7 +231,10 @@ void EditView::InvalidateOtherViewWindows( const tools::Rectangle& rInvRect ) for (auto& pWin : pImpEditView->aOutWindowSet) { if (pWin) - pWin->Invalidate( bNegativeX ? lcl_negateRectX(rInvRect) : rInvRect ); + { + if (!pWin->InvalidateByForeignEditView(this)) + pWin->Invalidate( bNegativeX ? lcl_negateRectX(rInvRect) : rInvRect ); + } } } } diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 640e9c6c9983..74f1d395e9ad 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -62,6 +62,7 @@ class VclWindowEvent; class AllSettings; class InputContext; class VclEventListeners; +class EditView; enum class ImplPaintFlags; enum class VclEventId; enum class PointerStyle; @@ -967,6 +968,7 @@ public: */ virtual void LogicInvalidate(const tools::Rectangle* pRectangle); + virtual bool InvalidateByForeignEditView(EditView* ); /** * Notification about some rectangle of the output device got invalidated. Used for the * dialogs and floating windows (e.g. context menu, popup). 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(); diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx index a98703ca255b..7cb1c969a983 100644 --- a/vcl/source/window/paint.cxx +++ b/vcl/source/window/paint.cxx @@ -1198,6 +1198,11 @@ void Window::LogicInvalidate(const tools::Rectangle* pRectangle) PixelInvalidate(nullptr); } +bool Window::InvalidateByForeignEditView(EditView* ) +{ + return false; +} + void Window::PixelInvalidate(const tools::Rectangle* pRectangle) { if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive()) commit 608d6db0399f1a3cf908ab64de01985a4bfcce3b Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Fri Jan 5 16:42:03 2024 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Jan 16 22:12:07 2024 +0100 uninitialized class members since: commit 284f2759dedbc2375abdbaab5258efda4a52b8f5 Date: Mon Dec 4 14:08:09 2023 +0000 calc: Add option to keep edit mode on enter/tab Change-Id: I47431f9096e12fe84ad13a139fba60ddd88793d1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161697 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sc/source/core/tool/inputopt.cxx b/sc/source/core/tool/inputopt.cxx index 13781040ee22..08d4feff60dc 100644 --- a/sc/source/core/tool/inputopt.cxx +++ b/sc/source/core/tool/inputopt.cxx @@ -32,6 +32,7 @@ using namespace com::sun::star::uno; ScInputOptions::ScInputOptions() : nMoveDir(DIR_BOTTOM) , bMoveSelection(true) + , bMoveKeepEdit(false) , bEnterEdit(false) , bExtendFormat(false) , bRangeFinder(true) diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx index 345a33534d1c..7d20ed10a085 100644 --- a/sc/source/ui/view/tabvwsh4.cxx +++ b/sc/source/ui/view/tabvwsh4.cxx @@ -1708,6 +1708,7 @@ ScTabViewShell::ScTabViewShell( SfxViewFrame& rViewFrame, bForceFocusOnCurCell(false), bInPrepareClose(false), bInDispose(false), + bMoveKeepEdit(false), nCurRefDlgId(0), mbInSwitch(false), m_pDragData(new ScDragData) commit dee7f73d312d063c8a445dbcb735bb8fa23fa61b Author: Skyler Grey <skyler.g...@collabora.com> AuthorDate: Mon Dec 4 14:08:09 2023 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Jan 16 22:11:38 2024 +0100 calc: Add option to keep edit mode on enter/tab This change makes it so that, rather than leaving edit mode, enter and tab keep editing the new cell when they have moved. This is important on devices with an onscreen keyboard (e.g. iPads, Android tablets, Convertible Laptops, etc.), particularly in Collabora Online, as exiting edit mode hides the onscreen keyboard. It is not desirable to enable this by default, as arrow keys cannot move around the document when we are in edit mode (they move within the cell). Therefore, this commit also adds an .uno command so that we can activate or deactivate the option. In LibreOfficeKit we want to make sure not to share this setting among different users, so we also add this option in the view shell and switch which one we care about based on whether Kit is active. Change-Id: I5e6c93c64af0d201a8ec045fea5546e189baca74 Signed-off-by: Skyler Grey <skyler.g...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160313 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Szymon Kłos <szymon.k...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161696 Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 6701988a5c0a..faa6d44cd447 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -3823,6 +3823,7 @@ static void doc_iniUnoCommands () u".uno:InsertPictureContentControl"_ustr, u".uno:DataFilterAutoFilter"_ustr, u".uno:CellProtection"_ustr, + u".uno:MoveKeepInsertMode"_ustr }; util::URL aCommandURL; diff --git a/sc/inc/inputopt.hxx b/sc/inc/inputopt.hxx index 05e59aad5716..aa4b4078e5df 100644 --- a/sc/inc/inputopt.hxx +++ b/sc/inc/inputopt.hxx @@ -26,6 +26,7 @@ class ScInputOptions private: sal_uInt16 nMoveDir; // enum ScDirection bool bMoveSelection; + bool bMoveKeepEdit; bool bEnterEdit; bool bExtendFormat; bool bRangeFinder; @@ -47,6 +48,8 @@ public: bool GetMoveSelection() const { return bMoveSelection; } void SetEnterEdit(bool bSet) { bEnterEdit = bSet; } bool GetEnterEdit() const { return bEnterEdit; } + void SetMoveKeepEdit(bool bSet) { bMoveKeepEdit = bSet; } + bool GetMoveKeepEdit() const { return bMoveKeepEdit; } void SetExtendFormat(bool bSet) { bExtendFormat = bSet; } bool GetExtendFormat() const { return bExtendFormat; } void SetRangeFinder(bool bSet) { bRangeFinder = bSet; } diff --git a/sc/inc/sc.hrc b/sc/inc/sc.hrc index f6f445fc5a2e..54d4c0b5a0e2 100644 --- a/sc/inc/sc.hrc +++ b/sc/inc/sc.hrc @@ -247,6 +247,7 @@ class SvxZoomSliderItem; #define SID_OPEN_CALC (SC_FUNCTION_START + 4) #define SID_CONVERT_FORMULA_TO_VALUE (SC_FUNCTION_START + 5) +#define FID_MOVE_KEEP_INSERT_MODE (SC_FUNCTION_START + 6) #ifndef FILE_MENU_END // duplicated in sfx2/sfxsids.hrc #define FILE_MENU_END (SC_FUNCTION_START + 20) #endif diff --git a/sc/sdi/cellsh.sdi b/sc/sdi/cellsh.sdi index 84217c63c949..7370d142607e 100644 --- a/sc/sdi/cellsh.sdi +++ b/sc/sdi/cellsh.sdi @@ -446,6 +446,8 @@ interface CellMovement ] SID_DATA_SELECT [ ExecMethod = Execute; StateMethod = GetState; ] SID_DETECTIVE_FILLMODE [ ExecMethod = Execute; StateMethod = GetState; ] // api: + + FID_MOVE_KEEP_INSERT_MODE [ ExecMethod = Execute; ] } diff --git a/sc/sdi/scalc.sdi b/sc/sdi/scalc.sdi index d26e99ce2f5d..38151604a3d9 100644 --- a/sc/sdi/scalc.sdi +++ b/sc/sdi/scalc.sdi @@ -6685,3 +6685,18 @@ SfxVoidItem AutoSum SID_AUTO_SUM ToolBoxConfig = TRUE, GroupId = SfxGroupId::Intern; ] + + +SfxVoidItem MoveKeepInsertMode FID_MOVE_KEEP_INSERT_MODE +(SfxBoolItem Enable FID_MOVE_KEEP_INSERT_MODE) +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + GroupId = SfxGroupId::Application; +] diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index 809ba8520e33..e7e7f6041c8a 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -3811,6 +3811,14 @@ bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false if (pActiveViewSh) pActiveViewSh->FindNextUnprot( bShift, true ); + + ScModule* pScMod = SC_MOD(); + const ScInputOptions& rOpt = pScMod->GetInputOptions(); + + if ( (rOpt.GetMoveKeepEdit() && !comphelper::LibreOfficeKit::isActive()) + || (pActiveViewSh->GetMoveKeepEdit() && comphelper::LibreOfficeKit::isActive()) ) + pScMod->SetInputMode( SC_INPUT_TABLE ); + return true; } @@ -3851,6 +3859,12 @@ bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false if (pActiveViewSh) pActiveViewSh->MoveCursorEnter( bShift && !bControl ); + ScModule* pScMod = SC_MOD(); + const ScInputOptions& rOpt = pScMod->GetInputOptions(); + if ( (rOpt.GetMoveKeepEdit() && !comphelper::LibreOfficeKit::isActive()) + || (pActiveViewSh->GetMoveKeepEdit() && comphelper::LibreOfficeKit::isActive()) ) + pScMod->SetInputMode( SC_INPUT_TABLE ); + bUsed = true; } break; diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx index b537af6900d2..fff123aa1bc6 100644 --- a/sc/source/ui/inc/tabvwsh.hxx +++ b/sc/source/ui/inc/tabvwsh.hxx @@ -174,6 +174,8 @@ private: bool bInPrepareClose; bool bInDispose; + bool bMoveKeepEdit; + sal_uInt16 nCurRefDlgId; std::unique_ptr<SfxBroadcaster> pAccessibilityBroadcaster; @@ -437,6 +439,9 @@ public: void ResetDragObject(); void SetDragLink(const OUString& rDoc, const OUString& rTab, const OUString& rArea); void SetDragJump(ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText); + + void SetMoveKeepEdit(bool value) { bMoveKeepEdit = value; }; + bool GetMoveKeepEdit() { return bMoveKeepEdit; }; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/cellsh3.cxx b/sc/source/ui/view/cellsh3.cxx index e6c89b6a2b9c..b7bd2daa4450 100644 --- a/sc/source/ui/view/cellsh3.cxx +++ b/sc/source/ui/view/cellsh3.cxx @@ -40,6 +40,7 @@ #include <autoform.hxx> #include <cellsh.hxx> #include <inputhdl.hxx> +#include <inputopt.hxx> #include <editable.hxx> #include <funcdesc.hxx> #include <markdata.hxx> @@ -1087,6 +1088,25 @@ void ScCellShell::Execute( SfxRequest& rReq ) OSL_FAIL("old slot SID_MARKAREA"); break; + case FID_MOVE_KEEP_INSERT_MODE: + { + const SfxBoolItem* pEnabledArg = rReq.GetArg<SfxBoolItem>(FID_MOVE_KEEP_INSERT_MODE); + if (!pEnabledArg) { + SAL_WARN("sfx.appl", "FID_MOVE_KEEP_INSERT_MODE: must specify if you would like this to be enabled"); + break; + } + + ScInputOptions aInputOptions = pScMod->GetInputOptions(); + + aInputOptions.SetMoveKeepEdit(pEnabledArg->GetValue()); + pScMod->SetInputOptions(aInputOptions); + + if (comphelper::LibreOfficeKit::isActive()) + pTabViewShell->SetMoveKeepEdit(pEnabledArg->GetValue()); + + break; + } + default: OSL_FAIL("ScCellShell::Execute: unknown slot"); break;