summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2021-01-26 14:28:40 +0100
committerXisco Fauli <xiscofauli@libreoffice.org>2021-02-10 13:40:33 +0100
commit7b2999ab91aa6fc6632dd87ca0bc950e5484c35a (patch)
treeeb54cc386b2e715025f98a73cff3b36e98fcbe69
parent297f511263db7434bb10cdc91230b4d3f8ac9aa0 (diff)
tdf#137081, tdf137082 fixes shape handling in RTL sheets
The patch introduces an enum ScObjectHandling as parameter of ScDrawLayer::SetPageSize to distinguish page size changes from show or hide col/row from changes because of sheet flip for RTL. RTL is now handled this way: On save/reload objects are not mirrored but only shifted between positive and negative part of draw page. When a user flips sheet to RTL or back, the objects are mirrored. The 'noRotate' anchor is set to this meaning: maShapeRect contains the logic rectangle of the object at time the anchor was created. It is used to detect position relevant object changes in ScDrawView::Notify(). maStart contains the address of that cell, which is parent element of the object in xml. The logic rectangle need not be in that cell. Handling of DetectiveArrow and CellNote is not changed. Validation circles were not drawn, when switching to RTL mode (no bug report). That is fixed. SetVisualCellAnchored handles 'noRotate' anchor. That anchor is not visible on screen. I have changed the misleading name to SetNonRotatedAnchor. Change-Id: I3dd2d3e37c138c8418369c760293a1f19dddb753 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109959 Reviewed-by: Regina Henschel <rb.henschel@t-online.de> Tested-by: Regina Henschel <rb.henschel@t-online.de> Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110657 Tested-by: Jenkins
-rw-r--r--sc/inc/document.hxx3
-rw-r--r--sc/inc/drwlayer.hxx14
-rw-r--r--sc/inc/table.hxx4
-rw-r--r--sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.odsbin0 -> 10079 bytes
-rw-r--r--sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.odsbin0 -> 10430 bytes
-rw-r--r--sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.odsbin0 -> 9779 bytes
-rw-r--r--sc/qa/unit/scshapetest.cxx154
-rw-r--r--sc/source/core/data/documen9.cxx4
-rw-r--r--sc/source/core/data/document.cxx14
-rw-r--r--sc/source/core/data/drwlayer.cxx162
-rw-r--r--sc/source/core/data/table2.cxx6
-rw-r--r--sc/source/filter/xml/xmlexprt.cxx78
-rw-r--r--sc/source/ui/docshell/docfunc.cxx2
-rw-r--r--sc/source/ui/undo/undotab.cxx2
14 files changed, 374 insertions, 69 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 1d6a20efd2af..46f3e51d1a99 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -53,6 +53,7 @@
#include <vector>
#include "markdata.hxx"
+#include "drwlayer.hxx"
namespace com::sun::star::chart2 { class XChartDocument; }
@@ -963,7 +964,7 @@ public:
bool IsStreamValidLocked() const { return mbStreamValidLocked; }
bool IsPendingRowHeights( SCTAB nTab ) const;
void SetPendingRowHeights( SCTAB nTab, bool bSet );
- SC_DLLPUBLIC void SetLayoutRTL( SCTAB nTab, bool bRTL );
+ SC_DLLPUBLIC void SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling eObjectHandling = ScObjectHandling::RecalcPosMode);
SC_DLLPUBLIC bool IsLayoutRTL( SCTAB nTab ) const;
SC_DLLPUBLIC bool IsNegativePage( SCTAB nTab ) const;
SC_DLLPUBLIC void SetScenario( SCTAB nTab, bool bFlag );
diff --git a/sc/inc/drwlayer.hxx b/sc/inc/drwlayer.hxx
index d0efb68513fa..547368dbe2bc 100644
--- a/sc/inc/drwlayer.hxx
+++ b/sc/inc/drwlayer.hxx
@@ -86,6 +86,14 @@ public:
virtual void Redo() override;
};
+// for ScDrawLayer::SetPageSize
+enum class ScObjectHandling
+{
+ RecalcPosMode, // used for row height or col width changes
+ MoveRTLMode, // used for switch to RTL during import of right-to-left sheet
+ MirrorRTLMode // used for switch between RTL and LTR by .uno:SheetRightToLeft
+};
+
class SC_DLLPUBLIC ScDrawLayer final : public FmFormModel
{
private:
@@ -150,10 +158,12 @@ public:
SCTAB nSourceTab, const tools::Rectangle& rSourceRange,
const ScAddress& rDestPos, const tools::Rectangle& rDestRange );
- void SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos );
+ void SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos,
+ const ScObjectHandling eObjectHandling = ScObjectHandling::RecalcPosMode);
// mirror or move between positive and negative positions for RTL
void MirrorRTL( SdrObject* pObj );
+ void MoveRTL(SdrObject* pObj);
static void MirrorRectRTL( tools::Rectangle& rRect ); // for bounding rectangles etc.
/** Returns the rectangle for the passed cell address in 1/100 mm.
@@ -174,7 +184,7 @@ public:
static bool IsResizeWithCell( const SdrObject& rObj );
static void SetPageAnchored( SdrObject& );
static void SetCellAnchored( SdrObject&, const ScDrawObjData &rAnchor );
- static void SetVisualCellAnchored( SdrObject&, const ScDrawObjData &rAnchor );
+ static void SetNonRotatedAnchor( SdrObject&, const ScDrawObjData &rAnchor );
// Updates rAnchor based on position of rObj
static void GetCellAnchorFromPosition(
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 9edf642f6f46..ea13cf9b4071 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -34,6 +34,7 @@
#include "calcmacros.hxx"
#include <formula/errorcodes.hxx>
#include "document.hxx"
+#include "drwlayer.hxx"
#include <set>
#include <memory>
@@ -965,7 +966,8 @@ public:
bool IsSortCollatorGlobal() const;
void InitSortCollator( const ScSortParam& rPar );
void DestroySortCollator();
- void SetDrawPageSize( bool bResetStreamValid = true, bool bUpdateNoteCaptionPos = true );
+ void SetDrawPageSize( bool bResetStreamValid = true, bool bUpdateNoteCaptionPos = true,
+ const ScObjectHandling eObjectHandling = ScObjectHandling::RecalcPosMode);
void SetRangeName(std::unique_ptr<ScRangeName> pNew);
ScRangeName* GetRangeName() const;
diff --git a/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods b/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods
new file mode 100644
index 000000000000..f0d0583d5934
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf137081_RTL_page_anchored.ods
Binary files differ
diff --git a/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods b/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods
new file mode 100644
index 000000000000..ed315c8f6996
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf137082_LTR_arrow_image.ods
Binary files differ
diff --git a/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods b/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods
new file mode 100644
index 000000000000..7b39927b1317
--- /dev/null
+++ b/sc/qa/unit/data/ods/tdf137082_RTL_cell_anchored.ods
Binary files differ
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 5ae35cde8430..11b7875c83ee 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -41,6 +41,9 @@ public:
ScShapeTest();
void saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent,
const OUString& rFilter);
+ void testTdf137082_LTR_to_RTL();
+ void testTdf137082_RTL_cell_anchored();
+ void testTdf137081_RTL_page_anchored();
void testTdf139583_Rotate180deg();
void testTdf137033_FlipHori_Resize();
void testTdf137033_RotShear_ResizeHide();
@@ -61,6 +64,9 @@ public:
void testCustomShapeCellAnchoredRotatedShape();
CPPUNIT_TEST_SUITE(ScShapeTest);
+ CPPUNIT_TEST(testTdf137082_LTR_to_RTL);
+ CPPUNIT_TEST(testTdf137082_RTL_cell_anchored);
+ CPPUNIT_TEST(testTdf137081_RTL_page_anchored);
CPPUNIT_TEST(testTdf139583_Rotate180deg);
CPPUNIT_TEST(testTdf137033_FlipHori_Resize);
CPPUNIT_TEST(testTdf137033_RotShear_ResizeHide);
@@ -183,6 +189,154 @@ static SdrObject* lcl_getSdrObjectWithAssert(ScDocument& rDoc, sal_uInt16 nObjNu
return pObj;
}
+void ScShapeTest::testTdf137082_LTR_to_RTL()
+{
+ // Before the fix for tdf137081 and tdf137082, when flipping sheet from LTR to RTL, page anchored
+ // shapes were mirrored, but cell anchored shapes not. This was changed so, that shapes are always
+ // mirrored. Graphics are still not mirrored but shifted. This test makes sure a shape is mirrored
+ // and an image is not mirrored.
+
+ OUString aFileURL;
+ createFileURL(u"tdf137082_LTR_arrow_image.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+ CPPUNIT_ASSERT(xComponent.is());
+
+ // Get document
+ ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ // Get objects and their transformation angles
+ SdrObject* pObjCS = lcl_getSdrObjectWithAssert(rDoc, 0);
+ const tools::Long nRotateLTR = pObjCS->GetRotateAngle();
+ SdrObject* pObjImage = lcl_getSdrObjectWithAssert(rDoc, 1);
+ const tools::Long nShearLTR = pObjImage->GetShearAngle();
+
+ // Switch to RTL
+ ScTabViewShell* pViewShell = lcl_getScTabViewShellWithAssert(pDocSh);
+ pViewShell->GetViewData().GetDispatcher().Execute(FID_TAB_RTL);
+
+ // Check custom shape is mirrored, image not.
+ const tools::Long nShearRTLActual = pObjImage->GetShearAngle();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("image should not be mirrored", nShearLTR, nShearRTLActual);
+ const tools::Long nRotateRTLExpected = 36000.00 - nRotateLTR;
+ const tools::Long nRotateRTLActual = pObjCS->GetRotateAngle();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("custom shape should be mirrored", nRotateRTLExpected,
+ nRotateRTLActual);
+
+ pDocSh->DoClose();
+}
+
+void ScShapeTest::testTdf137082_RTL_cell_anchored()
+{
+ // Error was, that cell anchored custom shapes wrote wrong offsets to file and thus were wrong on
+ // reloading. The file contains one custome shape with "resize" and another one without.
+ OUString aFileURL;
+ createFileURL(u"tdf137082_RTL_cell_anchored.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+ CPPUNIT_ASSERT(xComponent.is());
+
+ // Get document
+ ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ // Expected values.
+ const Point aTopLeftA(-20500, 3500); // shape A without "resize"
+ const Point aTopLeftB(-9500, 3500); // shape B with "resize"
+ const Size aSize(2278, 5545); // both
+ const tools::Rectangle aSnapRectA(aTopLeftA, aSize);
+ const tools::Rectangle aSnapRectB(aTopLeftB, aSize);
+
+ // Test reading was correct
+ SdrObject* pObj = lcl_getSdrObjectWithAssert(rDoc, 0);
+ lcl_AssertRectEqualWithTolerance("load shape A: ", aSnapRectA, pObj->GetSnapRect(), 1);
+ pObj = lcl_getSdrObjectWithAssert(rDoc, 1);
+ lcl_AssertRectEqualWithTolerance("load shape B: ", aSnapRectB, pObj->GetSnapRect(), 1);
+
+ // Save and reload.
+ saveAndReload(xComponent, "calc8");
+ CPPUNIT_ASSERT(xComponent);
+
+ // Get document
+ pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc2 = pDocSh->GetDocument();
+
+ // And test again
+ pObj = lcl_getSdrObjectWithAssert(rDoc2, 0);
+ lcl_AssertRectEqualWithTolerance("reload shape A: ", aSnapRectA, pObj->GetSnapRect(), 1);
+ pObj = lcl_getSdrObjectWithAssert(rDoc2, 1);
+ lcl_AssertRectEqualWithTolerance("reload shape B: ", aSnapRectB, pObj->GetSnapRect(), 1);
+
+ pDocSh->DoClose();
+}
+
+void ScShapeTest::testTdf137081_RTL_page_anchored()
+{
+ // Error was, that page anchored lines and custom shapes were mirrored on opening. The document
+ // contains measure line, polyline and transformed custom shape.
+ OUString aFileURL;
+ createFileURL(u"tdf137081_RTL_page_anchored.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+ CPPUNIT_ASSERT(xComponent.is());
+
+ // Get document
+ ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ // Expected values.
+ // Measure line
+ const Point aStart(-3998, 2490);
+ const Point aEnd(-8488, 5490);
+ // Polyline
+ const Point aFirst(-10010, 2500);
+ const Point aSecond(-14032, 5543);
+ const Point aThird(-14500, 3500);
+ // Custom shape
+ const Point aTopLeft(-20500, 4583);
+
+ // Test reading was correct
+ SdrObject* pObj = lcl_getSdrObjectWithAssert(rDoc, 0);
+ // Measure line
+ lcl_AssertPointEqualWithTolerance("measure line start", aStart, pObj->GetPoint(0), 1);
+ lcl_AssertPointEqualWithTolerance("measure line end", aEnd, pObj->GetPoint(1), 1);
+ // Polyline
+ pObj = lcl_getSdrObjectWithAssert(rDoc, 1);
+ lcl_AssertPointEqualWithTolerance("polyline 1: ", aFirst, pObj->GetPoint(0), 1);
+ lcl_AssertPointEqualWithTolerance("polyline 2: ", aSecond, pObj->GetPoint(1), 1);
+ lcl_AssertPointEqualWithTolerance("polyline 3: ", aThird, pObj->GetPoint(2), 1);
+ //Custom shape
+ SdrObjCustomShape* pObjCS
+ = static_cast<SdrObjCustomShape*>(lcl_getSdrObjectWithAssert(rDoc, 2));
+ CPPUNIT_ASSERT(!pObjCS->IsMirroredX());
+ lcl_AssertPointEqualWithTolerance("custom shape top left: ", aTopLeft,
+ pObjCS->GetLogicRect().TopLeft(), 1);
+
+ // Save and reload.
+ saveAndReload(xComponent, "calc8");
+ CPPUNIT_ASSERT(xComponent);
+
+ // Get document
+ pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc2 = pDocSh->GetDocument();
+
+ // And test again
+ pObj = lcl_getSdrObjectWithAssert(rDoc2, 0);
+ // Measure line
+ lcl_AssertPointEqualWithTolerance("measure line start", aStart, pObj->GetPoint(0), 1);
+ lcl_AssertPointEqualWithTolerance("measure line end", aEnd, pObj->GetPoint(1), 1);
+ // Polyline
+ pObj = lcl_getSdrObjectWithAssert(rDoc2, 1);
+ lcl_AssertPointEqualWithTolerance("polyline 1: ", aFirst, pObj->GetPoint(0), 1);
+ lcl_AssertPointEqualWithTolerance("polyline 2: ", aSecond, pObj->GetPoint(1), 1);
+ lcl_AssertPointEqualWithTolerance("polyline 3: ", aThird, pObj->GetPoint(2), 1);
+ //Custom shape
+ pObjCS = static_cast<SdrObjCustomShape*>(lcl_getSdrObjectWithAssert(rDoc2, 2));
+ CPPUNIT_ASSERT(!pObjCS->IsMirroredX());
+ lcl_AssertPointEqualWithTolerance("custom shape top left: ", aTopLeft,
+ pObjCS->GetLogicRect().TopLeft(), 1);
+
+ pDocSh->DoClose();
+}
+
void ScShapeTest::testTdf139583_Rotate180deg()
{
// Load an empty document.
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index 46d1b1c3750d..f44159d6c436 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -600,8 +600,10 @@ void ScDocument::SetImportingXML( bool bVal )
for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]; nTab++ )
if ( maTabs[nTab]->IsLoadingRTL() )
{
+ // SetLayoutRTL => SetDrawPageSize => ScDrawLayer::SetPageSize, includes RTL-mirroring;
+ // bImportingXML must be cleared first
maTabs[nTab]->SetLoadingRTL( false );
- SetLayoutRTL( nTab, true ); // includes mirroring; bImportingXML must be cleared first
+ SetLayoutRTL( nTab, true, ScObjectHandling::MoveRTLMode );
}
}
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 3adddf93a127..820676d56cc6 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -947,7 +947,7 @@ void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
maTabs[nTab]->SetPendingRowHeights( bSet );
}
-void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
+void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL, ScObjectHandling eObjectHandling)
{
if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab]) )
return;
@@ -963,10 +963,9 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
}
maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
- maTabs[nTab]->SetDrawPageSize();
-
- // mirror existing objects:
+ maTabs[nTab]->SetDrawPageSize(true, true, eObjectHandling);
+ // objects are already repositioned via SetDrawPageSize, only writing mode is missing
if (!mpDrawLayer)
return;
@@ -979,14 +978,7 @@ void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
SdrObject* pObject = aIter.Next();
while (pObject)
{
- // objects with ScDrawObjData are re-positioned in SetPageSize,
- // don't mirror again
- ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
- if ( !pData )
- mpDrawLayer->MirrorRTL( pObject );
-
pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
-
pObject = aIter.Next();
}
}
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index fffe3e75d085..b89db024a4a3 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -572,7 +572,8 @@ void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SC
}
}
-void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos )
+void ScDrawLayer::SetPageSize(sal_uInt16 nPageNo, const Size& rSize, bool bUpdateNoteCaptionPos,
+ const ScObjectHandling eObjectHandling)
{
SdrPage* pPage = GetPage(nPageNo);
if (!pPage)
@@ -584,31 +585,65 @@ void ScDrawLayer::SetPageSize( sal_uInt16 nPageNo, const Size& rSize, bool bUpda
Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() on the views
}
- // Implement Detective lines (adjust to new heights / widths)
- // even if size is still the same
- // (individual rows/columns can have been changed))
-
// Do not call RecalcPos while loading, because row height is not finished, when SetPageSize
// is called first time. Instead the objects are initialized from ScXMLImport::endDocument() and
// RecalcPos is called from there.
if (!pDoc || pDoc->IsImportingXML())
return;
+ // Implement Detective lines (adjust to new heights / widths)
+ // even if size is still the same
+ // (individual rows/columns can have been changed))
+
bool bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
// Disable mass broadcasts from drawing objects' position changes.
bool bWasLocked = isLocked();
setLock(true);
+
const size_t nCount = pPage->GetObjCount();
for ( size_t i = 0; i < nCount; ++i )
{
SdrObject* pObj = pPage->GetObj( i );
ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
- if( pData )
- RecalcPos( pObj, *pData, bNegativePage, bUpdateNoteCaptionPos );
+ if( pData ) // cell anchored
+ {
+ if (pData->meType == ScDrawObjData::DrawingObject
+ || pData->meType == ScDrawObjData::ValidationCircle)
+ {
+ switch (eObjectHandling)
+ {
+ case ScObjectHandling::RecalcPosMode:
+ RecalcPos(pObj, *pData, bNegativePage, bUpdateNoteCaptionPos);
+ break;
+ case ScObjectHandling::MoveRTLMode:
+ MoveRTL(pObj);
+ break;
+ case ScObjectHandling::MirrorRTLMode:
+ MirrorRTL(pObj);
+ break;
+ }
+ }
+ else // DetectiveArrow and CellNote
+ RecalcPos(pObj, *pData, bNegativePage, bUpdateNoteCaptionPos);
+ }
+ else // page anchored
+ {
+ switch (eObjectHandling)
+ {
+ case ScObjectHandling::MoveRTLMode:
+ MoveRTL(pObj);
+ break;
+ case ScObjectHandling::MirrorRTLMode:
+ MirrorRTL(pObj);
+ break;
+ case ScObjectHandling::RecalcPosMode: // does not occur for page anchored shapes
+ break;
+ }
+ }
}
- setLock(bWasLocked);
+ setLock(bWasLocked);
}
namespace
@@ -1179,9 +1214,9 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
else
pObj->SetSnapRect(rData.getShapeRect());
- // update 'unrotated anchor' it's the anchor we persist, it must be kept in sync
- // with the normal Anchor.
- ResizeLastRectFromAnchor(pObj, rNoRotatedAnchor, true, bNegativePage, bCanResize);
+ // The shape rectangle in the 'unrotated' anchor needs to be updated to the changed
+ // object geometry. It is used in adjustAnchoredPosition() in ScDrawView::Notify().
+ rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), pObj->IsVisible());
}
}
else
@@ -1192,6 +1227,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
pObj->SetRelativePos( aPos );
+ rNoRotatedAnchor.setShapeRect(pDoc, pObj->GetLogicRect(), pObj->IsVisible());
}
}
/*
@@ -1956,6 +1992,10 @@ void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const
void ScDrawLayer::MirrorRTL( SdrObject* pObj )
{
+ OSL_ENSURE( pDoc, "ScDrawLayer::MirrorRTL - missing document" );
+ if( !pDoc )
+ return;
+
sal_uInt16 nIdent = pObj->GetObjIdentifier();
// don't mirror OLE or graphics, otherwise ask the object
@@ -1970,23 +2010,87 @@ void ScDrawLayer::MirrorRTL( SdrObject* pObj )
if (bCanMirror)
{
- Point aRef1( 0, 0 );
- Point aRef2( 0, 1 );
- if (bRecording)
- AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
- pObj->Mirror( aRef1, aRef2 );
+ ScDrawObjData* pData = GetObjData(pObj);
+ if (pData) // cell anchored
+ {
+ // Remember values from positive side.
+ const tools::Rectangle aOldSnapRect = pObj->GetSnapRect();
+ const tools::Rectangle aOldLogicRect = pObj->GetLogicRect();
+ // Generate noRotate anchor if missing.
+ ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj);
+ if (!pNoRotatedAnchor)
+ {
+ ScDrawObjData aNoRotateAnchor;
+ const tools::Rectangle aLogicRect(pObj->GetLogicRect());
+ GetCellAnchorFromPosition(aLogicRect, aNoRotateAnchor,
+ *pDoc, pData->maStart.Tab());
+ aNoRotateAnchor.mbResizeWithCell = pData->mbResizeWithCell;
+ SetNonRotatedAnchor(*pObj, aNoRotateAnchor);
+ }
+ // Mirror object at vertical axis
+ Point aRef1( 0, 0 );
+ Point aRef2( 0, 1 );
+ if (bRecording)
+ AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+ pObj->Mirror( aRef1, aRef2 );
+
+ // Adapt offsets in pNoRotatedAnchor so, that object will be moved to current position in
+ // save and reload.
+ const tools::Long nInverseShift = aOldSnapRect.Left() + aOldSnapRect.Right();
+ const Point aLogicLT = pObj->GetLogicRect().TopLeft();
+ const Point aMirroredLogicLT = aLogicLT + Point(nInverseShift, 0);
+ const Point aOffsetDiff = aMirroredLogicLT - aOldLogicRect.TopLeft();
+ // new Offsets
+ pNoRotatedAnchor->maStartOffset += aOffsetDiff;
+ pNoRotatedAnchor->maEndOffset += aOffsetDiff;
+ }
+ else // page anchored
+ {
+ Point aRef1( 0, 0 );
+ Point aRef2( 0, 1 );
+ if (bRecording)
+ AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+ pObj->Mirror( aRef1, aRef2 );
+ }
}
else
{
// Move instead of mirroring:
// New start position is negative of old end position
// -> move by sum of start and end position
- tools::Rectangle aObjRect = pObj->GetLogicRect();
+ tools::Rectangle aObjRect = pObj->GetSnapRect();
Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoMoveObj>( *pObj, aMoveSize ) );
pObj->Move( aMoveSize );
}
+
+ // for cell anchored objects adapt rectangles in anchors
+ ScDrawObjData* pData = GetObjData(pObj);
+ if (pData)
+ {
+ pData->setShapeRect(GetDocument(), pObj->GetSnapRect(), pObj->IsVisible());
+ ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj, true /*bCreate*/);
+ pNoRotatedAnchor->setShapeRect(GetDocument(), pObj->GetLogicRect(), pObj->IsVisible());
+ }
+}
+
+void ScDrawLayer::MoveRTL(SdrObject* pObj)
+{
+ tools::Rectangle aObjRect = pObj->GetSnapRect();
+ Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
+ if (bRecording)
+ AddCalcUndo( std::make_unique<SdrUndoMoveObj>( *pObj, aMoveSize ) );
+ pObj->Move( aMoveSize );
+
+ // for cell anchored objects adapt rectangles in anchors
+ ScDrawObjData* pData = GetObjData(pObj);
+ if (pData)
+ {
+ pData->setShapeRect(GetDocument(), pObj->GetSnapRect(), pObj->IsVisible());
+ ScDrawObjData* pNoRotatedAnchor = GetNonRotatedObjData(pObj, true /*bCreate*/);
+ pNoRotatedAnchor->setShapeRect(GetDocument(), pObj->GetLogicRect(), pObj->IsVisible());
+ }
}
void ScDrawLayer::MirrorRectRTL( tools::Rectangle& rRect )
@@ -2169,7 +2273,7 @@ namespace
}
}
-void ScDrawLayer::SetVisualCellAnchored( SdrObject &rObj, const ScDrawObjData &rAnchor )
+void ScDrawLayer::SetNonRotatedAnchor(SdrObject& rObj, const ScDrawObjData& rAnchor)
{
ScDrawObjData* pAnchor = GetNonRotatedObjData( &rObj, true );
pAnchor->maStart = rAnchor.maStart;
@@ -2237,19 +2341,29 @@ void ScDrawLayer::SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument
else
aObjRect2 = rObj.GetLogicRect();
- ScDrawObjData aVisAnchor;
+ // Values in XML are so as if it is a LTR sheet. The object is shifted to negative page on loading
+ // so that the snap rectangle appears mirrored. For transformed objects the shifted logic rectangle
+ // is not the mirrored LTR rectangle. We calculate the mirrored LTR rectangle here.
+ if (rDoc.IsNegativePage(nTab))
+ {
+ const tools::Rectangle aSnapRect(rObj.GetSnapRect());
+ aObjRect2.Move(Size(-aSnapRect.Left() - aSnapRect.Right(), 0));
+ MirrorRectRTL(aObjRect2);
+ }
+
+ ScDrawObjData aNoRotatedAnchor;
GetCellAnchorFromPosition(
aObjRect2,
- aVisAnchor,
+ aNoRotatedAnchor,
rDoc,
- nTab, false);
+ nTab);
- aVisAnchor.mbResizeWithCell = bResizeWithCell;
- SetVisualCellAnchored( rObj, aVisAnchor );
+ aNoRotatedAnchor.mbResizeWithCell = bResizeWithCell;
+ SetNonRotatedAnchor( rObj, aNoRotatedAnchor);
// And update maShapeRect. It is used in adjustAnchoredPosition() in ScDrawView::Notify().
if (ScDrawObjData* pAnchor = GetNonRotatedObjData(&rObj))
{
- pAnchor->setShapeRect(&rDoc, rObj.GetSnapRect());
+ pAnchor->setShapeRect(&rDoc, rObj.GetLogicRect());
}
}
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index d8fb7fac5b0f..02a9ad19cbaf 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -3903,7 +3903,8 @@ void ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow, OUString& rStr)
// Calculate the size of the sheet and set the size on DrawPage
-void ScTable::SetDrawPageSize(bool bResetStreamValid, bool bUpdateNoteCaptionPos)
+void ScTable::SetDrawPageSize(bool bResetStreamValid, bool bUpdateNoteCaptionPos,
+ ScObjectHandling eObjectHandling)
{
ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
if( pDrawLayer )
@@ -3919,7 +3920,8 @@ void ScTable::SetDrawPageSize(bool bResetStreamValid, bool bUpdateNoteCaptionPos
if ( IsLayoutRTL() ) // IsNegativePage
x = -x;
- pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( x, y ), bUpdateNoteCaptionPos );
+ pDrawLayer->SetPageSize(static_cast<sal_uInt16>(nTab), Size(x, y), bUpdateNoteCaptionPos,
+ eObjectHandling);
}
// #i102616# actions that modify the draw page size count as sheet modification
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 501d0a3f03db..4fbdb0c1356a 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -3477,7 +3477,10 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
if( !(rMyCell.bHasShape && !rMyCell.aShapeList.empty() && pDoc) )
return;
- // Reference point
+ // Reference point to turn absolute coordinates in reference point + offset. That happens in most
+ // cases in XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint, which gets the absolute
+ // coordinates as translation from matrix in property "Transformation". For cell anchored shapes
+ // the reference point is left-top (in LTR mode) of that cell, which contains the shape.
tools::Rectangle aCellRectFull = pDoc->GetMMRect(
rMyCell.maCellAddress.Col(), rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Col(),
rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Tab(), false /*bHiddenAsZero*/);
@@ -3489,7 +3492,6 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
aPoint.X = aCellRectFull.Left();
aPoint.Y = aCellRectFull.Top();
- // ToDo: Adapt the solutions for RTL sheets.
for (const auto& rShape : rMyCell.aShapeList)
{
if (rShape.xShape.is())
@@ -3549,9 +3551,17 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
const tools::Rectangle aEndCellRect = pDoc->GetMMRect(
aSnapEndAddress.Col(), aSnapEndAddress.Row(), aSnapEndAddress.Col(),
aSnapEndAddress.Row(), aSnapEndAddress.Tab(), false /*bHiddenAsZero*/);
- aRectFull.SetLeft(aStartCellRect.Left() + aSnapStartOffset.X());
+ if (bNegativePage)
+ {
+ aRectFull.SetLeft(aEndCellRect.Right() - aSnapEndOffset.X());
+ aRectFull.SetRight(aStartCellRect.Right() - aSnapStartOffset.X());
+ }
+ else
+ {
+ aRectFull.SetLeft(aStartCellRect.Left() + aSnapStartOffset.X());
+ aRectFull.SetRight(aEndCellRect.Left() + aSnapEndOffset.X());
+ }
aRectFull.SetTop(aStartCellRect.Top() + aSnapStartOffset.Y());
- aRectFull.SetRight(aEndCellRect.Left() + aSnapEndOffset.X());
aRectFull.SetBottom(aEndCellRect.Top() + aSnapEndOffset.Y());
aRectReduced = pObjData->getShapeRect();
if(abs(aRectFull.getWidth() - aRectReduced.getWidth()) > 1
@@ -3584,25 +3594,31 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
AddAttribute(XML_NAMESPACE_TABLE, XML_END_Y, sBuffer.makeStringAndClear());
}
- // The general method XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint calculates
- // offset = translate - refPoint. But in case of a horizontal mirrored, 'resize with cell'
- // anchored custom shape, translate has wrong values. So we use refPoint = translate
- // - startOffset which removes translate and sets startOffset directly.
- // FixMe: Why is translate wrong?
- if (rShape.bResizeWithCell && pObj && pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE
- && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX())
+ // Correct above calculated reference point for some cases:
+ // a) For a RTL-sheet translate from matrix is not suitable, because the shape
+ // from xml (which is always LTR) is not mirrored to negative page but shifted.
+ // b) In case of horizontal mirrored, 'resize with cell' anchored custom shape, translate
+ // has wrong values. FixMe: Why is translate wrong?
+ // c) Measure lines do not use transformation matrix but use start and end point directly.
+ ScDrawObjData* pNRObjData = nullptr;
+ if (pObj && bNegativePage
+ && rShape.xShape->getShapeType() == "com.sun.star.drawing.MeasureShape")
{
- ScDrawObjData* pNRObjData = ScDrawLayer::GetNonRotatedObjData(pObj);
- if (pNRObjData)
- {
- aPoint.X = rShape.xShape->getPosition().X - pNRObjData->maStartOffset.X();
- aPoint.Y = rShape.xShape->getPosition().Y - pNRObjData->maStartOffset.Y();
- }
+ // invers of shift when import
+ tools::Rectangle aSnapRect = pObj->GetSnapRect();
+ aPoint.X = aSnapRect.Left() + aSnapRect.Right() - aPoint.X;
+ }
+ else if (pObj && (pNRObjData = ScDrawLayer::GetNonRotatedObjData(pObj))
+ && ((rShape.bResizeWithCell && pObj->GetObjIdentifier() == OBJ_CUSTOMSHAPE
+ && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX())
+ || bNegativePage))
+ {
+ //In these cases we set reference Point = matrix translate - startOffset.
+ awt::Point aMatrixTranslate = rShape.xShape->getPosition();
+ aPoint.X = aMatrixTranslate.X - pNRObjData->maStartOffset.X();
+ aPoint.Y = aMatrixTranslate.Y - pNRObjData->maStartOffset.Y();
}
- if (bNegativePage)
- aPoint.X = 2 * rShape.xShape->getPosition().X + rShape.xShape->getSize().Width
- - aPoint.X;
ExportShape(rShape.xShape, &aPoint);
// Restore object geometry
@@ -3626,11 +3642,23 @@ void ScXMLExport::WriteTableShapes()
{
if (pDoc->IsNegativePage(static_cast<SCTAB>(nCurrentTable)))
{
- awt::Point aPoint(rxShape->getPosition());
- awt::Size aSize(rxShape->getSize());
- aPoint.X += aPoint.X + aSize.Width;
- aPoint.Y = 0;
- ExportShape(rxShape, &aPoint);
+ // RTL-mirroring refers to snap rectangle, not to logic rectangle, therefore cannot use
+ // getPosition() and getSize(), but need property "FrameRect" from rxShape or
+ // GetSnapRect() from associated SdrObject.
+ uno::Reference<beans::XPropertySet> xShapeProp(rxShape, uno::UNO_QUERY);
+ awt::Rectangle aFrameRect;
+ if (xShapeProp.is() && (xShapeProp->getPropertyValue("FrameRect") >>= aFrameRect))
+ {
+ // file format uses shape in LTR mode. newLeft = - oldRight = - (oldLeft + width).
+ // newTranslate = oldTranslate - refPoint, oldTranslate from transformation matrix,
+ // calculated in XMLShapeExport::exportShape common for all modules.
+ // oldTranslate.X = oldLeft ==> refPoint.X = 2 * oldLeft + width
+ awt::Point aRefPoint;
+ aRefPoint.X = 2 * aFrameRect.X + aFrameRect.Width - 1;
+ aRefPoint.Y = 0;
+ ExportShape(rxShape, &aRefPoint);
+ }
+ // else should not happen
}
else
ExportShape(rxShape, nullptr);
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index e05513039d9e..a1bc0551f3cd 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -3463,7 +3463,7 @@ bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL )
ScDocShellModificator aModificator( rDocShell );
- rDoc.SetLayoutRTL( nTab, bRTL );
+ rDoc.SetLayoutRTL( nTab, bRTL, ScObjectHandling::MirrorRTLMode);
if (bUndo)
{
diff --git a/sc/source/ui/undo/undotab.cxx b/sc/source/ui/undo/undotab.cxx
index 4118b1bcbd5d..85c2708367e4 100644
--- a/sc/source/ui/undo/undotab.cxx
+++ b/sc/source/ui/undo/undotab.cxx
@@ -1509,7 +1509,7 @@ void ScUndoLayoutRTL::DoChange( bool bNew )
pDocShell->SetInUndo( true );
ScDocument& rDoc = pDocShell->GetDocument();
- rDoc.SetLayoutRTL( nTab, bNew );
+ rDoc.SetLayoutRTL(nTab, bNew, ScObjectHandling::MirrorRTLMode);
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
if (pViewShell)