summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.cxx155
-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, 375 insertions, 69 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index a8bfba521437..79091e89504c 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 030fd3855ec8..008e56f8b8c6 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 a09781366821..309d49d4f140 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 1c54c0e5ac5c..6d8fa9f1f09a 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -40,6 +40,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();
@@ -60,6 +63,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);
@@ -186,6 +192,155 @@ 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 Degree100 nRotateLTR = pObjCS->GetRotateAngle();
+ SdrObject* pObjImage = lcl_getSdrObjectWithAssert(rDoc, 1);
+ const Degree100 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 Degree100 nShearRTLActual = pObjImage->GetShearAngle();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("image should not be mirrored", nShearLTR.get(),
+ nShearRTLActual.get());
+ const Degree100 nRotateRTLExpected = 36000_deg100 - nRotateLTR;
+ const Degree100 nRotateRTLActual = pObjCS->GetRotateAngle();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("custom shape should be mirrored", nRotateRTLExpected.get(),
+ nRotateRTLActual.get());
+
+ 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 be588062c5df..48282126b0fc 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -945,7 +945,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;
@@ -961,10 +961,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;
@@ -977,14 +976,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 067b2bc38b0f..3d2eb834a6c0 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -570,7 +570,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)
@@ -582,31 +583,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
@@ -1177,9 +1212,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
@@ -1190,6 +1225,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());
}
}
/*
@@ -1954,6 +1990,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
@@ -1968,23 +2008,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 )
@@ -2167,7 +2271,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;
@@ -2235,19 +2339,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 0ba9421d8265..d25e7ce7c7f4 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -3910,7 +3910,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 )
@@ -3926,7 +3927,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 d69fdd784ef7..a7a61365a08c 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -3476,7 +3476,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*/);
@@ -3488,7 +3491,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())
@@ -3548,9 +3550,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
@@ -3583,25 +3593,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
@@ -3625,11 +3641,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 42ac96e8eea3..2949e92390f1 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -3465,7 +3465,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)