summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2020-12-01 00:05:43 +0100
committerRegina Henschel <rb.henschel@t-online.de>2020-12-02 19:06:43 +0100
commitd0921aa753c43600272865602df3c7c2a8f13196 (patch)
tree5d0818498fee3bdfdb7abaccee2c9a401a2b0895
parent0cffcf74a17449da56fb75557c7da1e1f6c5e94e (diff)
tdf#137576 Improve cell anchored measure line in Calc
Measure lines do not always have a logic rectangle. It might be empty or the 1cm x 1cm default square. But Calc needs it to calculate NonRotatedAnchor. The latter is needed for cell anchored shapes when saving in ODF. Always generating a logic rectangle in class SdrMeasureObj is difficult (I got crashes in Draw) and not necessary. Calc now forces the calculation of the logic rectangle where it is needed by Calc. Change-Id: I8689bc95985db1619eb5e72df99901bd52086cb2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106990 Tested-by: Jenkins Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-rw-r--r--sc/qa/unit/data/ods/ManualColWidthRowHeight.odsbin0 -> 8962 bytes
-rw-r--r--sc/qa/unit/scshapetest.cxx121
-rw-r--r--sc/source/core/data/drwlayer.cxx22
3 files changed, 135 insertions, 8 deletions
diff --git a/sc/qa/unit/data/ods/ManualColWidthRowHeight.ods b/sc/qa/unit/data/ods/ManualColWidthRowHeight.ods
new file mode 100644
index 000000000000..1cc738e05244
--- /dev/null
+++ b/sc/qa/unit/data/ods/ManualColWidthRowHeight.ods
Binary files differ
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 236cbc0879b4..c13ec7189622 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -13,10 +13,12 @@
#include <comphelper/propertyvalue.hxx>
#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdomeas.hxx>
#include <svx/svdpage.hxx>
#include <unotools/tempfile.hxx>
+#include <vcl/keycodes.hxx>
#include <docsh.hxx>
#include <drwlayer.hxx>
@@ -35,6 +37,8 @@ public:
ScShapeTest();
void saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent,
const OUString& rFilter);
+ void testTdf137576_LogicRectInDefaultMeasureline();
+ void testTdf137576_LogicRectInNewMeasureline();
void testMeasurelineHideColSave();
void testHideColsShow();
void testTdf138138_MoveCellWithRotatedShape();
@@ -46,6 +50,8 @@ public:
void testCustomShapeCellAnchoredRotatedShape();
CPPUNIT_TEST_SUITE(ScShapeTest);
+ CPPUNIT_TEST(testTdf137576_LogicRectInDefaultMeasureline);
+ CPPUNIT_TEST(testTdf137576_LogicRectInNewMeasureline);
CPPUNIT_TEST(testMeasurelineHideColSave);
CPPUNIT_TEST(testHideColsShow);
CPPUNIT_TEST(testTdf138138_MoveCellWithRotatedShape);
@@ -121,6 +127,121 @@ static void lcl_AssertPointEqualWithTolerance(const OString& sInfo, const Point
CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(), std::abs(rExpected.Y() - rActual.Y()) <= nTolerance);
}
+void ScShapeTest::testTdf137576_LogicRectInDefaultMeasureline()
+{
+ // Error was, that the empty logical rectangle of a default measure line (Ctrl+Click)
+ // resulted in zeros in NonRotatedAnchor and a wrong position when reloading.
+
+ // Load an empty document.
+ OUString aFileURL;
+ createFileURL("ManualColWidthRowHeight.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+ CPPUNIT_ASSERT(xComponent.is());
+
+ // Get ScDocShell
+ SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent);
+ CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+ CPPUNIT_ASSERT_MESSAGE("No ScDocShell", pDocSh);
+
+ // Create default measureline by SfxRequest that corresponds to Ctrl+Click
+ ScTabViewShell* pTabViewShell = pDocSh->GetBestViewShell(false);
+ CPPUNIT_ASSERT_MESSAGE("No ScTabViewShell", pTabViewShell);
+ SfxRequest aReq(pTabViewShell->GetViewFrame(), SID_DRAW_MEASURELINE);
+ aReq.SetModifier(KEY_MOD1); // Ctrl
+ pTabViewShell->ExecDraw(aReq);
+
+ // Get document and newly created measure line.
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ CPPUNIT_ASSERT_MESSAGE("No ScDrawLayer", pDrawLayer);
+ const SdrPage* pPage = pDrawLayer->GetPage(0);
+ CPPUNIT_ASSERT_MESSAGE("No draw page", pPage);
+ SdrObject* pObj = pPage->GetObj(0);
+ CPPUNIT_ASSERT_MESSAGE("No object found", pObj);
+
+ // Anchor "to Cell (resize with cell)"
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rDoc, 0 /*SCTAB*/, true /*bResizeWithCell*/);
+ // Deselect shape and switch to object selection type "Cell".
+ pTabViewShell->SetDrawShell(false);
+
+ // Hide column A.
+ uno::Sequence<beans::PropertyValue> aPropertyValues = {
+ comphelper::makePropertyValue("ToPoint", OUString("$A$1")),
+ };
+ dispatchCommand(xComponent, ".uno:GoToCell", aPropertyValues);
+ dispatchCommand(xComponent, ".uno:HideColumn", {});
+
+ // Get current position. I will not use absolute values for comparison, because document is loaded
+ // in full screen mode of unknown size and default object is placed in center of window.
+ Point aOldPos = pObj->GetRelativePos();
+
+ // Save and reload, get ScDocShell
+ saveAndReload(xComponent, "calc8");
+ CPPUNIT_ASSERT(xComponent);
+ pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent);
+ CPPUNIT_ASSERT_MESSAGE("Reload: Failed to access document shell", pFoundShell);
+ pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+ CPPUNIT_ASSERT(pDocSh);
+
+ // Get document and object
+ ScDocument& rDoc2 = pDocSh->GetDocument();
+ pDrawLayer = rDoc2.GetDrawLayer();
+ CPPUNIT_ASSERT_MESSAGE("Reload: No ScDrawLayer", pDrawLayer);
+ pPage = pDrawLayer->GetPage(0);
+ CPPUNIT_ASSERT_MESSAGE("Reload: No draw page", pPage);
+ pObj = pPage->GetObj(0);
+ CPPUNIT_ASSERT_MESSAGE("Measure line lost", pObj);
+
+ // Assert object position is unchanged, besides Twips<->Hmm inaccuracy.
+ Point aNewPos = pObj->GetRelativePos();
+ lcl_AssertPointEqualWithTolerance("after reload", aOldPos, aNewPos, 1);
+
+ pDocSh->DoClose();
+}
+
+void ScShapeTest::testTdf137576_LogicRectInNewMeasureline()
+{
+ // Error was, that a new measure line had no logical rectangle. This resulted in zeros in
+ // NonRotatedAnchor. As a result the position was wrong when reloading.
+
+ // Load an empty document
+ OUString aFileURL;
+ createFileURL("ManualColWidthRowHeight.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+ CPPUNIT_ASSERT(xComponent.is());
+
+ // Get ScDocShell
+ SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(xComponent);
+ CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(pFoundShell);
+ CPPUNIT_ASSERT(pDocSh);
+
+ // Get SdrPage
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ CPPUNIT_ASSERT_MESSAGE("No ScDrawLayer", pDrawLayer);
+ SdrPage* pPage = pDrawLayer->GetPage(0);
+ CPPUNIT_ASSERT_MESSAGE("No draw page", pPage);
+
+ // Create a new measure line and insert it
+ Point aStartPoint(5000, 5500);
+ Point aEndPoint(13000, 8000);
+ SdrMeasureObj* pObj = new SdrMeasureObj(*pDrawLayer, aStartPoint, aEndPoint);
+ CPPUNIT_ASSERT_MESSAGE("Could not create measure line", pObj);
+ pPage->InsertObject(pObj);
+
+ // Anchor "to cell (resize with cell)" and examine NonRotatedAnchor
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rDoc, 0 /*SCTAB*/, true /*bResizeWithCell*/);
+ ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData(pObj);
+ CPPUNIT_ASSERT_MESSAGE("Failed to get NonRotatedAnchor", pNData);
+ // Without the fix all four values would be zero.
+ CPPUNIT_ASSERT(pNData->maStart.Col() == 1 && pNData->maStart.Row() == 2);
+ CPPUNIT_ASSERT(pNData->maEnd.Col() == 7 && pNData->maEnd.Row() == 2);
+
+ pDocSh->DoClose();
+}
+
void ScShapeTest::testMeasurelineHideColSave()
{
// The document contains a SdrMeasureObj anchored "To Cell (resive with cell)" with start in cell
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 16fbe9c7f51c..eb329379398a 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -35,6 +35,7 @@
#include <svx/svdoashp.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdocapt.hxx>
+#include <svx/svdomeas.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdundo.hxx>
@@ -932,14 +933,13 @@ void ScDrawLayer::InitializeCellAnchoredObj(SdrObject* pObj, ScDrawObjData& rDat
else if (pObj->GetObjIdentifier() == OBJ_MEASURE)
{
// Measure lines might have got wrong start and end anchor from XML import. Recreate
- // them from start and end point.
- const Point aPoint0(pObj->GetPoint(0));
- const Point aPoint1(pObj->GetPoint(1));
- const Point aPointLT(std::min(aPoint0.X(), aPoint1.X()),
- std::min(aPoint0.Y(), aPoint1.Y()));
- const Point aPointRB(std::max(aPoint0.X(), aPoint1.X()),
- std::max(aPoint0.Y(), aPoint1.Y()));
- const tools::Rectangle aObjRect(aPointLT, aPointRB);
+ // anchor from start and end point.
+ SdrMeasureObj* pMeasureObj = dynamic_cast<SdrMeasureObj*>(pObj);
+ // tdf#137576. The logic rectangle has likely no current values here, but only the
+ // 1cm x 1cm default size. The call of TakeUnrotatedSnapRect is currently (LO 7.2)
+ // the only way to force a recalc of the logic rectangle.
+ tools::Rectangle aObjRect;
+ pMeasureObj->TakeUnrotatedSnapRect(aObjRect);
GetCellAnchorFromPosition(aObjRect, rNoRotatedAnchor, *pDoc, rData.maStart.Tab(),
false /*bHiddenAsZero*/);
}
@@ -2227,6 +2227,12 @@ void ScDrawLayer::SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument
aObjRect2 = rObj.GetLogicRect();
rObj.NbcMirror(aLeft, aRight);
}
+ else if (rObj.GetObjIdentifier() == OBJ_MEASURE)
+ {
+ // tdf#137576. A SdrMeasureObj might have a wrong logic rect here. TakeUnrotatedSnapRect
+ // calculates the current unrotated snap rectangle, sets logic rectangle and returns it.
+ static_cast<SdrObjCustomShape*>(&rObj)->TakeUnrotatedSnapRect(aObjRect2);
+ }
else
aObjRect2 = rObj.GetLogicRect();