diff --git a/sw/CppunitTest_sw_core_undo.mk b/sw/CppunitTest_sw_core_undo.mk index ea7f0becf02f..967324d9e9c3 100644 --- a/sw/CppunitTest_sw_core_undo.mk +++ b/sw/CppunitTest_sw_core_undo.mk @@ -21,6 +21,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_core_undo, \ comphelper \ cppu \ cppuhelper \ + editeng \ sal \ sfx \ subsequenttest \ diff --git a/sw/qa/core/undo/undo.cxx b/sw/qa/core/undo/undo.cxx index 5355eb4e9249..951a89a09c97 100644 --- a/sw/qa/core/undo/undo.cxx +++ b/sw/qa/core/undo/undo.cxx @@ -37,6 +37,17 @@ #include #include +#include +#include + +#include + +#include +#include + +#include +#include + /// Covers sw/source/core/undo/ fixes. class SwCoreUndoTest : public SwModelTestBase { @@ -332,6 +343,68 @@ CPPUNIT_TEST_FIXTURE(SwCoreUndoTest, testImagePropsCreateUndoAndModifyDoc) CPPUNIT_ASSERT(!pWrtShell->GetLastUndoInfo(nullptr, nullptr, nullptr)); } +CPPUNIT_TEST_FIXTURE(SwCoreUndoTest, testCropImageSingleUndo) +{ + // Cropping an image by dragging a handle is a single undo step. + createSwDoc("image-as-character.odt"); + SwXTextDocument* pTextDoc = getSwTextDoc(); + uno::Any aImage = pTextDoc->getGraphicObjects()->getByName(u"Image1"_ustr); + uno::Reference xImage(aImage, uno::UNO_QUERY_THROW); + + auto getCrop = [&xImage] { + css::text::GraphicCrop aCrop; + xImage->getPropertyValue(u"GraphicCrop"_ustr) >>= aCrop; + return aCrop; + }; + + const auto& rFormats = *getSwDoc()->GetSpzFrameFormats(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), rFormats.size()); + const Size aOldSize = rFormats[0]->GetFrameSize().GetSize(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getCrop().Left); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getCrop().Top); + + // Select the image and enter crop mode. + uno::Reference xSelectionSupplier( + pTextDoc->getCurrentController(), uno::UNO_QUERY_THROW); + xSelectionSupplier->select(aImage); + getSwDocShell()->GetView()->StopShellTimer(); + dispatchCommand(mxComponent, u".uno:Crop"_ustr, {}); + + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + const SdrHdlList& rHdlList = pWrtShell->GetDrawView()->GetHdlList(); + const SdrHdl* pTopLeft = rHdlList.GetHdl(0); + const SdrHdl* pBottomRight = rHdlList.GetHdl(7); + CPPUNIT_ASSERT(pTopLeft); + CPPUNIT_ASSERT(pBottomRight); + CPPUNIT_ASSERT_EQUAL(SdrHdlKind::UpperLeft, pTopLeft->GetKind()); + CPPUNIT_ASSERT_EQUAL(SdrHdlKind::LowerRight, pBottomRight->GetKind()); + + // Drag the upper left handle a quarter of the way towards the lower right one. + const Point aNewPos( + pTopLeft->GetPos().X() + (pBottomRight->GetPos().X() - pTopLeft->GetPos().X()) / 4, + pTopLeft->GetPos().Y() + (pBottomRight->GetPos().Y() - pTopLeft->GetPos().Y()) / 4); + uno::Sequence aArgs(comphelper::InitPropertySequence({ + { u"HandleNum"_ustr, uno::Any(sal_Int32(0)) }, + { u"NewPosX"_ustr, uno::Any(static_cast(aNewPos.X())) }, + { u"NewPosY"_ustr, uno::Any(static_cast(aNewPos.Y())) }, + })); + dispatchCommand(mxComponent, u".uno:MoveShapeHandle"_ustr, aArgs); + + CPPUNIT_ASSERT_GREATER(sal_Int32(0), getCrop().Left); + CPPUNIT_ASSERT_GREATER(sal_Int32(0), getCrop().Top); + CPPUNIT_ASSERT_LESS(aOldSize.Width(), rFormats[0]->GetFrameSize().GetWidth()); + + dispatchCommand(mxComponent, u".uno:Undo"_ustr, {}); + + // Without the fix, the crop was left for a second undo, so this failed with: + // - Expected: 0 + // - Actual : 1270 + // i.e. the frame had its original size back while the graphic stayed cropped. + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getCrop().Left); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getCrop().Top); + CPPUNIT_ASSERT_EQUAL(aOldSize, rFormats[0]->GetFrameSize().GetSize()); +} + CPPUNIT_TEST_FIXTURE(SwCoreUndoTest, testAnchorTypeChangePosition) { // Given a document with a textbox (draw + fly format pair) + an inner image: diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx index 36397d3fab20..4beee5d9f35a 100644 --- a/sw/source/core/draw/dflyobj.cxx +++ b/sw/source/core/draw/dflyobj.cxx @@ -913,7 +913,8 @@ void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, dou // Apply values pSh->StartAllAction(); - // pSh->StartUndo(SwUndoId::START); + // Group: crop changes the crop item, the frame size and possibly the position. + pSh->StartUndo(SwUndoId::START); // Set new crop values in twips aCrop.SetLeft (o3tl::toTwips(nLeftCrop, o3tl::Length::mm100)); @@ -978,7 +979,7 @@ void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, dou NbcMove(aDeltaMove); } - // pSh->EndUndo(SwUndoId::END); + pSh->EndUndo(SwUndoId::END); pSh->EndAllAction(); }